Django QuerySet .defer()问题 - bug或功能? [英] Django QuerySet .defer() problem - bug or feature?

查看:85
本文介绍了Django QuerySet .defer()问题 - bug或功能?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

一个例子比一千个词更好:

 在[3]中:User.objects.filter(id = 19 )[0] == User.objects.filter(id = 19)[0] 
Out [3]:True

在[4]中:User.objects.filter(id = 19)[0] == User.objects.filter(id = 19).defer('email')[0]
Out [4]:False
pre>

它是否按目的工作?



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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆