Django 1.7从内联表单中删除"添加"按钮

See*_*her 12 python django django-admin

我在实现(可能)相当简单的任务时遇到了问题.我有完全可修改的模型(Prodotto,Comune),它们显示为"可添加"字段,如下图所示.我不想看到的是这些字段的+(添加)按钮,因此删除了这种形式的"可添加"的适当性.我已经尝试在两个模型中设置has_add_permission = False,但是这会使得完全向这些模型添加新对象变得不可能,不仅仅是以这种形式.

我怎样才能做到这一点?

编辑:为了澄清我的需要,我不希望在FK模型的字段旁边有"+",但我仍然希望能够添加全新的内联.尽可能清楚,正如我在评论中所写,考虑这样的场景:https://code.djangoproject.com/attachment/ticket/20367/django_custom_user_admin_form.png我只需要"+"s "组和国家/地区"旁边已删除

现有代码:

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
Run Code Online (Sandbox Code Playgroud)

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)
Run Code Online (Sandbox Code Playgroud)

这个应用程序的管理界面产生这个:

管理界面

快捷方式链接1和2是我需要删除的那些,被称作列(FKS)我的在线课程.应保留快捷链接3和4,因为它们指的是内本身.

San*_*ndy 20

要删除"添加其他"选项,请在admin inline类中添加以下方法.

def has_add_permission(self, request):
    return False
Run Code Online (Sandbox Code Playgroud)

同样,如果要禁用"删除?" 选项,在admin内联类中添加以下方法.

def has_delete_permission(self, request, obj=None):
    return False
Run Code Online (Sandbox Code Playgroud)

  • 这不是想要的 - 这个答案删除了添加内联模型的另一个实例的选项,而不是添加/编辑内联的外键字段的选项(如编辑问题中所述). (5认同)

the*_*man 15

我认为这是一个比你最终解决的问题更糟糕的解决方案.无论如何,它对我有用.

基本上,这是行内相当于你的建议与重写做get_form的ModelAdmin的方法.在这里,我们覆盖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
Run Code Online (Sandbox Code Playgroud)


See*_*her 6

经过几天的紧张工作,我终于设法找到了一种方法来实现这一目标。

一个简单的技巧,如是绰绰有余用的ModelAdmin子类(见ClienteAdmin在我上面的代码),所以这里的类版本没有加入对“Prodotto”领域的能力范围内处理这个问题的时候:

@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
Run Code Online (Sandbox Code Playgroud)

当处理内联类(TabularInline,StackedInline)时,真正的痛苦就来了,因为似乎根本没有调用get_form()函数,因此前一种方法行不通。

解释我以前的所有尝试都将花费很长时间,而且我对Django甚至还不够好,无法说明为什么它们不起作用。因此,让我们直接看一下解决方案,它实际上甚至没有那么复杂。

我将django.contrib.admin.widgets.RelatedFieldWidgetWrapper小部件子类化,并覆盖了其render方法,这样它就不会在输出中附加“另一个”锚。注释掉几行即可轻松完成。之后,用我自己的版本(django.contrib.admin.widgets.RelatedFieldWidgetWrapper = NoAddingRelatedFieldWidgetWrapper)对原始的RelatedFieldWidgetWrapper进行猴子修补就可以了。

显然,要使其正常工作,我必须在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
Run Code Online (Sandbox Code Playgroud)

为了完整起见,这是相关的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
Run Code Online (Sandbox Code Playgroud)

请任何人提出更好的解决方案,我很乐意代替我接受。


leh*_*ang 6

实际上有一个干净的解决方案:

class YourInline(admin.TabularInline):
    extra = 0
    max_num=0
Run Code Online (Sandbox Code Playgroud)