2010-05-30 27 views
7

Công việc select_related có hoạt động đối với các mối quan hệ GenericRelation hay không? Hiện tại, Django đang thực hiện các cuộc gọi sql riêng lẻ cho từng mục trong queryset của tôi, và tôi muốn tránh điều đó bằng cách sử dụng một cái gì đó như select_related.Django: select_related và GenericRelation

class Claim(models.Model): 
    proof = generic.GenericRelation(Proof) 


class Proof(models.Model): 
    content_type = models.ForeignKey(ContentType) 
    object_id = models.PositiveIntegerField() 
    content_object = generic.GenericForeignKey('content_type', 'object_id') 

Tôi đang chọn một loạt Xác nhận quyền sở hữu và tôi muốn các Bằng chứng liên quan được lấy thay vì truy vấn riêng lẻ.

Trả lời

16

Không có cách tích hợp để thực hiện việc này. Nhưng tôi đã đăng một kỹ thuật để mô phỏng select_related về quan hệ chung on my blog. nội dung


Blog tóm tắt:

Chúng ta có thể sử dụng trường _content_object_cache của Django để về cơ bản tạo riêng select_related của chúng tôi đối với các mối quan hệ chung.

generics = {} 
for item in queryset: 
    generics.setdefault(item.content_type_id, set()).add(item.object_id) 

content_types = ContentType.objects.in_bulk(generics.keys()) 

relations = {} 
for ct, fk_list in generics.items(): 
    ct_model = content_types[ct].model_class() 
    relations[ct] = ct_model.objects.in_bulk(list(fk_list)) 

for item in queryset: 
    setattr(item, '_content_object_cache', 
      relations[item.content_type_id][item.object_id]) 

Ở đây chúng ta có được tất cả các loại nội dung khác nhau được sử dụng bởi các mối quan hệ trong queryset, và các thiết lập của các ID đối tượng riêng biệt cho mỗi một, sau đó sử dụng được xây dựng trong phương pháp quản lý in_bulk để có được tất cả các loại nội dung cùng một lúc trong một từ điển sẵn sàng sử dụng tốt được khóa bằng ID. Sau đó, chúng tôi thực hiện một truy vấn cho mỗi loại nội dung, một lần nữa bằng cách sử dụng in_bulk, để nhận tất cả đối tượng thực tế.

Cuối cùng, chúng tôi chỉ cần đặt đối tượng có liên quan vào trường _content_object_cache của mục nguồn. Lý do chúng tôi làm điều này là đây là thuộc tính mà Django sẽ kiểm tra, và cư trú nếu cần thiết, nếu bạn gọi x.content_object trực tiếp. Bằng cách điền sẵn , chúng tôi đảm bảo rằng Django sẽ không bao giờ cần phải gọi từng tra cứu riêng lẻ - trong thực tế những gì chúng tôi đang thực hiện đang triển khai một loại select_related() cho các mối quan hệ chung.

3

bạn có thể sử dụng .extra function() tự trích xuất các lĩnh vực:

Claims.filter(proof__filteryouwant=valueyouwant).extra(select={'field_to_pull':'proof_proof.field_to_pull'}) 

Các .filter() sẽ thực hiện tham gia, các .extra() sẽ kéo một lĩnh vực. proof_proof là tên bảng SQL cho mô hình Proof. Nếu bạn cần nhiều trường, hãy chỉ định từng trường trong từ điển.

Các vấn đề liên quan