我有一个代表用户的序列化器类。
class UserSerializer(BaseSerializer):
uid = serializers.IntegerField(required=True)
class Meta:
model = User
fields = "all"
def validate(self, data):
super().validate(data)
validate_user_data(data=self.initial_data, user=self.instance)
return data
用户在uid上应该是唯一的,因此在获得发布请求时,我真正想要的是将uid字段更改为:
uid = serializers.IntegerField(required=True, validators=[validators.UniqueValidator(queryset=User.objects.all())])
这可能会起作用,问题是,这将触发一个SQL查询,该查询将选择所有用户。
因为可能有成千上万个,所以这可能会对系统产生很大的影响。
我真正想要的是将查询更改为User.objects.get(uid=uid)
,这将不会从数据库中选择每个用户。
但是,由于我在uid的序列化程序定义中,因此不能使用uid = uid,因为只是在定义uid。
答案 0 :(得分:3)
(…),这可能会起作用,问题是,这将触发sql查询,并会选择所有用户。
这是不正确。 Django将过滤查询集,但过滤本身发生在数据库端。
这将不查询User
表中的所有项目。查询集未评估 。它充当构建查询所依据的“根查询集”。
我们可以查找source code on GitHub:
class UniqueValidator(object): # ... def __call__(self, value): queryset = self.queryset queryset = self.filter_queryset(value, queryset) queryset = self.exclude_current_instance(queryset) if qs_exists(queryset): raise ValidationError(self.message, code='unique')
此处查询集已被过滤。这种过滤不是在Python / Django级别完成的,而是构造一个过滤后的变体。确实,如果我们查看filter_queryset
函数,我们将看到:
def filter_queryset(self, value, queryset): """ Filter the queryset to all instances matching the given attribute. """ filter_kwargs = {'%s__%s' % (self.field_name, self.lookup): value} return qs_filter(queryset, **filter_kwargs)
以qs_filter
开头:
def qs_filter(queryset, **kwargs): try: return queryset.filter(**kwargs) except (TypeError, ValueError, DataError): return queryset.none()
如您所见,它将因此生成查询User.objects.filter(uid=the_uid).exclude(pk=item_that_is_updated)
因此它将检查该数据库中是否存在一个User
对象,该对象与您设置的对象相同uid
,并排除您要更新的对象(如果适用)。查询如下所示:
SELECT user.*
FROM user
WHERE uid = the_uid
AND id <> item_that_is_updated
它将因此在数据库级别进行过滤,从而提高效率。