我正在尝试使用m2m中间表保存表单。我实现multichoicefield表单时出现此错误:
Cannot assign "[Option: Option1]": "StateOption.partoption" must be a "Option" instance.
但是,如果我发表评论表单将保存,但一次只能保存1个选项。我希望能够有一个清单,并让用户选择多个选项。
我使用的是:Django m2m form save " through " table 作为参考,但必须承认我不太了解它,尤其是for循环部分。
我的问题是:如何保存表单?我理解为什么我得到实例错误,但我不知道如何解决它。此外,下面的for循环可能是错误的。任何有关如何修复for循环的建议都将受到赞赏。这似乎可以让我保存多项选择。
models.py
class Disease(models.Model):
disease = models.CharField(max_length=300, verbose_name="disease")
class Option(models.Model):
relevantdisease = models.ForeignKey(Disease, verbose_name="disease")
option = models.CharField(max_length=300, verbose_name="treatment Options")
class State(models.Model):
state = models.CharField(max_length=300, verbose_name='state')
relevantdisease = models.ForeignKey(Disease, verbose_name="disease")
relevantoption = models.ManyToManyField(Option, through='StateOption')
class StateOption(models.Model):
parttstate = models.ForeignKey(State)
partoption = models.ForeignKey(Option)
relevantoutcome = models.ManyToManyField(Outcome, through='StateOptionOutcome')
forms.py
class StateOptionForm(forms.ModelForm):
partoption = forms.ModelMultipleChoiceField(queryset=Option.objects.all(), required=True, widget=forms.CheckboxSelectMultiple)
#if I comment the line above out, then my selection will save but only 1 at at time. There are multiple options for a 'state' and I'd like to capture it all at once
class Meta:
model = StateOption
exclude = ['parttstate', 'relevantoutcome']
views.py
def diseasestateoption(request, disease_id, state_id):
state = get_object_or_404(State, pk=state_id)
disease = get_object_or_404(Disease, pk=disease_id)
if request.method == "POST":
form = StateOptionForm(request.POST, request.FILES)
if form.is_valid():
profile = form.save(commit=False)
profile.user = request.user
profile.save()
for state in request.POST.getlist('relevantoption'): #don't really understand this part and I'm probably not implementing this right
option = StateOption.objects.create(partstate=state, partoption=profile)
return HttpResponseRedirect(reverse('state', kwargs={'disease_id':disease_id}))
else:
form = StateOptionForm()
模板
<form class="option_form" action="{% url "diseasestateoption" disease.pk state.pk %}" method="post">{% csrf_token %}
{{ disease }}
{{ state }}
{{option}}
我之前在这里发过一个类似的问题,但没有得到答案。我是django和stackoverflow的新手,所以任何帮助都会受到赞赏。
修改
我能够在没有中间表和使用save_m2m()的情况下实现它,但是,我需要一个中间表用于我的程序的下一部分...如果我可以先解决这一部分。
答案 0 :(得分:1)
您的错误:
Cannot assign "[Option: Option1]": "StateOption.partoption" must be a "Option" instance.
告诉您,您正在尝试将某些内容保存到partoption
不是Option
实例的字段中。具体来说,这发生在您在此行中的for循环中:
option = StateOption.objects.create(partstate=state, partoption=profile)
原因是profile
不是Option
。它是StateOption
个实例。
for循环:
for state in request.POST.getlist('relevantoption'):
表示您在模板中指定了多个“relatedoption”字段。你也可以发布模板代码吗?
这里有几件事情。一,模特。让我们将字段名称更改为选项,以便更清楚地了解它们的真实含义:
class State(models.Model):
state = models.CharField(max_length=300, verbose_name='state')
relevantdisease = models.ForeignKey(Disease, verbose_name="disease")
# Note: I've renamed this field to 'options' for clarity
options = models.ManyToManyField(Option, through='StateOption')
现在,您希望表单使用复选框指定State实例的options
。我们将基于State模型创建一个专用表单来执行此操作:
class UpdateStateWithOptionsForm(forms.ModelForm):
class Meta:
model = State
exclude = ['state', 'relevantdisease']
def __init__(self, *args, **kwargs):
# call the parent init
super(UpdateStateWithOptionsForm, self).__init__(*args, **kwargs)
# change the widget to use checkboxes
self.fields['options']forms.ModelMultipleChoiceField(
queryset=Option.objects.all(),
required=True,
widget=forms.CheckboxSelectMultiple)
现在我们可以编写视图代码来查找用户选择的选项ID:
# Note: may not need disease_id if it is supposed to be the state's disease?
def diseasestateoption(request, state_id):
state = get_object_or_404(State, pk=state_id)
if request.method == "POST":
form = UpdateStateWithOptionsForm(request.POST, instance=state)
if form.is_valid():
for option_id in request.POST.getlist('options'):
state_option = StateOption.objects.create(partstate=state, partoption_id=int(option_id)
return HttpResponseRedirect(reverse('state', kwargs={'disease_id':state.disease_id}))
else:
form = UpdateStateWithOptionsForm(instance=state)
return render_to_response(
'some_template.html',
{
'form': form,
'state': state,
},
context_instance=RequestContext(request)
)
好的,那怎么办?查看呈现的模板HTML可能会有所帮助。表单的样板模板代码:
<form action="{% url 'diseasestateoption' state.pk %}" method="post">
{% csrf_token %}
{% if form.non_field_errors %}
{{ form.non_field_errors }}
{% endif %}
{% for field in form %}
{{ field.label }}:
{{ field }}
{% if field.errors %}
{{ field.errors|striptags }}
{% endif %}
{% endfor %}
<button type="submit">Save</button>
</form>
将其放入模板中,然后访问该页面并查看源代码。在HTML表单中,您将注意到一组名称为options
的输入,每个输入的值对应于Option实例的主键(来自我们在ModelForm中指定的查询集)。视图中的for循环只是抓取该列表并使用Option pk为State实例创建一个带有该选项的关联StateOption。
注意:这是未经测试的代码,可能会有错误在那里爬行!
希望这会有所帮助并祝你好运!