如何在Django ModelAdmin中创建和保存动态字段? [英] How do I create and save dynamic fields in Django ModelAdmin?

查看:255
本文介绍了如何在Django ModelAdmin中创建和保存动态字段?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一些模型:

  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中,我想为每个组类型动态添加字段。所以如果我有两个组类型 public private ,我希望管理表单显示两个字段 public_groups private_groups 而不是实际的db字段。 p>

更多信息



我尝试创建一个自定义窗体来动态添加字段:

  class PersonAdminForm(forms.ModelForm):
def __init __(self,* args,** kwargs)
super(PersonAdminForm,self).__ init __(* args,** kwargs)
new_fields = {}
GroupType.objects.all()中的group_type:
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 中的字段属性中,我得到:

  FieldError:为Person指定的未知字段(public_groups,private_groups)。检查PersonAdmin类的字段/ fieldsets / exclude属性。 

当尝试通过自定义<$ c $动态添加 c> 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']。 public_groups','private_groups'])
return fieldsets


解决方案

以下代码运行良好。 ModelForm 中覆盖的 __ init __ clean 方法添加动态字段并定义如何保存值。



被覆盖的 get_form get_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_objects.all()中的group_type:
field_name ='{0} _groups'.format(group_type.name.lower())
qs = Group.objects.filter(group_type = group_type)
field = forms.ModelMultipleChoiceField(
queryset = qs,
required = False,
初始=初始,

new_fields [field_name] =字段
self.fields.update(new_fields)

def clean(self):
cleaning_data = super(PersonAdminForm,self).clean()
groups = []
GroupType.objects.all()中的group_type:
gt_name ='{0} _groups'.format(group_type .name.lower())
groups.extend(clean_data.get(gt_name))
self.instance.groups.clear()
self.instance.groups.add(* groups)
return clean_data

class Meta:
model = Person
fields ='__all__'


@ admin.register( Person)
class PersonAdmin(admin.ModelAdmin):
form = PersonAdminForm

#使用fieldsets属性而不是字段为动态
#添加组类型字段后来。
fieldsets =(
(无,{
'fields':(
'name',
),
}),


def get_form(self,request,obj = None,** kwargs):
kwargs ['fields'] = flatten_fieldsets(self.declared_fieldsets)
return super(PersonAdmin,自己).get_form(request,obj,** kwargs)

def get_fieldsets(self,request,obj = None):
fieldsets = super(PersonAdmin,self).get_fieldsets(request, obj)
newfieldsets = list(fieldsets)
fields = []
GroupType.objects.all()中的group_type:
fields.append('{0} _groups'。 format(group_type.name.lower()))
newfieldsets.append(['Groups',{'fields':fields}])
return newfieldsets


I have some models:

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="+")

But in the ModelAdmin I'd like to dynamically add fields for each group type. So if I have two group types public, private, I'd like the admin form to show two fields public_groups and private_groups instead of the actual db field groups.

More Info

I've tried creating a custom form to add the fields dynamically:

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__'

Which seems to do the trick as far as adding the fields to the form. But saving those fields and and adding them to the PersonAdmin doesn't work. If I add the fields explicitly to the fields attribute on the PersonAdmin I get:

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

I also get the same thing when trying to add them "dynamically" through a custom get_formsets method:

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

解决方案

The following code worked perfectly. The overridden __init__ and clean methods on the ModelForm adds the dynamic fields and defines how the values should be saved.

The overridden get_form and get_fieldsets together with the fieldsets attribute on the AdminModel make sure the dynamic form fields get displayed in the admin.

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

这篇关于如何在Django ModelAdmin中创建和保存动态字段?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆