Django QuerySet .defer()问题 - bug或功能? [英] Django QuerySet .defer() problem - bug or feature?
问题描述
一个例子比一千个词更好:
在[3]中:User.objects.filter(id = 19 )[0] == User.objects.filter(id = 19)[0]
pre>
Out [3]:True
在[4]中:User.objects.filter(id = 19)[0] == User.objects.filter(id = 19).defer('email')[0]
Out [4]:False
它是否按目的工作?
Subquestion:有什么简单的方法来获得正常的模型实例从延期的一个?
编辑:
看起来像contenttypes框架是适当修补的:
http://code.djangoproject.com/changeset/10523
所以我会说,模型._____ eq _____()运算符不应该像此:
def __eq __(self ,其他):
return isinstance(other,self .__ class__)和self._get_pk_val()== other._get_pk_val()
,但更像这样:
def __eq __(self,other):
返回ContentType.objects.get_for_model(self)是ContentType.objects.get_for_model(other)和self._get_pk_val()== other._get_pk_val()
这当然是引起两个DB命中,但幸运的是get_for_model似乎实现缓存。
解决方案延迟查询返回一个不同的类,由
deferred_class_factory
提供:#在db / models / query_utils.py
def deferred_class_factory(model,attrs):
返回一个类对象,模型与指定的attrs
替换为DeferredAttribute对象。 pk_value将
延迟属性与模型的特定实例相关联。
它基本上是一个代理,你可以从方法解析中看到订单:
>>> x = User.objects.filter(id = 1).defer(email )[0]
>>> x .__ class __.__ mro__
(< class'django.contrib.auth.models.User_Deferred_email'>,\
< class 'django.contrib.auth.models.User'>,\
< class'django.db.models.base.Model'>,< type'object'>)
An example is better than a thousand words:
In [3]: User.objects.filter(id=19)[0] == User.objects.filter(id=19)[0] Out[3]: True In [4]: User.objects.filter(id=19)[0] == User.objects.filter(id=19).defer('email')[0] Out[4]: False
Does it work like this on purpose ?
Subquestion: is there any simple way to get a regular model instance from the deferred one ?
EDIT:
It looks like contenttypes framework is patched appropriately: http://code.djangoproject.com/changeset/10523
so I would say that the Model._____eq_____() operator shouldn't look like this:
def __eq__(self, other): return isinstance(other, self.__class__) and self._get_pk_val() == other._get_pk_val()
but more like this:
def __eq__(self, other): return ContentType.objects.get_for_model(self) is ContentType.objects.get_for_model(other) and self._get_pk_val() == other._get_pk_val()
This of course causes two DB hits for the first time, but fortunately get_for_model seems to implement cache.
解决方案Deferred queries return a different class, provided by the
deferred_class_factory
:# in db/models/query_utils.py def deferred_class_factory(model, attrs): """ Returns a class object that is a copy of "model" with the specified "attrs" being replaced with DeferredAttribute objects. The "pk_value" ties the deferred attributes to a particular instance of the model. """
It is basically a proxy, as you can see from the method resolution order:
>>> x = User.objects.filter(id=1).defer("email")[0] >>> x.__class__.__mro__ (<class 'django.contrib.auth.models.User_Deferred_email'>, \ <class 'django.contrib.auth.models.User'>, \ <class 'django.db.models.base.Model'>, <type 'object'>)
这篇关于Django QuerySet .defer()问题 - bug或功能?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!