我有两个以一对多关系连接的模型(Workout和ExerciseSet)。我试图使用CreateView来构建一个允许我同时创建锻炼和锻炼集的表单。事情是当我只有一个运动设置字段(在inlineformset_factory中额外= 1)时,它可以工作 - 但是当我想要设置额外的更大数字(如3)时,它只有在设置了所有锻炼时才有效。否则会引发null value in column "repetitions" violates not-null constraint
错误。
我想在inlineformset类中覆盖clean方法来解决这个问题,但是当我调用super.clean()时,它会一直返回None。只是想知道是否有人可以提供帮助。
编辑 - 我建议在模型字段中包含blank = True和null = True。我可以通过将验证代码移动到表单来使其工作,但它似乎有点hackish。有没有更好的方法来进行验证?
models.py
class Workout(models.Model):
profile = models.ForeignKey(
'Profile', on_delete=models.CASCADE, blank=False
)
class ExerciseSet(models.Model):
EXERCISE_TYPE_CHOICES = (
('pushup', 'Push Up'),
('situp', 'Sit-up')
)
workout = models.ForeignKey(
'Workout', on_delete=models.CASCADE, related_name='exercise_sets'
)
repetitions = models.PositiveIntegerField(blank=True, null=True)
exercise_type = models.CharField(max_length=100, choices=EXERCISE_TYPE_CHOICES, blank=True, null=True)
forms.py
class WorkoutForm(ModelForm):
class Meta:
model = Workout
exclude = ()
class ExerciseSetForm(ModelForm):
class Meta:
model = ExerciseSet
exclude = ()
class CustomExerciseSetInlineFormSet(BaseInlineFormSet):
def clean(self):
cleaned_data = super().clean()
print('custom')
print(cleaned_data)
ExerciseSetFormSet = inlineformset_factory(Workout, ExerciseSet, form=ExerciseSetForm,
formset=CustomExerciseSetInlineFormSet, extra=3)
views.py
class WorkoutCreate(CreateView):
model = Workout
fields = ['profile', 'created']
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
template_name = 'pushup/workout_form.html'
context['workout_form'] = WorkoutForm()
context['exercise_set_form'] = ExerciseSetFormSet()
return context
def post(self, request, *args, **kwargs):
workout_form = WorkoutForm(request.POST)
formset = ExerciseSetFormSet(request.POST)
if workout_form.is_valid() and formset.is_valid():
with transaction.atomic():
workouts_saved = 0
workout = workout_form.save()
for exercise_set_form in formset:
exercise_set = exercise_set_form.save(commit=False)
if exercise_set.repetitions == None or exercise_set.exercise_type == None:
continue
exercise_set.workout = workout
exercise_set.save()
workouts_saved += 1
if workouts_saved == 0:
raise ValidationError('No workouts are valid')
return HttpResponseRedirect(reverse_lazy('pushup:workout-detail', kwargs={'pk': workout.pk}))
else:
raise Http404