Django Admin中的动态字段
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Django Admin中的动态字段相关的知识,希望对你有一定的参考价值。
我想要有关于一个字段值的其他字段。因此,我构建了一个自定义管理表单来添加一些新字段。
与jacobian 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)
但附加字段'foo'不会显示在管理员中。如果我添加这样的字段,一切正常,但不如所需的动态,添加关于模型的另一个字段的值的字段
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
如果使用多个字段集,请确保使用适当的索引将其添加到右侧字段集。
这适用于在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
虽然Jacob的帖子可能适用于常规的ModelForm
s(即使它超过一年半),但管理员却有点不同。
定义模型的所有声明方式,形式ModelAdmins和诸如此类的东西大量使用元类和类内省。与管理员相同 - 当您告诉ModelAdmin
使用特定表单而不是创建默认表单时,它会对该类进行内省。它从类本身获取字段列表和其他内容,而不实例化它。
但是,您的自定义类不会在类级别定义额外的表单字段,而是在实例化之后动态添加一个 - 这对于ModelAdmin
来说识别此更改为时已晚。
解决问题的一种方法可能是继承ModelAdmin
并覆盖其get_fieldsets
方法以实际实例化ModelForm
类并从实例而不是类中获取字段列表。但是,您必须记住,这可能比默认实现慢一些。
上面接受的答案适用于旧版本的django,这就是我的做法。现在已经打破了以后的django版本(目前我在1.68上,但即使现在已经老了)。
它现在被破坏的原因是因为从ModelAdmin.get_fieldsets()返回的字段集中的任何字段最终都作为fields =参数传递给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
您可以使用表单元类创建动态字段和字段集。示例代码如下。根据您的要求添加循环逻辑。
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
Stephan的答案很优雅,但是当我在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
不确定为什么这不起作用,但是可能的解决方法是静态地(在表单上)定义字段然后在__init__
中覆盖它?
我很长一段时间都无法解决动态添加字段的问题。解决方案“little_birdie”确实有效。谢谢Birdie))唯一的细微差别是:“Self.declared_fieldsets”应该替换为“self.fieldsets”。
#kwargs['fields'] = flatten_fieldsets(self.declared_fieldsets)
kwargs['fields'] = flatten_fieldsets(self.fieldsets)
我使用的是版本1.10。也许事情发生了变化。
如果有人找到更简单优雅的解决方案,请在此处显示。
谢谢大家 )))
以上是关于Django Admin中的动态字段的主要内容,如果未能解决你的问题,请参考以下文章
如何使用 ajax 在 Django-admin 表格内联中读取/写入输入字段?