首页 > 解决方案 > 验证 Django 运行时生成的表单字段信息

问题描述

我正在尝试创建一个在运行时生成带有其字段的表单的过程。此表格是简单表格,而不是模型表格。它包含许多 RadioSelect 字段、一个 TextArea 和一个 IntegerField。将生成的单选按钮字段的数量由从数据库表中获取的数据决定。数据采用 JSON 格式,解析时包含字典列表,如下所示:

[
  {'criteria': 'design', 'description': 'aaa, bbb'}, 
  {'criteria': 'design', 'description': 'ccc, ddd'}, 
  {'criteria': 'design', 'description': 'eee, fff'}, 
  {'criteria': 'design', 'description': 'ggg, hhh'}, 
  {'criteria': 'design', 'description': 'iii, jjj'}, 
  {'criteria': 'design', 'description': 'kkk, lll'},
]

在上面的示例中,有 6 个字典,这意味着将生成 6 个 RadioSelect 字段。如果 JSON 数据包含 10 个字典,则将生成 10 个 RadioSelect 字段。TextArea 和 IntegerField 字段始终存在于表单中。

提交表单时,我想验证表单,如果没有错误,则从表单中获取数据,对数据执行一些操作,将数据保存在不同的数据库表中,并使用保存的数据显示表单。如果有错误,则显示出现错误的表单。

我想只使用一个视图和一个模板来编写这个过程。这是我的代码的简化摘录

表格.py

class ExampleForm(forms.Form):
    def __init__(self, *args, **kwargs):
        radio_choices = (
            ('0', '0'),
            ('1', '1'),
            ('2', '2'),
            ('3', '3'),
            ('4', '4'),
        )

        ratings = kwargs.pop('rating')
        super(ExampleForm, self).__init__(*args, **kwargs)
        if isinstance(ratings, QueryDict):
            self.ratings = ratings.dict()
            # stuck here
        else:
            self.ratings = ratings
            # loop through the dict and create radio button for each of them
            for idx, rating in enumerate(self.ratings, start=1):
                field = forms.TypedChoiceField(
                    label=rating["criteria"],
                    choices=radio_choices,
                    coerce=lambda x: bool(int(x)),
                    widget=forms.RadioSelect,
                    initial=0,
                    required=False,
                )
                self.fields["criteria{}".format(idx)] = field

        self.fields["details"] = forms.CharField(
            label="Details",
            # max_length=80,
            required=False,
            widget=forms.Textarea(attrs={
                'placeholder': 'Type any other impressions you have',
            }),
            help_text='Write any message here',
        )

        self.fields["overall_evaluation"] = forms.IntegerField(
            label="Overall Evaluation",
            max_value=4,
            min_value=0,
            required=True,
        )

视图.py

from .models import Rating, Result
def formtest(request):
    if request.method == "POST":
        # request.POST contains a QueryDict which is immutable
        # To get a mutable object call the copy() method on request.POST??
        ratingform = ExampleForm(rating=request.POST or None) # fails here

        # call is_valid here??
        # Process data
        # Save data in Result
    else:
        rating = Rating.objects.get(pk=4).criteria
        ratingform = ExampleForm(rating=json.loads(rating))

return render(request, 'formtest.html', context={
    'form': ratingform,
})

第一次访问表单时,我可以毫无问题地创建表单,但是在提交表单后,我不仅会收到错误消息,而且我认为我将无法为 RadioSelect 字段生成标签。

我认为原因是 QueryDict 中的数据与request.POST从数据库表中获取的原始字典列表的形式不同。这是request.POST看起来的样子

<QueryDict: {'csrfmiddlewaretoken': ['sfdgbif'], 'criteria1': [
'0'], 'criteria2': ['0'], 'criteria3': ['0'], 'criteria4': ['0'], 'criteria5': ['0'], 'criteria6': ['0'], 'details': ['very good product'], 'overall_evaluation': ['3']}>

键 ,与原始字典列表中criteria1..criteria6的键不同criteria,它们仅包含数字,即在提交表单之前从单选按钮中选择的值。一种方法可能是修改 QueryDict 但我不知道这是否是一个好方法。

如何使用 request.POST 数据重新创建表单并检查表单在提交时是否有效?

标签: djangodjango-formsdjango-templatesdjango-views

解决方案


我想到了。我没有将 POST 值传递给表单,而是将其作为表单的**kwargs参数传递,这是完全错误的。因此,无法验证表单。一次代码更改解决了我的问题。

ratingform = ExampleForm(request.POST, rating=interview_rating)

推荐阅读