在Django管理后台模型表单中添加动态字段

12 投票
4 回答
24975 浏览
提问于 2025-04-18 09:55

我需要在我的网站上把一个链接字段添加到Django的管理界面中。 当我把字段名称加到 list_display 里,并定义一个方法来显示这个链接时:

class SetAdmin(admin.ModelAdmin):
    list_display = ['many other fields', 'show_set_url']

    def show_set_url(self, obj):
            return '<a href="#">Set</a>' # render depends on other fields

它在Django管理界面的列表中显示出来了,但在模型表单中却没有。 我该怎么做才能在Django管理界面的Sets表单中添加这个链接呢?

我也尝试为这个模型创建一个自定义表单:

from core.models import Set
from django import forms

class SetAdminForm(forms.Form):
    class Meta:
        model = Set

    def __init__(self, *args, **kwargs):
        super(SetAdminForm, self).__init__(*args, **kwargs)
        self.fields['foo'] = forms.IntegerField(label=u"Link")

但是在表单中没有看到任何效果。

4 个回答

3

我在使用Django 1.9处理内联模型时,对所有这些答案都感到困惑。

这里有一段代码示例,帮我实现了动态字段。在这个例子中,我假设你已经有一个叫做ProductVariant的模型,它和一个叫做Product的模型有外键关系:

class ProductVariantForm(forms.ModelForm):
  pass

class ProductVariantInline(admin.TabularInline):
  model = ProductVariant
  extra = 0

  def get_formset(self, request, obj=None, **kwargs):
    types = ( (0, 'Dogs'), (1, 'Cats'))
        #Break this line appart to add your own dict of form fields.
        #Also a handy not is you have an instance of the parent object in obj
    ProductVariantInline.form = type( 'ProductVariantFormAlt', (ProductVariantForm, ), { 'fancy_select': forms.ChoiceField(label="Animals",choices=types)})
    formset = super( ProductVariantInline, self).get_formset( request, obj, **kwargs)
    return formset

class ProductAdmin(admin.ModelAdmin):
  inlines = (ProductVariantInline, )

我具体的需求是,ProductVariant有一个多对多的关系,但这个关系的选择应该根据业务逻辑的分组来限制。因此,我需要在内联中使用自定义的动态字段。

4

你需要把它添加到 readonly_fields 列表里。

class SetAdmin(admin.ModelAdmin):
    list_display = ['many other fields', 'show_set_url']
    readonly_fields = ['show_set_url']

    def show_set_url(self, obj):
            return '<a href="#">Set</a>' # render depends on other fields

相关文档。

4

你可以使用表单的元类来创建动态字段和字段集。下面给出了示例代码。根据你的需求添加循环逻辑。

class CustomAdminFormMetaClass(ModelFormMetaclass):
    """
    Metaclass for custom admin form with dynamic field
    """
    def __new__(cls, name, bases, attrs):
        for field in myloop: #add logic to get the fields
            attrs[field] = forms.CharField(max_length=30) #add logic to the form field
        return super(CustomAdminFormMetaClass, cls).__new__(cls, name, bases, attrs)


class CustomAdminForm(six.with_metaclass(CustomAdminFormMetaClass, forms.ModelForm)):
    """
    Custom admin form
    """

    class Meta:
        model = ModelName
        fields = "__all__" 


class CustomAdmin(admin.ModelAdmin):
    """
    Custom admin 
    """

    fieldsets = None
    form = CustomAdminForm

    def get_fieldsets(self, request, obj=None):
        """
        Different fieldset for the admin form
        """
        self.fieldsets = self.dynamic_fieldset(). #add logic to add the dynamic fieldset with fields
        return super(CustomAdmin, self).get_fieldsets(request, obj)

    def dynamic_fieldset(self):
        """
        get the dynamic field sets
        """
        fieldsets = []
        for group in get_field_set_groups: #logic to get the field set group
            fields = []
            for field in get_group_fields: #logic to get the group fields
                fields.append(field)

            fieldset_values = {"fields": tuple(fields), "classes": ['collapse']}
            fieldsets.append((group, fieldset_values))

        fieldsets = tuple(fieldsets)

        return fieldsets
8

你可以通过重写 ModelAdmin 来实现你想要的功能,但你还需要重写 ModelAdmin.get_fieldsets这个回答可能对你有帮助。链接中的提问者遇到了类似的问题。

补充:如果你不想让某个字段可以编辑,可以尝试重写 ModelAdmin.get_readonly_fields。另外,你也可以查看 这里,了解更多可以重写的属性。

撰写回答