Django:在具有排除字段的 ModelForm 中验证 unique_together 约束
Django: validating unique_together constraints in a ModelForm with excluded fields
我有一个表格:
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 对这些约束的验证,而不是必须自己编写?
我想在表单的隐藏字段中传递用户(而不是排除它),但这似乎不安全(即可以更改用户值)?
在 form_valid
中设置 form.instance.user
为时已晚,因为届时表单已经过验证。由于这是您的 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)
这对我有用,请检查。请求 feedback/suggestions。
(基于 this 所以 post。)
1) 修改POST请求发送excluded_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
我有一个表格:
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 对这些约束的验证,而不是必须自己编写?
我想在表单的隐藏字段中传递用户(而不是排除它),但这似乎不安全(即可以更改用户值)?
在 form_valid
中设置 form.instance.user
为时已晚,因为届时表单已经过验证。由于这是您的 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)
这对我有用,请检查。请求 feedback/suggestions。 (基于 this 所以 post。)
1) 修改POST请求发送excluded_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