[英]Add custom form fields that are not part of the model (Django)
我在管理站点上注册了一个 model。 其中一个字段是长字符串表达式。 我想在管理员中将自定义表单字段添加到此 model 的添加/更新页面。 基于这些字段的值,我将构建长字符串表达式并将其保存在相关的 model 字段中。
我怎样才能做到这一点?
我正在从符号构建数学或字符串表达式。 用户选择符号(这些是不属于模型的自定义字段),当他们单击保存时,我从符号列表中创建一个字符串表达式表示并将其存储在数据库中。 我不希望这些符号成为 model 和 DB 的一部分,只是最终表达式。
在您的admin.py
或单独的forms.py
中,您可以添加一个ModelForm
类,然后像往常一样在其中声明您的额外字段。 我还举例说明了如何在form.save()
中使用这些值:
from django import forms
from yourapp.models import YourModel
class YourModelForm(forms.ModelForm):
extra_field = forms.CharField()
def save(self, commit=True):
extra_field = self.cleaned_data.get('extra_field', None)
# ...do something with extra_field here...
return super(YourModelForm, self).save(commit=commit)
class Meta:
model = YourModel
要让额外的字段出现在管理员中,只需:
admin.py
并将表单属性设置为引用您在上面创建的表单。像这样:
class YourModelAdmin(admin.ModelAdmin):
form = YourModelForm
fieldsets = (
(None, {
'fields': ('name', 'description', 'extra_field',),
}),
)
更新:
在 Django 1.8 中,您需要将fields = '__all__'
添加到YourModelForm
的元类中。
可以在管理员中进行,但没有一种非常简单的方法。 另外,我想建议将大多数业务逻辑保留在您的模型中,这样您就不会依赖 Django Admin。
如果您的模型上有两个单独的字段,可能会更容易(甚至更好)。 然后在您的模型上添加一个结合它们的方法。
例如:
class MyModel(models.model):
field1 = models.CharField(max_length=10)
field2 = models.CharField(max_length=10)
def combined_fields(self):
return '{} {}'.format(self.field1, self.field2)
然后在管理员中,您可以将combined_fields()
添加为只读字段:
class MyModelAdmin(models.ModelAdmin):
list_display = ('field1', 'field2', 'combined_fields')
readonly_fields = ('combined_fields',)
def combined_fields(self, obj):
return obj.combined_fields()
如果您想将combined_fields
存储在数据库中,您也可以在保存模型时保存它:
def save(self, *args, **kwargs):
self.field3 = self.combined_fields()
super(MyModel, self).save(*args, **kwargs)
Django 2.1.1 主要答案让我回答了我的问题。 它没有帮助我将结果保存到我的实际模型中的字段中。 在我的情况下,我想要一个用户可以输入数据的文本字段,然后当保存发生时,将处理数据并将结果放入模型中的字段并保存。 虽然原始答案显示了如何从额外字段中获取值,但至少在 Django 2.1.1 中没有显示如何将其保存回模型
这会从未绑定的自定义字段中获取值,处理并将其保存到我的真实描述字段中:
class WidgetForm(forms.ModelForm):
extra_field = forms.CharField(required=False)
def processData(self, input):
# example of error handling
if False:
raise forms.ValidationError('Processing failed!')
return input + " has been processed"
def save(self, commit=True):
extra_field = self.cleaned_data.get('extra_field', None)
# self.description = "my result" note that this does not work
# Get the form instance so I can write to its fields
instance = super(WidgetForm, self).save(commit=commit)
# this writes the processed data to the description field
instance.description = self.processData(extra_field)
if commit:
instance.save()
return instance
class Meta:
model = Widget
fields = "__all__"
您始终可以创建新的管理模板,并在admin_view
中执行您需要的操作(覆盖 admin 添加 URL 到您的admin_view
):
url(r'^admin/mymodel/mymodel/add/$','admin_views.add_my_special_model')
如果您绝对只想在模型上存储组合字段而不是两个单独的字段,您可以执行以下操作:
ModelAdmin
上的form
属性创建自定义表单。 ModelAdmin.formModelAdmin
上save_formset
方法中的自定义字段。 ModelAdmin.save_model(request, obj, form, change)我从来没有做过这样的事情,所以我不完全确定它会如何工作。
第一个(最高分)解决方案( https://stackoverflow.com/a/23337009/10843740 )是准确的,但我有更多。
如果您通过代码声明字段,该解决方案可以完美运行,但如果您想动态构建这些字段怎么办?
在这种情况下,在__init__
ModelForm
中为 ModelForm 创建字段将不起作用。 您将需要传递一个自定义metaclass
并覆盖__new__
函数中的declared_fields
!
这是一个示例:
class YourCustomMetaClass(forms.models.ModelFormMetaclass):
"""
For dynamically creating fields in ModelForm to be shown on the admin panel,
you must override the `declared_fields` property of the metaclass.
"""
def __new__(mcs, name, bases, attrs):
new_class = super(NamedTimingMetaClass, mcs).__new__(
mcs, name, bases, attrs)
# Adding fields dynamically.
new_class.declared_fields.update(...)
return new_class
# don't forget to pass the metaclass
class YourModelForm(forms.ModelForm, metaclass=NamedTimingMetaClass):
"""
`metaclass=YourCustomMetaClass` is where the magic happens!
"""
# delcare static fields here
class Meta:
model = YourModel
fields = '__all__'
您可能会从我的回答中获得帮助: 我之前在 multicheckchoice 自定义字段上的回复
您还可以扩展具有不同自定义字段的多个表单,然后将它们分配给您的内联类,如stackedinline 或tabularinline:
表格 =
这样,您可以避免需要从多个模型添加多个自定义字段的表单集复杂性。
所以你的模型管理员看起来像:
内联 = [form1inline,form2inline,...]
在我之前对此处链接的回复中,您将找到 init 和 save 方法。
init 将在您查看页面时加载并保存将其发送到数据库。
在这两种方法中,您可以执行逻辑来添加字符串,然后保存,然后在 Django admin change_form 或 change_list 中查看它,具体取决于您想要的位置。 list_display 将在 change_list 上显示您的字段。 让我知道它是否有帮助......
class CohortDetailInline3(admin.StackedInline):
model = CohortDetails
form = DisabilityTypesForm
...
class CohortDetailInline2(admin.StackedInline):
model = CohortDetails
form = StudentRPLForm
……
@admin.register(Cohort)
class CohortAdmin(admin.ModelAdmin):
form = CityInlineForm
inlines = [uploadInline, cohortDetailInline1,
CohortDetailInline2, CohortDetailInline3]
list_select_related = True
list_display = ['rto_student_code', 'first_name', 'family_name',]
...
这是我添加自定义表单字段“extra_field”所做的,它不是模型“MyModel”的一部分,如下所示:
# "models.py"
from django.contrib import admin
from django import forms
from .models import MyModel
class MyModelForm(forms.ModelForm):
extra_field = forms.CharField()
def save(self, commit=True):
extra_field = self.cleaned_data.get('extra_field', None)
# Do something with extra_field here
return super().save(commit=commit)
@admin.register(MyModel)
class MyModelAdmin(admin.ModelAdmin):
form = MyModelForm
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.