Django unique_for_date与模型.DateField(可编辑=False)


Django文档中说:

如果任何unique_for_date约束涉及不属于ModelForm(例如,如果其中一个字段列在exclude或具有editable=False(,则Model.validate_unique()将跳过这种特殊的约束。

如上所述,下面的模型为具有editable=FalseDateField设置unique_for_date

根据以上文档的摘录,我希望在验证过程中跳过unique_for_date约束。

然而,下面的测试通过了,显示Model.validate_unique()确实由于unique_for_date(使用Django 3.0(而引发了ValidationError

我错过了什么?

from django.db import models
from django.utils import timezone
from django.core.exceptions import ValidationError
from django.test import TransactionTestCase

class MyModel(models.Model):
name = models.CharField(max_length=10, unique_for_date='date')
date = models.DateField(editable=False)

class MyModelTests(TransactionTestCase):
def test_name_unique_for_date(self):
name = 'bird'
today = timezone.now().date()
MyModel.objects.create(name=name, date=today)
with self.assertRaises(ValidationError) as a:
MyModel(name=name, date=today).validate_unique()
self.assertIn('Name must be unique for Date date.', a.exception.messages)

感谢@WillemVanOnsem在上面的评论:

尽管文件上写着

。。。Model.validate_unique()将跳过该特定约束的验证。

实际上是BaseModelForm.validate_unique()导致跳过约束。

除非我们明确设置exclude=['date'],否则Model.validate_unique()本身不会跳过约束。

如果我们验证一个ModelForm实例,则带有editable=Falsedate字段将自动排除:该字段将从此处的表单中排除,因此,该字段将在此处从验证中排除。

修改示例以说明这一点:

NAME = 'bird'
TODAY = timezone.now().date()
class MyModel(models.Model):
name = models.CharField(max_length=10, unique_for_date='date')
date = models.DateField(editable=False)
class MyModelForm(forms.ModelForm):
class Meta:
model = MyModel
fields = '__all__'
class MyModelTests(TransactionTestCase):
def setUp(self):
MyModel.objects.create(name=NAME, date=TODAY)
def test_model_validate_name_unique_for_date(self):
# constraint is NOT skipped if we validate the Model instance directly
with self.assertRaises(ValidationError) as a:
MyModel(name=NAME, date=TODAY).validate_unique()
self.assertIn('Name must be unique for Date date.', a.exception.messages)
def test_modelform_validate_name_unique_for_date(self):
# constraint IS skipped if we validate a ModelForm instance
my_model_form = MyModelForm(data=dict(name=NAME, date=TODAY))
self.assertTrue(my_model_form.is_valid())