验证在Django中运行时生成的表单字段的信息

时间:2018-05-25 01:37:20

标签: django django-forms django-templates django-views

我正在尝试创建一个在运行时生成带有字段的表单的进程。此表单是一个简单的表单,而不是模型表单。它包含许多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字段始终存在于表单中。

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

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

forms.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,
        )

views.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字段的标签。

我认为原因是request.POST中的QueryDict数据与从数据库表中获取的原始词典列表的形式不同。以下是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数据重新创建表单并检查表单在提交时是否有效?

1 个答案:

答案 0 :(得分:0)

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

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