简体   繁体   English

使用单选按钮创建 Django 表单调查表

[英]Creating Django form questionnaire with radio buttons

I'm attempting to implement a survey within my django application.我正在尝试在我的 django 应用程序中实施一项调查。 Currently I have it implemented by manually drawing out the HTML for the form structure like so:目前,我通过手动为表单结构绘制 HTML 来实现它,如下所示:

      <!-- Question 1-->
  <form method="post" action="{% url 'piuserform' %}">
    {% csrf_token %}
    <div class="mx-auto">
      <h3 class="mb-4">At the time of the accident, the injured party was: </h3>
      <label class="radcontainer">The driver of an automobile.
            <input type="radio" name="question1" value="The driver of an automobile">
            <span class="checkmark"></span>
          </label>
      <label class="radcontainer">The passenger of an automobile.
            <input type="radio" name="question1" value="The passenger of an automobile">
            <span class="checkmark"></span>
          </label>
      <label class="radcontainer">A pedestrian.
            <input type="radio" name="question1" value="A pedestrian">
            <span class="checkmark"></span>
          </label>
    </div>
    <!-- /Question 1 -->


    <!-- question 3-->
    <div class="mx-auto pt-5">
      <h3 class="mb-4">How many vehicles were involved in the accident?</h3>
      <label class="radcontainer">One
            <input type="radio" name="question3" value="One">
            <span class="checkmark"></span>
          </label>
      <label class="radcontainer">Two
            <input type="radio" name="question3" value="Two">
            <span class="checkmark"></span>
          </label>
      <label class="radcontainer">Three
            <input type="radio" name="question3" value="Three">
            <span class="checkmark"></span>
          </label>
      <label class="radcontainer">Four or more
            <input type="radio" name="question3" value="Four or more">
            <span class="checkmark"></span>
          </label>
    </div>
    <!-- /Question 3 -->

Now I tried to implement something to this effect using Django forms api but it would only render the last question.现在我尝试使用 Django forms api 来实现这种效果,但它只会呈现最后一个问题。 The questionnaire is all radio buttons with the answer fields varying greatly.问卷都是单选按钮,答案字段变化很大。 Is there a way to automate this so I can possibly render using {{form}} via modelForm or Formsetfactory?有没有办法自动化这个,所以我可以通过 modelForm 或 Formsetfactory 使用 {{form}} 渲染? I've taken a look at many documentation but none of them are really clear for my question and when I tried implementing the forms api like I said, it would only render one question.我查看了许多文档,但没有一个对我的问题非常清楚,当我尝试实现 forms api 时,就像我说的那样,它只会提出一个问题。 help greatly appreciated非常感谢帮助

EDIT:编辑:

When I tried to implement the forms API I used this method:当我尝试实现 forms API 时,我使用了这种方法:

forms.py forms.py

blah_choices = [("1", "first"), ("2", "second")]
blah_choices2 = [("3", "third"), ("4", "four")]

class testRadioQuestions(forms.Form):
    q1 = forms.ChoiceField(label="Blah blah blah form question",
                           choices=(blah_choices),
                           widget=forms.RadioSelect()),
    q2 = forms.ChoiceField(label="blah blah some more form question",
                           choices=(blah_choices2),
                           widget=forms.RadioSelect())

view看法

def other_questionnaire(request):
     if request.method == "POST":
         print(request.body)
     return render(request, 'website/otherQuestions.html', {'form': form})

This looks like a lot of work.这看起来工作量很大。 I think the problem is probably that your view context only has the last form.我认为问题可能是您的视图上下文只有最后一种形式。 You will need to create a list or a dictionary of forms.您将需要创建 forms 的列表或字典。 You will also need to differentiate their 'id' using a " prefix ".您还需要使用“ 前缀”来区分他们的“id”。

I worked out a solution to this but (like you, I think) I have a lingering feeling that I missed something important in the 'forms' api.我想出了一个解决方案,但是(就像你一样,我想)我有一种挥之不去的感觉,我错过了“表格”api 中的一些重要内容。

My solution was to manually assign a prefix to each form that would allow me to to unpack it from the POST into the correct form subclass.我的解决方案是手动为每个表单分配一个前缀,这样我就可以将它从 POST 解压到正确的表单子类中。 I won't post all the different parts, but here's a sketch:我不会发布所有不同的部分,但这里有一个草图:

# forms.py
AnswerMap = { question_answer_type1 : FormClass1, etc etc }
def form_get(question, instance=None):
    answerform = AnswerMap[question.answer_type](instance=instance) # not sure this works, may need to handle two cases separately.
    return answerform 

def form_post(question, data, instance=None):
    answerform = AnswerMap[question.answer_type](data=data, instance=instance)
    if answerform.is_valid():
        return answerform
    else:
        pass  # handle error, I guess.

The next part is the view.下一部分是视图。 The way I go through the request.POST here seems pretty inefficient, because I go through twice - first to collect prefixes and work out which questions are there, and a second time (in a single comprehension) collecting the data for each prefix.我 go 通过 request.POST 的方式在这里似乎效率很低,因为我通过两次 go - 首先收集前缀并找出存在哪些问题,然后第二次(在单一理解中)收集每个前缀的数据。 But I haven't come up with anything better yet.但我还没有想出更好的办法。

# views.py
class page_view(View):
    def get(self, page_no):
        forms = {}
        questions = Question.objects.filter(page=page_no)
        for question in questions:
            forms[question] = get_form_for_question(question, prefix=('q'+question.pk))
        self.context['forms'] = forms
        return render(request, template, context)

     def post(self, page_no)
         prefixes = []
         self.form_items = {}
         for key, value in request.POST.items():
             if key.startswith("q"):
                 q_number = re.search(r'q(\d+)#', key)
                 pk_q = int(q_number.group(1))  # the digits are the question primary key
                 prefix = 'q' + str(pk_q)
                 if prefix not in prefixes:
                     prefix.append(prefix)
                     question = Question.objects.get(pk=pk_q)
                     self.form_items[prefix] = {key: val for key,val in request.POST.items() if prefix in key}  # collects data for form; add any data that you don't render but will need in the database somewhere here - e.g. username or timestamp
                     form = form_post(value=self.form_items[prefix], question=question)
                     if form.is_valid():
                         form.save()
         return HttpRedirectResponse('as appropriate')

Add a custom template tag to unpack the form in the template:添加自定义模板标签以解压模板中的表单:

# custom_tags.py
@register.filter
def get_item(dictionary, key):    
    return dictionary.get(key)

In a template, extract the form required something like this:在模板中,提取所需的表单,如下所示:

{% load 'custom_tags' %}
{% for question in page_question_set %}
     {{question}}
     {{ forms|get_item:question }}
{% endfor %}

I hope you find this useful.希望这个对你有帮助。 I don't think its a bad workaround, but I remain worried that I'm working around something the framework can actually take care of.我不认为这是一个糟糕的解决方法,但我仍然担心我正在解决框架实际上可以处理的问题。

Just remove the <,>(comma) at the end of each defined field and this should work只需删除每个已定义字段末尾的 <,>(逗号),这应该可以

forms.py forms.py

from django import forms

    blah_choices = [("1", "first"), ("2", "second")]
    blah_choices2 = [("3", "third"), ("4", "four")]

    class TestRadioQuestions(forms.Form):
        email = forms.EmailField()
        q1 = forms.ChoiceField(label="Blah blah blah form question",choices=(blah_choices),widget=forms.RadioSelect())
        q2 = forms.ChoiceField(label="blah blah some form question",choices=(blah_choices2),widget=forms.RadioSelect())

views.py视图.py

def testRadioQuestions(request):
    if request.method == 'POST':
        form = TestRadioQuestions(request.POST)

        if form.is_valid():
            return HttpResponseRedirect('../../url_name')


    else:
        form = TestRadioQuestions()

    return render(request, 'template_url', {'form' : form })    

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM