簡體   English   中英

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

[英]drf how to avoid objects.all() in UniqueValidator

我有一個代表用戶的序列化程序類。

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只是被定義了。

(...)這可能會起作用,問題是,這將觸發一個sql查詢將選擇所有用戶。

這是不正確的 Django將過濾查詢集,但過濾本身發生在數據庫端。

不會查詢User表中的所有項目。 評估查詢集。 它充當“根查詢集”,將根據該查詢構造查詢。

我們可以在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() 

).exclude(pk= ) 如您所見,它將生成一個查詢User.objects.filter(uid= ).exclude(pk= )

因此,它會檢查是否有User在使用相同的是數據庫對象uid為您設置一個,並排除您正在更新的一個(假設適用)。 查詢將如下所示:

SELECT user.*
FROM user
WHERE uid = 
  AND id <> 

因此,它將在數據庫級別進行過濾,從而提高效率。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM