我是Django的新手,在google / SO上搜索后找不到类似的问题。
我有一个名为Questions的模型,它有多个(2-4)选项,定义如下:
class Question(models.Model):
name = models.CharField(max_length=128)
class Choice(models.Model):
name = models.CharField(max_length=256)
is_correct = models.BooleanField(default=False)
question = models.ForeignKey(Question, on_delete=models.CASCADE)
在多个选择中,只有一个是正确的。
我想做的事:在一个页面中,用户可以提交一个问题和多个选项,这是一个UI草稿:
我的第一个问题:我已经定义了ModelForm但不知道如何添加"选择"字段到QuestionForm:
class QuestionForm(ModelForm):
name = forms.CharField(max_length=128)
description = forms.CharField(max_length=256)
class Meta:
model = Question
fields = ['name', 'description']
class ChoiceForm(ModelForm):
name = forms.CharField(max_length=256)
is_correct = forms.BooleanField()
class Meta:
model = Choice
fields = ['name', 'is_correct']
除了手动编写之外,是否可以使用ModelForm渲染上面的HTML页面?
我的第二个问题:如果使用点击次数"提交"按钮,我使用AJAX将json数据发送到后端服务器,这里是表单数据的一个例子:
name:question1
choices[][name]:choice1
choices[][is_correct]:1
choices[][name]:choice2
choices[][is_correct]:0
这是我处理请求的代码:
form = QuestionForm(request.POST)
if form.is_valid():
question = form.save()
如何解析请求中的选择? 我如何从POST请求中解析多个选择部分的数据?
同样,我是Django的新手,我们非常感谢任何答案/建议。
答案 0 :(得分:1)
要为具有OneToMany关系的模型创建表单,我建议您使用Django的内联表单集:https://docs.djangoproject.com/en/1.8/topics/forms/modelforms/#inline-formsets
这是为相关模型创建表单的一种非常简单而优雅的方式。
要解析选项,用户输入的内容可以覆盖表单的clean
方法。在此,通常检查并准备用户内容以将其存储到数据库中。 https://docs.djangoproject.com/en/1.8/ref/forms/validation/#form-field-default-cleaning
所以清洁可能如下所示:
class QuestionForm(ModelForm):
...
def clean(self):
cleaned_data = super(QuestionForm, self).clean()
if cleaned_data['choice_name'].startswith('Something'):
raise forms.ValidationError(
"Choice names cannot start with 'Something'!"
)
答案 1 :(得分:1)
您的模型似乎是正确的,为了能够在模板中添加多个选项,您需要formset。此外,您可以将formset和表单放在模板中的相同html表单中,并单独验证它们。每个人只关心与他们相关的POST数据。类似的东西:
<强> template.html 强>
<form method="post" action="">
{% csrf_token %}
{{ choices_formset.management_form }} <!-- used by django to manage formsets -->
{{ question_form.as_p }}
{% for form in choices_formset %}
{{ form.as_p }}
{% endfor %}
<button type='submit'>Submit</button>
</form>
<强> views.py 强>
from django.db import IntegrityError, transaction
from django.shortcuts import redirect
from django.forms.formsets import formset_factory
from django.core.urlresolvers import reverse
def new_question(request):
ChoicesFormset = formset_factory(ChoicesForm)
if request.method == 'POST':
question_form = QuestionForm(request.POST)
choices_formset = ChoicesFormset(request.POST)
if question_form.is_valid():
question = Question(**question_form.cleaned_data)
if choices_formset.is_valid():
question.save()
new_choice_list = list()
append_choice = new_choice_list.append
for form in choices_formset:
form.cleaned_data.update({'question': question})
append_choice(Choice(**form.cleaned_data))
try:
with transaction.atomic():
Choice.objects.bulk_create(new_choice_list)
except IntegrityError as e:
raise IntegrityError
return redirect(reverse('question-detail-view', kwargs={'id': question.id}))
def question_detail(request, id):
question_list = Question.objects.get(id=id)
return render(request, 'question_detail.html', {'question_list': question_list})
<强> urls.py 强>
url(r'^question/$', new_question, name='new-question-view'),
url(r'^question/(?P<id>\d+)/$', question_detail, name='question-detail-view'),