[英]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
表中的所有項目。 不評估查詢集。 它充當“根查詢集”,將根據該查詢構造查詢。
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.