我有一个模型,其中电子邮件字段是唯一的。我想它会让每个电子邮件都小写,因为它在User实例上有normalize_email((方法。然而,它规范化域部分只是为了Company@gmail.com如果company@gmail.com存在。因此,我决定在序列化程序中创建validate_email((,以便始终返回小写电子邮件。这是一个字段验证,文档中对此进行了描述。
def validate_email(self, value):
return value.lower()
但是,看起来这个方法是在序列化程序检查数据库中是否存在该值之后返回该值的。这里有一个例子:
如果我尝试使用创建用户user@gmail.com并且它已经存在;用户已经存在";这是意料之中的。但是,如果我和User@gmail.com它将首先运行SQL请求并检查User@gmail.com!=user@gmail.com之后,它将尝试使用user@gmail.com因为它是从validate_email((返回的,IntegrityError将被引发,因为它变成user@gmail.com已经在DB中了!
我可以做一些类似的事情
def validate_email(self, value):
norm_email = value.lower()
if User.objects.filter(email=norm_email).exists():
raise serializers.ValidationError("Not unique email")
return norm_email
但这是对DB的另一个请求,我不想要。
所以我的问题是什么方法运行SQL请求来检查数据库中的唯一性?这样我就可以覆盖它并传递已经降低了的值?
使用iexact
--(django-doc(查找
User.objects.filter(email__iexact=norm_email).exists()
更新
DRF在引擎盖下查询以检查唯一约束,因为在模型字段中我们设置了unique=True
。为了避免这种情况,我们需要在序列化程序中明确定义email
字段,绕过唯一检查验证
class UserSerializer(serializers.ModelSerializer):
email = serializers.EmailField()
def validate_email(self, value):
lower_email = value.lower()
if User.objects.filter(email__iexact=lower_email).exists():
raise serializers.ValidationError("Duplicate")
return lower_email
class Meta:
model = User
fields = ('email',)
Django shell输出
In [17]: print(len(connection.queries))
7
In [18]: class UserSerializer(serializers.ModelSerializer):
...: email = serializers.EmailField()
...:
...: def validate_email(self, value):
...: lower_email = value.lower()
...: if User.objects.filter(email__iexact=lower_email).exists():
...: raise serializers.ValidationError("Duplicate")
...: return lower_email
...:
...: class Meta:
...: model = User
...: fields = ('email',)
...:
In [19]: print(len(connection.queries))
7
In [20]: s = UserSerializer(data={'email': 'Foo@gmail.com'})
In [21]: print(len(connection.queries))
7
In [22]: try:
...: s.is_valid(True)
...: except serializers.ValidationError:
...: print("raised validation error")
...:
raised validation error
In [23]: print(len(connection.queries))
8