2010-09-01 2 views
5

Ví dụ tốt hơn một nghìn từ:Vấn đề Django QuerySet .defer() - lỗi hoặc tính năng?

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 

Có hoạt động như mục đích này không?

Câu hỏi con: có cách nào đơn giản để lấy mẫu phiên bản thông thường từ phiên bản trả chậm không?

EDIT:

Dường như contenttypes khuôn khổ được vá một cách thích hợp: http://code.djangoproject.com/changeset/10523

vì vậy tôi sẽ nói rằng Model ._____ eq _____() điều hành không nên trông giống như this:

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

nhưng giống như sau:

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

Điều này tất nhiên gây ra hai lần truy cập DB lần đầu tiên, nhưng may mắn thay get_for_model dường như triển khai bộ nhớ cache.

+0

Trả lời cập nhật ... – FallenAngel

+0

Chỉ trong trường hợp bất kỳ ai khác bị vấp phải bởi điều này, rõ ràng đây thực ra là lỗi Django cần được [cố định trong 1.7] (https://code.djangoproject.com/ticket/24772) –

Trả lời

2

truy vấn thu nhập hoãn lại trả về một lớp học khác nhau, được cung cấp bởi các 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. 
    """ 

Nó cơ bản là một proxy, như bạn có thể nhìn thấy từ để giải quyết phương pháp:

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

Vâng, tôi biết rằng đó là một lớp khác, nhưng toán tử mẫu __eq__ đã bị quá tải ([ở đây] (http://code.djangoproject.com/browser/django/tags/releases/1.2.1/django/ db/models/base.py # L355)), vì vậy tôi hy vọng rằng hai cá thể trỏ đến cùng một đối tượng DB sẽ bằng nhau cho dù một trong số chúng bị trì hoãn hay không - trì hoãn chỉ là một vấn đề kỹ thuật. –

+0

Trong khi đó, tôi tìm thấy mã http: // mã này.djangoproject.com/changeset/10523 mà cố định một vấn đề với contentypes là khác nhau cho các mô hình trì hoãn và không hoãn lại, điều này khẳng định quan điểm của tôi. –

0

của các hành vi bình thường Bởi vì User.objects.filter (id = 19) [0] sẽ trả về một queryset với tất cả các trường liên quan của mô hình, nhưng User.objects.filter (id = 19) .defer ('email') [0] sẽ mang lại một queryset mà không có email ... Vì vậy, bạn có hai queryset, một với một trường ít hơn.

Cập nhật:

thử nghiệm ...

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 giải thích điều này như sau:

Một queryset có các trường chậm vẫn sẽ trở lại trường hợp mô hình. Mỗi trường được hoãn lại sẽ được truy xuất từ ​​cơ sở dữ liệu nếu bạn truy cập vào trường đó (từng trường một, không phải tất cả các trường bị trì hoãn cùng một lúc).

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

== là một so sánh đơn giản và nó so sánh hai đối tượng, nó không được sử dụng phương pháp lớp ____eq____ liên quan.

+0

Nhưng sau khi lập chỉ mục, tôi sẽ nhận được các 'khung nhìn khác nhau 'trên cùng một đối tượng –

+0

MYYN giải thích nó nhiều hơn và câu trả lời của tôi rất dễ hiểu ... Vì vậy, tôi thêm một số ví dụ ... – FallenAngel