2014-10-17 81 views
7

我在實現(可能)相當簡單的任務時遇到問題。 我有完全可修改的模型(Prodotto,Comune),它們顯示爲「可添加」字段,如下圖所示。 我不希望看到的是這些字段的+(添加)按鈕,因此要刪除這種形式的「可添加」屬性。 我試過在兩個模型中設置has_add_permission = False,但是這樣會使得不可能完全向這樣的模型添加新的對象,而不僅僅是以這種形式。Django 1.7正在刪除從內嵌表單添加按鈕

我怎麼能這樣做?

編輯:爲了澄清我的需要,我希望不要有「+」的隔壁FK模型的領域,但我仍然希望能夠增加全新的內聯。爲了儘可能清楚,正如我在評論中寫的那樣,考慮如下情景:https://code.djangoproject.com/attachment/ticket/20367/django_custom_user_admin_form.png我只需要將組和國家旁邊的「+」刪除。

現有代碼:

models.py(所涉及的具體應用的):

from django.db import models 

from smart_selects.db_fields import ChainedForeignKey 

from apps.comune.models import Comune, Cap 


class Prodotto(models.Model): 
    SETTORE_CHOICES = (
     ('CAL', 'Accessori calzature'), 
     ('ALI', 'Alimentari'), 
     ('ARA', 'Arredamenti e accessori'), 
     ('AEM', 'Auto e moto'), 
     ('CAL', 'Calzature'), 
     ('CEG', 'Cartaria e grafica'), 
     ('CEP', 'Concerie e pelletterie'), 
     ('EDI', 'Edilizia'), 
     ('INV', 'Industrie varie'), 
     ('IST', 'Istruzione'), 
     ('MDC', 'Materiali da costruzione'), 
     ('MMC', 'Metalmeccanica'), 
     ('SEI', 'Serramenti e infissi'), 
     ('STM', 'Strumenti musicali'), 
     ('TEI', 'Terziario innovativo'), 
     ('TAB', 'Tessile abbigliamento'), 
     ('TCP', 'Trasporto cose e persone'), 
     ('VAR', 'Vari'), 
    ) 
    nome = models.CharField(max_length=100) 
    settore = models.CharField(max_length=40, choices=SETTORE_CHOICES) 

    class Meta: 
     verbose_name_plural = "prodotti" 
     verbose_name = "prodotto" 
     ordering = ['nome'] 

    def __unicode__(self): 
     return self.nome.capitalize() 


class Cliente(models.Model): 
    TIPOLOGIA_CHOICES = (
     ('AR', 'Artigiano'), 
     ('CO', 'Commerciante'), 
     ('GI', 'Grande impresa'), 
     ('PI', 'Piccola impresa'), 
    ) 
    FORMA_SOCIETARIA_CHOICES = (
     ('SNC', 'S.n.c.'), 
     ('SRL', 'S.r.l.'), 
     ('SPA', 'S.p.A.'), 
     ('SAS', 'S.a.s.'), 
     ('COOP', 'Coop.A.r.l.'), 
     ('DI', 'D.I.'), 
     ('SCARL', 'S.c.a.r.l.'), 
     ('SCPA', 'S.c.p.a.'), 
    ) 
    SETTORE_CHOICES = (
     ('CAL', 'Accessori calzature'), 
     ('ALI', 'Alimentari'), 
     ('ARA', 'Arredamenti e accessori'), 
     ('AEM', 'Auto e moto'), 
     ('CAL', 'Calzature'), 
     ('CEG', 'Cartaria e grafica'), 
     ('CEP', 'Concerie e pelletterie'), 
     ('EDI', 'Edilizia'), 
     ('INV', 'Industrie varie'), 
     ('IST', 'Istruzione'), 
     ('MDC', 'Materiali da costruzione'), 
     ('MMC', 'Metalmeccanica'), 
     ('SEI', 'Serramenti e infissi'), 
     ('STM', 'Strumenti musicali'), 
     ('TEI', 'Terziario innovativo'), 
     ('TAB', 'Tessile abbigliamento'), 
     ('TCP', 'Trasporto cose e persone'), 
     ('VAR', 'Vari'), 
    ) 
    ragione_sociale = models.CharField(max_length=200) 
    forma_societaria = models.CharField(
     max_length=5, choices=FORMA_SOCIETARIA_CHOICES) 
    titolare = models.CharField(max_length=100, blank=True) 
    partita_iva = models.CharField(
     max_length=11, verbose_name='Partita IVA', unique=True) 
    tipologia = models.CharField(max_length=2, choices=TIPOLOGIA_CHOICES) 
    settore = models.CharField(max_length=40, choices=SETTORE_CHOICES) 
    prodotto = models.ManyToManyField(Prodotto, blank=True) 

    class Meta: 
     verbose_name_plural = "clienti" 
     verbose_name = "cliente" 

    def __unicode__(self): 
     return self.ragione_sociale.capitalize() 


class Sede(models.Model): 
    nome = models.CharField(max_length=100) 
    indirizzo = models.CharField(max_length=200, blank=True) 
    cliente = models.ForeignKey(Cliente) 
    comune = models.ForeignKey(Comune) 
    cap = ChainedForeignKey(
     Cap, 
     chained_field="comune", 
     chained_model_field="comune", 
     show_all=False, 
     auto_choose=True, 
    ) 

    class Meta: 
     verbose_name_plural = "sedi" 
     verbose_name = "sede" 
     ordering = ['nome'] 

    def __unicode__(self): 
     return self.nome.capitalize() + ", " + self.indirizzo 

admin.py(所涉及的具體應用的):

from django.contrib import admin 

from .models import Cliente, Prodotto, Sede 
from apps.recapito.models import RecapitoCliente 


class SedeInline(admin.TabularInline): 
    model = Sede 
    extra = 1 

    def provincia(self, obj): 
     return obj.comune.provincia 

    readonly_fields = ['provincia', ] 


class RecapitoInline(admin.TabularInline): 
    model = RecapitoCliente 
    extra = 1 
    list_fields = ['cliente', 'tipo', 'recapito', ] 


@admin.register(Cliente) 
class ClienteAdmin(admin.ModelAdmin): 
    list_display = [ 
     'ragione_sociale', 'forma_societaria', 'titolare', 'partita_iva', ] 
    list_filter = ['forma_societaria', ] 
    search_fields = ['ragione_sociale', ] 
    inlines = [RecapitoInline, SedeInline] 


admin.site.register(Prodotto) 

此應用程序的管理界面produc ES這樣的:

Admin interface

快捷方式鏈接1和2是我需要刪除的那些,被稱作列(FKS)我在線課程。 快捷鏈接3和4將被保留,因爲它們自己提及內聯

回答

9

我認爲這是一個比你最終的解決方案更簡單的解決方案。無論如何,它對我都有效。

基本上,它是您建議使用ModelAdmin的方法覆蓋get_form的內聯等效項。在這裏,我們覆蓋內聯類中的get_formset,從formset獲取表單,並執行完全相同的操作。似乎工作正常,至少在1.9,我正在使用。

class VersionEntryInline(admin.TabularInline): 
    template = 'admin/edit_inline/tabular_versionentry.html' 
    model = VersionEntry 
    extra = 0 

    def get_formset(self, request, obj=None, **kwargs): 
     """ 
     Override the formset function in order to remove the add and change buttons beside the foreign key pull-down 
     menus in the inline. 
     """ 
     formset = super(VersionEntryInline, self).get_formset(request, obj, **kwargs) 
     form = formset.form 
     widget = form.base_fields['project'].widget 
     widget.can_add_related = False 
     widget.can_change_related = False 
     widget = form.base_fields['version'].widget 
     widget.can_add_related = False 
     widget.can_change_related = False 
     return formset 
+0

這對我工作在1.8.3。比公認的答案imho好得多。 – jenniwren 2016-08-30 22:14:33

+0

也適用於1.9.8。我想一個最小的例子(基於上面)將是:'formset.form.base_fields ['my_field']。widget.can_add_related = False(在調用super和return之間) – Dennis 2017-06-02 13:41:04

4

經過幾天激烈的日子,我終於設法找到了實現這個目標的途徑。

@admin.register(Cliente) 
class ClienteAdmin(admin.ModelAdmin): 
    list_display = [ 
     'ragione_sociale', 'forma_societaria', 'titolare', 'partita_iva', ] 
    list_filter = ['forma_societaria', ] 
    search_fields = ['ragione_sociale', ] 
    inlines = [RecapitoInline, SedeInline] 
    def get_form(self, request, obj=None, **kwargs): # Just added this override 
     form = super(ClienteAdmin, self).get_form(request, obj, **kwargs) 
     form.base_fields['prodotto'].widget.can_add_related = False 
     return form 
:用的ModelAdmin子類(見ClienteAdmin在我上面的代碼),所以這裏的類版本無添加的功能爲「Prodotto」領域內處理這個問題時

一個簡單的技巧,如this是綽綽有餘

當處理內聯類(TabularInline,StackedInline)時,真正的痛苦來了,因爲get_form()函數似乎根本不會被調用,所以前面的方法將不起作用。

解釋我以前的所有嘗試都需要很長時間,而且我可能還沒有用Django做得足夠好,但還不知道爲什麼他們不工作。所以讓我們直接找到解決方案,其實這並不複雜。

我子類django.contrib.admin.widgets.RelatedFieldWidgetWrapper部件和覆蓋它的渲染方法,所以它不追加「附加另一個」錨輸出。通過評論幾行很容易完成。完成後,用我自己的版本(django.contrib.admin.widgets)修改原始的RelatedFieldWidgetWrapper。RelatedFieldWidgetWrapper = NoAddingRelatedFieldWidgetWrapper)取得了訣竅。

顯然,爲它工作,我不得不添加導入線在admin.py

從.widgets導入NoAddingRelatedFieldWidgetWrapper

widgets.py

import django.contrib.admin.widgets 
from django.utils.safestring import mark_safe 


class NoAddingRelatedFieldWidgetWrapper(django.contrib.admin.widgets.RelatedFieldWidgetWrapper): 

    def render(self, name, value, *args, **kwargs): 
     from django.contrib.admin.views.main import TO_FIELD_VAR 
     rel_to = self.rel.to 
     info = (rel_to._meta.app_label, rel_to._meta.model_name) 
     self.widget.choices = self.choices 
     output = [self.widget.render(name, value, *args, **kwargs)] 
     ''' 
     if self.can_add_related: 
      related_url = reverse('admin:%s_%s_add' % info, current_app=self.admin_site.name) 
      url_params = '?%s=%s' % (TO_FIELD_VAR, self.rel.get_related_field().name) 
      # TODO: "add_id_" is hard-coded here. This should instead use the 
      # correct API to determine the ID dynamically. 
      output.append('<a href="%s%s" class="add-another" id="add_id_%s" onclick="return showAddAnotherPopup(this);"> ' 
          % (related_url, url_params, name)) 
      output.append('<img src="%s" width="10" height="10" alt="%s"/></a>' 
          % (static('admin/img/icon_addlink.gif'), _('Add Another'))) 
     ''' 
     return mark_safe(''.join(output)) 

# Monkeypatch 
django.contrib.admin.widgets.RelatedFieldWidgetWrapper = NoAddingRelatedFieldWidgetWrapper 

爲了完成,下面是相關admin.py的最終版本:

admin.py

from django.contrib import admin 
import django.contrib.admin.widgets 

from django.db import models 

from .models import Cliente, Prodotto, Sede 
from apps.recapito.models import RecapitoCliente 
from .widgets import NoAddingRelatedFieldWidgetWrapper 


class SedeInline(admin.TabularInline): 
    model = Sede 
    extra = 1 

    def provincia(self, obj): 
     return obj.comune.provincia 

    readonly_fields = ['provincia', ] 


class RecapitoInline(admin.TabularInline): 
    model = RecapitoCliente 
    extra = 1 
    readonly_fields = ['cliente', 'tipo', 'recapito', ] 


@admin.register(Cliente) 
class ClienteAdmin(admin.ModelAdmin): 
    list_display = [ 
     'ragione_sociale', 'forma_societaria', 'titolare', 'partita_iva', ] 
    list_filter = ['forma_societaria', ] 
    search_fields = ['ragione_sociale', ] 
    inlines = [RecapitoInline, SedeInline] 
    def get_form(self, request, obj=None, **kwargs): 
     form = super(ClienteAdmin, self).get_form(request, obj, **kwargs) 
     form.base_fields['prodotto'].widget.can_add_related = False 
     return form 

難道有人拿出任何更好的解決方案,我會很樂意接受它來代替我的。

+0

我不禁覺得用javascript或css隱藏它會更好 - 無論是爲了簡單性和可維護性。 – 2015-05-17 14:28:20

+0

我想我的答案在下面是您尋找的更簡單的解決方案。你願意接受嗎? – thegiffman 2016-06-28 03:44:37

+0

@thegiffman只要你確信這可以在Dj中使用Django 1.7,我沒有問題接受你的答案。我不再與Django一起工作,所以我無法以任何方式提供任何幫助。 – Seether 2016-10-03 14:13:42

11

要刪除「添加另一個」選項,請在admin inline類中添加以下方法。

def has_add_permission(self, request): 
    return False 

同樣如果你想禁用「刪除?」選項,請在管理內聯類中添加以下方法。

def has_delete_permission(self, request, obj=None): 
    return False 
+0

到頂部!沒有必要搞亂小部件;) – 2016-08-11 12:24:56

+3

這不是想要的 - 這個答案刪除了添加內聯模型的另一個實例的選項,而不是添加/編輯內聯的外鍵字段的選項(如EDIT中描述的題)。 – jenniwren 2016-08-30 22:09:20

+0

注意:這將刪除「添加另一個」LINK,但仍執行相關的SQL查詢並在包含此請求結果的dom中呈現該小部件。 – ppython 2017-03-14 17:12:04