python - orm django queries
Problema de Django QuerySet.defer()-¿error o característica? (2)
Es el comportamiento normal, porque User.objects.filter (id = 19) [0] devolverá un conjunto de consulta con todos los campos relacionados del modelo, pero User.objects.filter (id = 19) .defer (''email'' ) [0] traerá un conjunto de consulta sin correo electrónico ... Por lo tanto, tiene dos conjuntos de consulta, uno con un campo menor.
Actualizar:
Prueba...
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''
La documentación de aplazamiento explica esto como:
Un conjunto de consulta que tiene campos diferidos todavía devolverá instancias de modelo. Cada campo diferido se recuperará de la base de datos si accede a ese campo (uno a la vez, no todos los campos diferidos a la vez).
EDICION 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()
== es una comparación simple y compara dos objetos, no está usando el método de la clase relacionada ____eq____.
Un ejemplo es mejor que mil palabras:
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
Funciona así a propósito?
Subjetivo: ¿hay alguna manera simple de obtener una instancia de modelo regular de la diferida?
EDITAR:
Parece que el framework contenttypes está parcheado apropiadamente: http://code.djangoproject.com/changeset/10523
entonces yo diría que el operador Modelo ._____ eq _____ () no debería verse así:
def __eq__(self, other):
return isinstance(other, self.__class__) and self._get_pk_val() == other._get_pk_val()
pero más como esto:
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()
Esto, por supuesto, causa dos hits DB por primera vez, pero afortunadamente get_for_model parece implementar el caché.
Las consultas diferidas devuelven una clase diferente, proporcionada por el 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.
"""
Básicamente es un proxy, como se puede ver en el orden de resolución del método:
>>> 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''>)