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

vltsax25  于 2023-01-14  发布在  Go
关注(0)|答案(8)|浏览(201)

我有一个模型在管理网站上注册。它的字段之一是一个长字符串表达式。我想添加自定义表单字段到添加/更新此模型在管理页面。基于这些字段的值,我将建立长字符串表达式,并将其保存在相关的模型字段。
我该怎么做呢?
我正在从符号构建一个数学或字符串表达式。用户选择符号(这些是不属于模型的自定义字段),当他们点击保存时,我从符号列表中创建一个字符串表达式表示,并将其存储在DB中。我不希望符号成为模型和DB的一部分,而只希望最终表达式成为模型和DB的一部分。

s8vozzvw

s8vozzvw1#

无论是在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并设置form属性以引用上面创建的表单。
1.在字段或字段集声明中包含新字段。
就像这样:

class YourModelAdmin(admin.ModelAdmin):

    form = YourModelForm

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

更新:
在Django1.8中,你需要将fields = '__all__'添加到YourModelForm的元类中。

4si2a6ki

4si2a6ki2#

这可以在管理中实现,但是没有一个非常直接的方法。另外,我想建议你把大部分的业务逻辑保留在你的模型中,这样你就不会依赖于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)

然后在admin中,您可以将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)
wn9m85ua

wn9m85ua3#

Django 2.1.1最初的答案让我回答了一半的问题。它并没有帮助我将结果保存到实际模型中的字段中。在我的情况下,我希望有一个用户可以输入数据的文本字段,然后当保存发生时,数据将被处理,结果将被放入模型中的字段并保存。虽然最初的答案显示了如何从额外的字段中获取值,至少在Django2.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__"
k4emjkb1

k4emjkb14#

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

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

fjnneemd5#

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

  • 使用ModelAdmin.ModelAdmin.表单上的form属性创建自定义表单
  • 解析ModelAdminsave_formset方法中的自定义字段。ModelAdmin.save_model(request,obj,form,change)

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

vaj7vani

vaj7vani6#

第一个(最高分)解决方案(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__'
odopli94

odopli947#

这就是我添加**自定义表单字段“extra_field”时所做的,它不是模型“MyModel”**的一部分,如下所示:

# "admin.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
bxpogfeg

bxpogfeg8#

您可能会从我的答案中得到帮助:我的响应上一次在multicheckchoice自定义字段上
您也可以扩展多个表单,使其具有不同的自定义字段,然后将它们分配给inlines类,如stackedinline或tabularinline:
表格=
通过这种方式,您可以避免表单集复杂化,因为您需要从多个模型添加多个自定义字段。
所以你的modeladmin看起来像这样:
内联=[表单1内联,表单2内联,...]
在我之前对这里的链接的回应中,您会发现init和save方法。
init将在您查看页面时加载,而save会将其发送到数据库。
在这两种方法中,你可以做你的逻辑来添加字符串,然后保存,然后在Django管理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',]

...

相关问题