简而言之:我有一个用户输入训练的应用程序。在他们将练习添加到训练中之前,他们必须提交一份“准备就绪”问卷,其中包含5-10个问题,每个问题的评分都为低-高。我不知道如何在视图中列出所有的ReadinessQuestions,并让用户在表单集中提交每个问题的答案
模型:具有问题集的模型(ReadinessQuestion),以及存储问题、评分和它所属的训练的模型(WorkoutReadiness)
表单:我已将一个模型表单制作成一个formset_工厂。当我将“准备就绪问题”表单字段小部件设置为“只读”时,这会使我的表单无效并忽略我的“初始”数据
视图:我想创建一个视图,其中ReadinesQuestion中的5-10个问题位于一个列表中,并带有答案的下拉列表
我的页面现在看起来如何(几乎是我想要的样子):https://imgur.com/a/HD1l3oe
提交表格时出现错误:
Cannot assign "'Sleep'": "WorkoutReadiness.readiness_question" must be a "ReadinessQuestion" instance.
Django文档在这里非常糟糕,widget=forms.TextInput(attrs={'readonly':'readonly'})
甚至不在Django官方网站上。如果我没有将准备就绪问题设置为“只读”,用户可以更改下拉列表(这是不可取的)
#models.py
class Workout(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE, null=True)
date = models.DateField(auto_now_add=True, null=True)
date_created = models.DateTimeField(auto_now_add=True, null=True)
def __str__(self):
return f'{self.date}'
class ReadinessQuestion(models.Model):
name = models.CharField(max_length=40, unique=True)
def __str__(self):
return f'{self.name}'
class WorkoutReadiness(models.Model):
class Rating(models.IntegerChoices):
LOWEST = 1
LOWER = 2
MEDIUM = 3
HIGHER = 4
HIGHEST = 5
workout = models.ForeignKey(Workout, on_delete=models.CASCADE, null=True, blank=True)
readiness_question = models.ForeignKey(ReadinessQuestion, on_delete=models.CASCADE, null=True)
rating = models.IntegerField(choices=Rating.choices)
#forms.py
class WorkoutReadinessForm(forms.ModelForm):
class Meta:
model = WorkoutReadiness
fields = ['readiness_question', 'rating',]
readiness_question = forms.CharField(
widget=forms.TextInput(attrs={'readonly':'readonly'})
)
WRFormSet = forms.formset_factory(WorkoutReadinessForm, extra=0)
#views.py
def create_workoutreadiness(request):
questions = ReadinessQuestion.objects.all()
initial_data = [{'readiness_question':q} for q in questions]
if request.method == 'POST':
formset = WRFormSet(request.POST)
workout = Workout.objects.create(user=request.user)
if formset.is_valid():
for form in formset:
cd = form.cleaned_data
readiness_question = cd.get('readiness_question')
rating = cd.get('rating')
w_readiness = WorkoutReadiness(
workout=workout,
readiness_question=readiness_question,
rating=rating
)
w_readiness.save()
return HttpResponseRedirect(reverse_lazy('routines:workout_exercise_list', kwargs={'pk':workout.id}))
else:
formset = WRFormSet(initial=initial_data)
context = {
'questions':questions,
'formset':formset,
}
return render(request, 'routines/workout_readiness/_form.html', context)
或者:
我可以删除'readonly'属性并更改HTML的呈现方式。但是,这会导致formset.is_valid()为false,因为初始数据字段未填充screenshot of option 2
#forms.py
class WorkoutReadinessForm(forms.ModelForm):
class Meta:
model = WorkoutReadiness
fields = ['readiness_question', 'rating',]
WRFormSet = forms.formset_factory(WorkoutReadinessForm, extra=0)
#views.py
if request.method == 'POST':
formset = WRFormSet(request.POST, initial=initial_data) ###CHANGED THIS####
workout = Workout.objects.create(user=request.user)
print(formset)
if formset.is_valid():
#form.html
<table>
<form action="" method="post">
{% csrf_token %}
{{ formset.management_form }}
{% for form in formset %}
<tr>
<td>{{ form.initial.readiness_question }}</td>
<td>{{ form.rating }}</td>
</tr>
{% endfor %}
<button type="submit" class="btn btn-outline-primary">Submit</button>
</form>
</table>
备选方案2:
理论上,我可以将我的训练主导性模型作为一个更广泛的模型,以5-10个问题作为列,每次训练1行。我知道这违背了整洁的数据建模原则,但我目前在Django看不到解决这一问题的方法。表单集限制了我的项目
我设法解决了这个问题(使用备选方案1)。我不确定这是最好的方式,但它现在起作用了:
WorkoutReadiness
模型中的readiness_question
中添加了blank=True
attrs={'readonly':'readonly'}
的小部件-我认为Django不再支持它,它当然不鼓励它initial_data
填充表单集之外,我还确保在验证后将其单独添加回每个表单中。form.cleaned_data.readiness_question
字段是None
,直到我用initial_data
中的每个字段替换它form.initial.readiness_question
,这意味着用户不能在下拉列表中编辑它相关问题 更多 >
编程相关推荐