我有一张表格:
class CourseStudentForm(forms.ModelForm):
class Meta:
model = CourseStudent
exclude = ['user']
对于具有一些复杂要求的模型:
class CourseStudent(models.Model):
user = models.ForeignKey(settings.AUTH_USER_MODEL)
semester = models.ForeignKey(Semester)
block = models.ForeignKey(Block)
course = models.ForeignKey(Course)
grade = models.PositiveIntegerField()
class Meta:
unique_together = (
('semester', 'block', 'user'),
('user','course','grade'),
)
我希望新对象使用CourseStudent.user的当前登录用户:
class CourseStudentCreate(CreateView):
model = CourseStudent
form_class = CourseStudentForm
success_url = reverse_lazy('quests:quests')
def form_valid(self, form):
form.instance.user = self.request.user
return super(CourseStudentCreate, self).form_valid(form)
然而,这是有效的,因为用户不是表单的一部分,它错过了Django否则会对unique_together约束进行的验证。
如何让我的表单和视图在这些约束上使用Django的验证,而不是自己编写?
我虽然将用户传递给表单中的隐藏字段(而不是将其排除),但这看起来不安全(即用户值可能会被更改)?
答案 0 :(得分:4)
在form.instance.user
中设置form_valid
为时已晚,因为此时表单已经过验证。由于这是form_valid
方法所做的唯一自定义操作,因此您应将其删除。
您可以覆盖get_form_kwargs
,并传入已设置用户的CourseStudent
实例:
class CourseStudentCreate(CreateView):
model = CourseStudent
form_class = CourseStudentForm
success_url = reverse_lazy('quests:quests')
def get_form_kwargs(self):
kwargs = super(CreateView, self).get_form_kwargs()
kwargs['instance'] = CourseStudent(user=self.request.user)
return kwargs
这还不足以使其工作,因为表单验证会跳过引用user
字段的唯一约束条件。解决方案是覆盖模型表格的full_clean()
方法,并在模型上显式调用validate_unique()
。覆盖clean
方法(正如您通常所做的那样)不起作用,因为该实例在此时尚未填充表单中的值。
class CourseStudentForm(forms.ModelForm):
class Meta:
model = CourseStudent
exclude = ['user']
def full_clean(self):
super(CourseStudentForm, self).full_clean()
try:
self.instance.validate_unique()
except forms.ValidationError as e:
self._update_errors(e)
答案 1 :(得分:0)
这对我有用,请检查。请求反馈/建议。 (基于this这样的帖子。)
1)修改POST请求以发送exclude_field。
def post(self, request, *args, **kwargs):
obj = get_object_or_404(Model, id=id)
request.POST = request.POST.copy()
request.POST['excluded_field'] = obj
return super(Model, self).post(request, *args, **kwargs)
2)使用所需的验证更新表单的清理方法
def clean(self):
cleaned_data = self.cleaned_data
product = cleaned_data.get('included_field')
component = self.data['excluded_field']
if Model.objects.filter(included_field=included_field, excluded_field=excluded_field).count() > 0:
del cleaned_data['included_field']
self.add_error('included_field', 'Combination already exists.')
return cleaned_data