【问题标题】:How do I create and save dynamic fields in Django ModelAdmin?如何在 Django ModelAdmin 中创建和保存动态字段?
【发布时间】:2015-09-01 15:21:08
【问题描述】:

我有一些模型:

class GroupType(models.Model):
    name = models.CharField(max_length=255)

class Group(models.Model):
    name = models.CharField(max_length=255)
    group_type = models.ForeignKey(GroupType)

class Person(models.Model):
    name = models.CharField(max_length=255)
    groups = models.ManyToManyField(Group, related_name="+")

但在 ModelAdmin 中,我想为每个组类型动态添加字段。因此,如果我有两个组类型publicprivate,我希望管理表单显示两个字段public_groupsprivate_groups,而不是实际的数据库字段groups

更多信息

我尝试创建自定义表单来动态添加字段:

class PersonAdminForm(forms.ModelForm):
    def __init__(self, *args, **kwargs):
        super(PersonAdminForm, self).__init__(*args, **kwargs)
        new_fields = {}
        for group_type in GroupType.objects.all():
            field_name = "{0}_groups".format(group_type.name.lower())
            qs = Group.objects.filter(group_type=group_type)
            field_field = forms.ModelMultipleChoiceField(queryset=qs)
            new_fields[field_name] = field_field
        self.fields.update(new_fields)

    class Meta:
        model = Person
        fields = '__all__'

就将字段添加到表单而言,这似乎起到了作用。但是保存这些字段并将它们添加到PersonAdmin 不起作用。如果我将字段显式添加到PersonAdmin 上的fields 属性,我会得到:

FieldError: Unknown field(s) (public_groups, private_groups) specified for Person. Check fields/fieldsets/exclude attributes of class PersonAdmin.

在尝试通过自定义 get_formsets 方法“动态”添加它们时,我也得到了同样的结果:

def get_fieldsets(self, request, obj=None):
    fieldsets = super(PersonAdmin, self).get_fieldsets(request, obj)
    print(self.form.fields)
    fieldsets[0][1]['fields'].extend(['public_groups', 'private_groups'])
    return fieldsets

【问题讨论】:

    标签: python django django-admin


    【解决方案1】:

    以下代码完美运行。 ModelForm 上重写的 __init__clean 方法添加了动态字段并定义了值的保存方式。

    覆盖的get_formget_fieldsets 以及AdminModel 上的fieldsets 属性确保动态表单字段显示在管理员中。

    class PersonAdminForm(forms.ModelForm):
        def __init__(self, *args, **kwargs):
            super(PersonAdminForm, self).__init__(*args, **kwargs)
            new_fields = {}
            initial = self.instance.groups.all()
            for group_type in GroupType.objects.all():
                field_name = '{0}_groups'.format(group_type.name.lower())
                qs = Group.objects.filter(group_type=group_type)
                field = forms.ModelMultipleChoiceField(
                    queryset=qs,
                    required=False,
                    initial=initial,
                )
                new_fields[field_name] = field
            self.fields.update(new_fields)
    
        def clean(self):
            cleaned_data = super(PersonAdminForm, self).clean()
            groups = []
            for group_type in GroupType.objects.all():
                gt_name = '{0}_groups'.format(group_type.name.lower())
                groups.extend(cleaned_data.get(gt_name))
            self.instance.groups.clear()
            self.instance.groups.add(*groups)
            return cleaned_data
    
        class Meta:
            model = Person
            fields = '__all__'
    
    
    @admin.register(Person)
    class PersonAdmin(admin.ModelAdmin):
        form = PersonAdminForm
    
        # using the fieldsets attribute instead of fields in order to dynamically
        # add group type fields later.
        fieldsets = (
            (None, {
                'fields': (
                    'name',
                ),
            }),
        )
    
        def get_form(self, request, obj=None, **kwargs):
            kwargs['fields'] = flatten_fieldsets(self.declared_fieldsets)
            return super(PersonAdmin, self).get_form(request, obj, **kwargs)
    
        def get_fieldsets(self, request, obj=None):
            fieldsets = super(PersonAdmin, self).get_fieldsets(request, obj)
            newfieldsets = list(fieldsets)
            fields = []
            for group_type in GroupType.objects.all():
                fields.append('{0}_groups'.format(group_type.name.lower()))
            newfieldsets.append(['Groups', {'fields': fields}])
            return newfieldsets
    

    【讨论】:

      猜你喜欢
      • 2013-09-26
      • 2013-07-07
      • 1970-01-01
      • 2011-08-30
      • 2021-06-08
      • 1970-01-01
      • 1970-01-01
      • 2011-08-26
      • 1970-01-01
      相关资源
      最近更新 更多