django ModelForms - 我做得对吗?

时间:2017-07-21 01:11:28

标签: django django-forms

我有一个使用6字段或8字段答案的民意调查应用扩展程序。我已经非常简单地定义了这些ModelForms。

class expert_judgement_three_form(ModelForm):
"""From Burgman "Trusting Judgements" 2016 p95. Values are probabilities """
class Meta:
    model = EJ_three_field
    exclude = ['question','user']

[这些表格似乎需要在模板中进行大量的手动配置才能进行估算:理由对]

要预填充字段,我正在创建模型的对象实例,然后将其传递给表单,然后从表单中取回它。 the docs中的示例逐项逐步执行cleaning_data字典 - 它似乎并没有减少样板。我注意到this reply,我看到this answer,我可能会以这种方式工作。

我无法逃避这种感觉,即我误解或误读了应该如何使用表格,特别是模型的关键特征,因为仍然可以看到很多(并给我带来麻烦)。

这个问题的一个很好的答案是最稀疏的模型,ModelForm和多字段形式的视图,它始终预先填写用户之前的问题答案。

3 个答案:

答案 0 :(得分:0)

基本上,FormModelForm是不同的。您手动配置了表单,系统会自动创建ModelForm

如果您已创建模型,则通常希望允许用户通过表单创建这些模型。 Django不需要复制所有字段名称并自己创建表单,而是提供了一个快捷方式,ModelForm:

使用 Modelform

创建的模型表单示例

<强> forms.py

class expert_judgement_three_form(ModelForm):
"""From Burgman "Trusting Judgements" 2016 p95. Values are probabilities """
     class Meta:
           model = EJ_three_field
           exclude = ['question','user']

此表单自动具有与其创建的EJ_three_field模型相同的字段类型。

<强> views.py

def create(request):
    form = expert_judgement_three_form(request.POST)
    if request.method == 'POST':
        form = expert_judgement_three_form(request.POST)
        print form.errors
        if form.is_valid :
            print "all validation passed"
            # commit=False tells Django that "Don't send this to database yet.
            expert_judgement_three_form = form.save(commit=False)
            expert_judgement_three_form.save()
            return (request, "")
        else:
             print form.errors
    else:
        form = expert_judgement_three_form(request.POST)
    return render(request, "",{"form":form})

def edit(request,pk):
    EJ_three_field_object = EJ_three_field.objects.get(pk=pk)
    form = expert_judgement_three_form(request.POST,instance=EJ_three_field_object)
    if request.method == 'POST':
        form = expert_judgement_three_form(request.POST,instance=EJ_three_field_object)
        print form.errors
        if form.is_valid :
            print "all validation passed"
            # commit=False tells Django that "Don't send this to database yet.
            expert_judgement_three_form = form.save(commit=False)
            expert_judgement_three_form.save()
            return (request, "")
        else:
             print form.errors
    else:
        form = expert_judgement_three_form(request.POST,instance=EJ_three_field_object)enter code here
    return render(request, "",{"form":form})

<强> urls.py

url(r'^create/', views.create, name='create'),
#edit
url(r'^edit/(?P<pk>\d+)/$',views.edit,name='edit'),

文档:Creating forms from ModelForm

答案 1 :(得分:0)

我会用这种方式解释。

1

不使用{{form}}模板标记,您应该自己编写<form action="." method="post">{% csrf token %} <label ...> <input type ...> .. </form>。因此,使用表单,您可以减少编写所有这些内容的时间。

2

没有modelForm,您需要指定每个输入。

class Example(forms.Form):
    example1 = forms.CharField(label="label name", max_length=100)
    example2 = forms.IntergerField()
    ... what if you have 10 inputs?, you should write all 10 inputs

但是如果您已经定义了模型(在许多情况下,您可以在数据库中创建表单来保存或更新。这意味着您已经定义了模型。),您可以简单地使用ModelForm而无需花时间自己编写FormField。

class Example(ModelForm):
    class Meta:
        Model : yourModel
        fields : ['example1', 'example2', ...]

我认为我可以安全。如果您定义模型元素,如

#model.py
class ExampleModelCalss(models.Model):
    example1 = models.CharField(max_length=50)

#forms.py
class ExampleFormClass(forms.Form):
    example1 = forms.CharField(max_length=100)

你可以输入长度为70的文本,因此它会通过表单验证,但是当它保存在你的数据库中时会发生什么?

所以我的想法就是这样。我很好奇其他人的想法。

另外,你可以混合它。 例如,

#models.py
class ExampleModelCalss(models.Model):
    example1 = models.CharField(max_length=50)
    example2 = models.IntegerField(default=0)

您要添加一个不在您的模型中的。

class ExampleMixForm(forms.ModelForm)
    example3 = forms.CharField(max_length=50) # adding

    class Meta:
        Model : ExampleModelCalss
        fields = ['example1', 'example2', 'example3'] # adding

答案 2 :(得分:0)

我现在有效!我想我会提出这个有效的代码,万一有人发现它有用。可能使这个有趣的困难之一是我只使用表单来进行多字段答案,而不是将它们用于单字段答案。任何评论都会对此表示欢迎。我对此很陌生。

models.py

class Question(models.Model):
...
class Answer(models.Model):
    question = models.ForeignKey(Question, on_delete=models.CASCADE)
    user = models.ForeignKey(User, on_delete=models.CASCADE, default = 1)
    class Meta:
        abstract = True

# What follows is a class method that gets existing answers, creates new default entries or updates answers depending on when it is called. It assumes that each question is answered only once.
    @classmethod
    def get_or_update_answer(self, user, question, submitted_value={None}):
        if question.answer_type == 'CH':
            if submitted_value == {None}:
                selected_choice = question.choice_set.first() # by default, select the top of a set of radio buttons
                answer, _created = Vote.objects.get_or_create(user = user, question = question, defaults={'choice':selected_choice})

            else:
                selected_choice = question.choice_set.get(pk=submitted_value)
                answer = Vote.objects.get(user = user, question = question)
                answer.choice = selected_choice

        if question.answer_type == 'SA':
            if submitted_value == {None}:
                submitted_value = "brief response"
                answer, _created = Short_Answer.objects.get_or_create(user = user, question = question, defaults={'short_answer': submitted_value})

            else:
                answer = Short_Answer.objects.get(user = user, question = question)
                answer.short_answer = submitted_value

        if question.answer_type == 'LA':
            if submitted_value == {None}:
                submitted_value = "full response"
                answer, _created = Long_Answer.objects.get_or_create(user = user, question = question, defaults={'long_answer':submitted_value})

            else:
                answer = Long_Answer.objects.get(user = user, question = question)
                answer.long_answer = submitted_value
        if question.answer_type == 'E3':
            if submitted_value == {None}:
                submitted_value = {'lowest_value': 0, 'lv_rationale': "low estimate reasons",
                                  'highest_value':0,  'hv_rationale': "high estimate reasons",
                                  'best_value':0, 'bv_rationale': "best estimate reasons",}
                answer, _created = EJ_three_field.objects.get_or_create(user= user, question = question, defaults=submitted_value)
            else:
                answer = EJ_three_field.objects.get(user= user, question = question)
                for key, value in submitted_value.items():
                    setattr(answer,key,value)
        if question.answer_type == 'E4':
            if submitted_value == {None}:
                submitted_value = {'lowest_value': 0, 'lv_rationale': "low estimate reasons",
                                  'highest_value':0,  'hv_rationale': "high estimate reasons",
                                  'best_value':0, 'bv_rationale': "best estimate reasons",
                                  'confidence': 0, 'conf_rationale': "reasons for confidence score",}
                answer, _created = EJ_four_field.objects.get_or_create(user = user, question = question, defaults=submitted_value)
            else:
                answer = EJ_four_field.objects.get(user= user, question = question)
                for key, value in submitted_value.items():
                    setattr(answer,key,value)
        # answer.save() - not required for create / update funcs
        answer.save()
        return answer

class Short_Answer(Answer):
class Long_Answer(Answer):
class Vote(Answer):
class EJ_three_field(Answer):
class EJ_four_field(Answer):

Views.py

def pageView(request, user_id, page_num):
    question_set = Question.objects.filter(man_page = page_num)
    user = User.objects.get(username = user_id)
    template = 'polls/page_question.html'
    context = {'question_set' : question_set, }
    forms = {}
    answers = {}
    for question in question_set:
        answers[question] = Answer.get_or_update_answer(user, question)
        form_instance = form_instantiator(question, instance = answers[question])
        forms[question] = form_instance

    context['forms']=forms
    context['answers']=answers
    return render(request, template, context)

@login_required
def answer(request, user_id, man_index):
    #attempt to standardise saving of answers (votes, shorts, longs, E3, vE4 etc)
    user = User.objects.get(username = user_id)
    question = Question.objects.get(man_index = man_index)
    form_instance = form_instantiator(question, request = request)
    if form_instance == None:
        answer_value = request.POST['answer_value']
        Answer.get_or_update_answer(user = user, question = question, submitted_value = answer_value)
    else:
        form = form_instantiator(question, request = request)
        if form.is_valid():
            print(form.cleaned_data)
            Answer.get_or_update_answer(user = user, question = question, submitted_value = form.cleaned_data)
    return HttpResponseRedirect(reverse('polls:page', args=(user_id, question.man_page)))

回答我原来的问题:可以使用(instance =)或a(request.POST)创建ModelForm,也可以使用两者都不创建。提交数据时,将丢弃与上下文一起传递的对象。可以使用form.save()保存ModelForm,这非常有效。