Django中的动态字段管理

问题描述:

我想要有关于一个字段的值的附加字段。因此,我建立了一个自定义的管理表单来添加一些新的字段。Django中的动态字段管理

相关的雅可比1这个博客帖子是我想出了:

class ProductAdminForm(forms.ModelForm): 
    class Meta: 
     model = Product 

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

class ProductAdmin(admin.ModelAdmin): 
    form = ProductAdminForm 

admin.site.register(Product, ProductAdmin) 

但附加字段“富”不管理员露面。如果我添加字段这样,一切工作正常,但没有按规定的动态,以添加关于模型

class ProductAdminForm(forms.ModelForm): 

    foo = forms.IntegerField(label="foo") 

    class Meta: 
     model = Product 

class ProductAdmin(admin.ModelAdmin): 
    form = ProductAdminForm 

admin.site.register(Product, ProductAdmin) 

那么另一个字段的值的字段没有任何初始化的方法,我不得不触发再次使新领域发挥作用?还是有其他的尝试?

这是解决问题的办法。由于koniiiik我试图通过延长* get_fieldsets *方法

class ProductAdmin(admin.ModelAdmin): 
    def get_fieldsets(self, request, obj=None): 
     fieldsets = super(ProductAdmin, self).get_fieldsets(request, obj) 
     fieldsets[0][1]['fields'] += ['foo'] 
     return fieldsets 

如果使用多个字段集一定要添加到通过使用适当的索引字段集正确的解决这个问题。

+1

'为GlobalLabel指定的未知字段(foo)。检查字段/字段集/排除GlobalLabelAdmin类的属性。“我收到这个错误,我不知道为什么......你能帮我解决吗? – bhushya

+0

@bhushya:你能明白这一点吗?我也不能让它在Django 1.9.3,如工作:'django.core.exceptions.FieldError:为MyModel' – tehfink

+0

指定的未知领域(S)(dynamicfield1,dynamicfield2)@tehfink好像你还没有定义的字段在你的模型中..你能否将你的模型结构贴在pastebin.com上并分享链接? – bhushya

虽然雅各布的帖子可能适用于正常的ModelForm s(尽管它已经超过一年半了),但管理员有点不同。

所有定义模型,表单ModelAdmins和不使用元类和类自省的声明方式。与管理员一样 - 当您告诉ModelAdmin使用特定表单而不是创建默认表单时,它反映了。它从类中获取字段和其他东西的列表,而不用实例化它。

您的自定义类,然而,这并不在类级别定义额外的表单字段,而是动态地添加一个后已被实例化 - 这是为时已晚了ModelAdmin认识到这种变化。

一个去了解你的问题的方式可能是子类ModelAdmin并覆盖其get_fieldsets方法以实际实例化ModelForm类和实例,而不是类获得的字段列表。不过,您必须记住,这可能比默认实现稍慢。

不知道为什么这不是工作,而是可以可能的解决方法是静态定义(表格上)字段,然后将其覆盖在__init__

斯蒂芬的回答是优雅的,但是当我在dj1.6用于这是一个元组所需要的领域。 完整的解决方案是这样的:

class ProductForm(ModelForm): 
    foo = CharField(label='foo') 


class ProductAdmin(admin.ModelAdmin): 
    form = ProductForm 
    def get_fieldsets(self, request, obj=None): 
     fieldsets = super(ProductAdmin, self).get_fieldsets(request, obj) 
     fieldsets[0][1]['fields'] += ('foo',) 
     return fieldsets 
+0

你不介意,如果我有这在我的答案;) –

您可以创建动态域和使用格式元类字段集。示例代码如下。根据您的要求添加循环逻辑。

class CustomAdminFormMetaClass(ModelFormMetaclass): 
    """ 
    Metaclass for custom admin form with dynamic field 
    """ 
    def __new__(cls, name, bases, attrs): 
     for field in get_dynamic_fields: #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 

上面接受的答案在老版本的django中工作,这就是我这样做的。现在这个django版本已经打​​破了(我目前在1.68,但现在已经很老了)。

它现在被破坏的原因是因为从ModelAdmin.get_fieldsets()返回的字段集中的任何字段最终都会作为字段=参数传递给modelform_factory(),因为列表中的字段会发生错误不存在(并且直到你的表单被实例化并且__ init __被调用)才会存在。

为了解决这个问题,我们必须重写ModelAdmin.get_form(),并提供不包括将在后面添加任何多余的字段的字段列表。 get_form的默认行为是调用这些信息get_fieldsets(),我们必须防止这种情况发生:

# CHOOSE ONE 
# newer versions of django use this 
from django.contrib.admin.utils import flatten_fieldsets 
# if above does not work, use this 
from django.contrib.admin.util import flatten_fieldsets 

class MyModelForm(ModelForm): 
    def __init__(self, *args, **kwargs): 
     super(MyModelForm, self).__init__(*args, **kwargs) 
     # add your dynamic fields here.. 
     for fieldname in ('foo', 'bar', 'baz',): 
      self.fields[fieldname] = form.CharField() 

class MyAdmin(ModelAdmin): 
    form = MyModelForm 

    fieldsets = [ 
     # here you put the list of fieldsets you want displayed.. only 
     # including the ones that are not dynamic 
    ] 

    def get_form(self, request, obj=None, **kwargs): 
     # By passing 'fields', we prevent ModelAdmin.get_form from 
     # looking up the fields itself by calling self.get_fieldsets() 
     # If you do not do this you will get an error from 
     # modelform_factory complaining about non-existent fields. 

     # use this line only for django before 1.9 (but after 1.5??) 
     kwargs['fields'] = flatten_fieldsets(self.declared_fieldsets) 
     # use this line only for django 1.9 and later 
     kwargs['fields'] = flatten_fieldsets(self.fieldsets) 

     return super(MyAdmin, self).get_form(request, obj, **kwargs) 

    def get_fieldsets(self, request, obj=None): 
     fieldsets = super(MyAdmin, self).get_fieldsets(request, obj) 

     newfieldsets = list(fieldsets) 
     fields = ['foo', 'bar', 'baz'] 
     newfieldsets.append(['Dynamic Fields', { 'fields': fields }]) 

     return newfieldsets 
+0

不幸的是,'ModelAdmin.declared_fieldsets' [已被删除(https://docs.djangoproject.com/en/1.9/internals/deprecation/ )在Django 1.9 – tehfink

+0

嗯..嗯,我想,当我在我的服务器升级到1.9,我将会有一些工作要做;)但幸运的是我在我的应用程序复制大多数的管理功能,其他地方... –

+0

还'django.contrib.admin.util'现在是'django.contrib.admin.utils' –

这适用于在Django 1.9.3添加动态字段,只使用一个类的ModelAdmin(没有的ModelForm )并且通过重写get_fields。我不知道这是怎么尚未强劲:

class MyModelAdmin(admin.ModelAdmin): 

    fields = [('title','status',), 'description', 'contact_person',] 
    exclude = ['material'] 

    def get_fields(self, request, obj=None): 
     gf = super(MyModelAdmin, self).get_fields(request, obj) 

     new_dynamic_fields = [ 
      ('test1', forms.CharField()), 
      ('test2', forms.ModelMultipleChoiceField(MyModel.objects.all(), widget=forms.CheckboxSelectMultiple)), 
     ] 

     #without updating get_fields, the admin form will display w/o any new fields 
     #without updating base_fields or declared_fields, django will throw an error: django.core.exceptions.FieldError: Unknown field(s) (test) specified for MyModel. Check fields/fieldsets/exclude attributes of class MyModelAdmin. 

     for f in new_dynamic_fields: 
      #`gf.append(f[0])` results in multiple instances of the new fields 
      gf = gf + [f[0]] 
      #updating base_fields seems to have the same effect 
      self.form.declared_fields.update({f[0]:f[1]}) 
     return gf 
+0

这似乎在django工作1.10 – nidhin

我很长一段时间未能解决动态添加字段的问题。 解决方案“little_birdie”确实有效。谢谢小鸟)) 唯一的细微差别是: “Self.declared_fieldsets”应与“self.fieldsets”所取代。

#kwargs['fields'] = flatten_fieldsets(self.declared_fieldsets) 
kwargs['fields'] = flatten_fieldsets(self.fieldsets) 

我使用的版本是1.10。也许事情已经改变了。

如果有人发现了一个更简单和优雅的解决方案,在这里展示。

感谢所有)))

+0

你非常欢迎。 –