如何在Django ModelAdmin中创建和保存动态字段?

时间:2015-09-01 15:21:08

标签: python django django-admin

我有一些模特:

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,而不是实际的数据库字段{{1 }}

更多信息

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

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上的fields属性,我会得到:

PersonAdmin

尝试通过自定义FieldError: Unknown field(s) (public_groups, private_groups) specified for Person. Check fields/fieldsets/exclude attributes of class PersonAdmin. 方法“动态”添加它们时,我也会遇到同样的事情:

get_formsets

1 个答案:

答案 0 :(得分:2)

以下代码完美无缺。 __init__上覆盖的cleanModelForm方法会添加动态字段,并定义如何保存值。

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

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