drf如何避免UniqueValidator中的objects.all()

时间:2019-09-11 09:02:32

标签: django python-3.x django-models django-rest-framework

我有一个代表用户的序列化器类。

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。

1 个答案:

答案 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

它将因此在数据库级别进行过滤,从而提高效率。