Django QuerySet .defer () проблема - ошибка или функция? - PullRequest
6 голосов
/ 01 сентября 2010

Пример лучше тысячи слов:

   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

Это нарочно так работает?

Подзапрос: есть ли простой способ получить обычный экземпляр модели из отложенного?

EDIT:

Похоже, что фреймворк Contenttypes исправлен соответствующим образом: http://code.djangoproject.com/changeset/10523

поэтому я бы сказал, что оператор Model ._____ eq _____ () не должен выглядеть так: this :

    def __eq__(self, other):
        return isinstance(other, self.__class__) and self._get_pk_val() == other._get_pk_val()

но больше похоже на это:

    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_model реализует кеш.

Ответы [ 2 ]

2 голосов
/ 01 сентября 2010

Отложенные запросы возвращают другой класс, предоставленный 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.
    """

Это в основном прокси, как вы можете видеть из порядка разрешения методов:

>>> 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'>)
0 голосов
/ 01 сентября 2010

Это нормальное поведение, поскольку User.objects.filter (id = 19) [0] будет возвращать набор запросов со всеми связанными полями модели, но User.objects.filter (id = 19) .defer ('email') [0] принесет набор запросов без электронной почты ... Итак, у вас есть два набора запросов, один с меньшим количеством полей.

Обновление:

Тест ...

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'

Отложенная документация объясняет это следующим образом:

Набор запросов, имеющий отложенные поля, по-прежнему будет возвращать экземпляры модели.Каждое отложенное поле будет извлечено из базы данных, если вы получите доступ к этому полю (по одному, а не ко всем отложенным полям одновременно).

РЕДАКТИРОВАТЬ 2:

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()

== - это простое сравнение, в котором сравниваются два объекта, в нем не используется метод связанного класса ____eq____.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...