2010-09-01 32 views
5

Un ejemplo es mejor que mil palabras:Problema Django QuerySet .defer() - ¿error o característica?

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 

él trabaja como esto a propósito?

Subestación: ¿hay alguna manera simple de obtener una instancia de modelo regular de la diferida?

EDIT:

Parece que ContentTypes marco está parcheado apropiada: http://code.djangoproject.com/changeset/10523

, así que diría que el modelo ._____ eq _____() operador no debe verse como this:

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

pero más como este:

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é.

+0

Respuesta actualizada ... – FallenAngel

+0

Por si acaso alguien más se tropieza con esto, aparentemente esto era de hecho un error de Django que debería ser [reparado en 1.7] (https://code.djangoproject.com/ticket/24772) –

Respuesta

2

consultas diferidos 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. 
    """ 

Se trata básicamente de un proxy, como se puede ver en el orden de resolución de métodos:

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

Sí, sé que es una clase diferente, pero la instancia de modelo __eq__ ya está sobrecargada ([aquí] (http://code.djangoproject.com/browser/django/tags/releases/1.2.1/django/ db/models/base.py # L355)), por lo que cabría esperar que dos instancias que apuntan al mismo objeto de base de datos sean iguales, independientemente de si uno de ellos se aplaza o no, diferir es solo una cuestión técnica. –

+0

Mientras tanto, encontré este ticket http: // code.djangoproject.com/changeset/10523 que resolvió un problema con los tipos de contenido que son diferentes para los modelos diferidos y no diferidos, esto confirma mi punto de vista. –

0

Su 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 preguntas sin correo electrónico ... Por lo tanto, tiene dos conjuntos de consultas, uno con un campo menor.

Actualización:

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' 

Defer Documentation explica esto como:

Un conjunto de consultas que tiene campos diferidos se sigue regresar 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).

EDIT 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 se compara dos objetos, no se utiliza método ____eq____ clase relacionada.

+0

Pero después de indexar debería recibir diferentes 'vistas' en el mismo objeto –

+0

El MYYN lo explica más específico y mi respuesta es tan mal interpretada ... Así que agrego un ejemplo ... – FallenAngel

Cuestiones relacionadas