Django QuerySet .defer() problem - bug or feature?
一个例子胜过千言万语:
1 2 3 4 5 | 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 |
这是故意的吗?
子问题:从延迟的模型实例中获取常规模型实例有什么简单的方法吗?
编辑:
看起来ContentTypes框架已适当修补:http://code.djangoproject.com/changeset/10523
所以我要说的是,这个模型。uuuuuuuuuuuuuuuuuuuuuueq_uuuuuuuuu()操作符不应该像这样:
1 2 | def __eq__(self, other): return isinstance(other, self.__class__) and self._get_pk_val() == other._get_pk_val() |
但更像这样:
1 2 | 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() |
当然,这是第一次导致两个数据库命中,但幸运的是,get-for-u模型似乎实现了缓存。
延迟查询返回一个不同的类,由
1 2 3 4 5 6 7 8 | # 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. """ |
它基本上是一个代理,从方法解析顺序可以看出:
1 2 3 4 5 | >>> 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'>) |
它是正常的行为,因为user.objects.filter(id=19)[0]将返回一个包含模型所有相关字段的查询集,但user.objects.filter(id=19)。defer("email")[0]将带来一个不带电子邮件的查询集…所以您有两个查询集,一个具有更少的字段。
更新:
测试…
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | In [30]: a = User.objects.filter(id=1)[0] In [31]: a Out[31]: <User: mustafa> In [27]: b = User.objects.filter(id=1).defer('username')[0] In [28]: b Out[28]: <User_Deferred_username: mustafa> In [32]: a == b Out[32]: False In [33]: type(a) Out[33]: <class 'django.contrib.auth.models.User'> In [34]: type(b) Out[34]: <class 'django.contrib.auth.models.User_Deferred_username'> In [35]: a.username Out[35]: u'mustafa' In [36]: b.username Out[36]: u'mustafa' |
延迟文档解释如下:
A queryset that has deferred fields will still return model instances. Each deferred field will be retrieved from the database if you access that field (one at a time, not all the deferred fields at once).
编辑2:
1 2 3 4 5 6 7 8 9 10 11 12 13 | In [43]: isinstance(b, a.__class__) Out[43]: True In [40]: User.__eq__?? Type: instancemethod Base Class: <type 'instancemethod'> String Form: <unbound method User.__eq__> Namespace: Interactive File: /home/mustafa/python/lib/django/db/models/base.py Definition: User.__eq__(self, other) Source: def __eq__(self, other): return isinstance(other, self.__class__) and self._get_pk_val() == other._get_pk_val() |
==是一个简单的比较,它比较两个对象,它不使用相关的类uuuuuuuuuuuuuuuuuuuuueq_uuuuuuuuuuu方法。