验证唯一的电子邮件 django rest 框架序列化程序
Validate Unique email django rest framework serializer
我有一个模型,其中电子邮件字段是唯一的。我认为它会使每个电子邮件小写,因为它在 User 实例上有 normalize_email() 方法。但是,它仅规范化域部分,因此如果 company@gmail.com 存在,则 Company@gmail.com 被认为是唯一的。所以我决定在我的序列化程序中创建 validate_email() 以始终 return 小写电子邮件。这是一个字段验证,在文档中有描述。
def validate_email(self, value):
return value.lower()
但是,看起来这个方法 return 是序列化程序检查数据库中是否存在该值之后的值。这是一个例子:
如果我尝试使用 user@gmail.com 创建一个用户并且它已经存在,它将 return “用户已经存在”,这是预期的。但是,如果我 运行 与 User@gmail.com 它将首先 运行 一个 SQL 请求并检查 User@gmail.com != user@gmail.com之后它将尝试使用 user@gmail.com 创建一个新实例,因为它是 returned from validate_email() 并且将引发 IntegrityError 因为它变成了 user@gmail.com 已经在数据库中了!
我可以做类似的事情
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 请求来检查数据库中的唯一性?这样我就可以覆盖它并传递已经小写的值?
User.objects.filter(<b>email__iexact=norm_email</b>).exists()
更新
DRF 在幕后查询以检查 唯一约束 因为在模型字段中我们设置了 unique=True
。为了避免这种情况,我们需要在序列化器中显式定义email
字段,旁路 唯一校验验证
class UserSerializer(serializers.ModelSerializer):
<b>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</b>
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
我有一个模型,其中电子邮件字段是唯一的。我认为它会使每个电子邮件小写,因为它在 User 实例上有 normalize_email() 方法。但是,它仅规范化域部分,因此如果 company@gmail.com 存在,则 Company@gmail.com 被认为是唯一的。所以我决定在我的序列化程序中创建 validate_email() 以始终 return 小写电子邮件。这是一个字段验证,在文档中有描述。
def validate_email(self, value):
return value.lower()
但是,看起来这个方法 return 是序列化程序检查数据库中是否存在该值之后的值。这是一个例子:
如果我尝试使用 user@gmail.com 创建一个用户并且它已经存在,它将 return “用户已经存在”,这是预期的。但是,如果我 运行 与 User@gmail.com 它将首先 运行 一个 SQL 请求并检查 User@gmail.com != user@gmail.com之后它将尝试使用 user@gmail.com 创建一个新实例,因为它是 returned from validate_email() 并且将引发 IntegrityError 因为它变成了 user@gmail.com 已经在数据库中了!
我可以做类似的事情
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 请求来检查数据库中的唯一性?这样我就可以覆盖它并传递已经小写的值?
User.objects.filter(<b>email__iexact=norm_email</b>).exists()
更新
DRF 在幕后查询以检查 唯一约束 因为在模型字段中我们设置了 unique=True
。为了避免这种情况,我们需要在序列化器中显式定义email
字段,旁路 唯一校验验证
class UserSerializer(serializers.ModelSerializer):
<b>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</b>
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