添加不属于模型的自定义表单字段(Django)

我有一个模型注册在管理网站上。它的一个字段是长字符串表达式。我希望在管理中将自定义表单字段添加到此模型的添加/更新页面。基于这些字段的值,我将构建长字符串表达式并将其保存在相关的模型字段中。

我怎么能这么做?

我正在用符号构建一个数学或字符串表达式。用户选择符号(这些是不属于模型的自定义字段) ,当它们单击 Save 时,我从符号列表中创建一个字符串表达式表示,并将其存储在 DB 中。我不希望符号成为模型和数据库的一部分,只有最终的表达式。

134991 次浏览

它可以做在管理员,但没有一个非常直接的方式来它。另外,我想建议在您的模型中保留大多数业务逻辑,这样您就不会依赖于 Django 管理员。

如果在模型中有两个独立的字段,那么可能会更容易(甚至更好)。然后在模型中添加一个方法来组合它们。

例如:

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)

如果您绝对只想在模型上存储组合字段,而不是存储两个独立字段,您可以这样做:

我从来没有做过这样的事情,所以我不完全确定它将如何工作。

无论是在您的 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

要使管理中出现额外的字段,只需:

  1. 编辑 admin.py并设置表单属性以引用您在上面创建的表单。
  2. 在字段或字段集声明中包含新字段。

像这样:

class YourModelAdmin(admin.ModelAdmin):


form = YourModelForm


fieldsets = (
(None, {
'fields': ('name', 'description', 'extra_field',),
}),
)

更新:

在 Django 1.8中,需要将 fields = '__all__'添加到 YourModelForm的元类中。

您总是可以创建新的管理模板,并在您的 admin_view中执行您需要的操作(覆盖管理添加 URL 到您的 admin_view) :

url(r'^admin/mymodel/mymodel/add/$','admin_views.add_my_special_model')

姜戈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__"

你可以从我的回答中得到帮助: 我的回应上一次关于多重选择自定义字段

您还可以扩展具有不同自定义字段的多个表单,然后将它们分配给内联类,如 stackedinline 或 tabularinline:

表格 =

通过这种方式,您可以避免需要从多个模型添加多个自定义字段的格式集复杂性。

所以你的建模管理员看起来像:

Inlines = [ form1 inline,form2 inline,... ]

在我之前对这个链接的回应中,您将找到 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',]

...

这是我所做的添加 自定义表单字段“ Ultra _ field”,它不是 模特“我的模特”的一部分,如下所示:

# "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

第一个(最高分)解决方案(https://stackoverflow.com/a/23337009/10843740)是准确的,但我有更多。

如果通过代码声明字段,那么该解决方案可以很好地工作,但是如果要动态构建这些字段,该怎么办呢?

在这种情况下,在 __init__函数中为 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=YourCustomMetaClass):
"""
`metaclass=YourCustomMetaClass` is where the magic happens!
"""
# delcare static fields here


class Meta:
model = YourModel
fields = '__all__'