2012-12-20 28 views
28

Giả sử này như mô hình django vì lợi ích của simplcity:django chúng ta có thể chọn một trường liên quan trên mô hình có liên quan đến tìm nạp trước không?

class A(): 

    a = manytomany('B') 

class B(): 

    b = charfield() 
    z = foreignkey('C') 

class C(): 

    c = charfield() 

Chúng ta có thể làm điều gì đó như thế này để lấy z thêm:

foo = A.objects.get(pk = 1).prefetch_related('a').select_related('a__z') 
+0

Đây là tất cả được bao gồm trong hướng dẫn sử dụng ... https://docs.djangoproject.com/en/dev/ref/models/querysets/, nhưng "có" là câu trả lời. – demux

+1

Thực ra, câu trả lời là “không”, lệnh gọi 'select_related' được viết trong câu hỏi sẽ không hoạt động. Tôi sẽ thêm một câu trả lời mới. Nhân tiện, lệnh gọi 'get' phải ở cuối, không phải trước' select_related' và 'prefetch_related'. – koniiiik

Trả lời

21

Bạn chỉ cần một prefetch_related gọi:

foo = A.objects.prefetch_related('a__z').get(pk=1) 

Thao tác này sẽ tìm nạp trước cả hai bảng. Trong Django 1.7+, bạn có thể cải thiện hiệu suất bằng cách sử dụng đối tượng Prefetch, như trong koniiiik's answer.

+1

tôi nghĩ rằng prefetch liên quan chỉ hoạt động trên 'manytomanyfield', nhưng nó hoạt động trên' ngoại khóa 'quá? –

+0

Như Arnar đã nói trong phần nhận xét, điều này được đề cập trong [tài liệu liên quan đến tìm nạp trước] (https://docs.djangoproject.com/en/dev/ref/models/querysets/#prefetch-related). Trường hợp sử dụng của bạn tương tự như ví dụ '>>> Restaurant.objects.prefetch_related ('best_pizza__toppings')'. – Alasdair

+0

Có tình huống nào không hoạt động? Tôi đang gặp vấn đề với mô hình a có khóa ngoại cho b và khóa ngoại cho c. Tôi muốn làm c.objects.prefetch_related ('a__b') nhưng nó chỉ tìm nạp tập hợp cho a và không làm gì cho b. – Adam

39

This answer là chính xác với các phiên bản của Django trước 1.7. Nó tạo ra ba truy vấn: đầu tiên, lấy cá thể của A, sau đó lấy các cá thể có liên quan của nó là B và cuối cùng tìm nạp các cá thể của C liên quan đến trường hợp của B được tìm nạp trong truy vấn thứ hai.

Trước Django 1,7, điều này là tốt nhất bạn có thể làm, thậm chí khi truy vấn thứ hai có thể, về mặt lý thuyết, chọn tất cả B đối tượng cùng với C đối tượng có liên quan tham gia thông qua các zForeignKey.

Bắt đầu với Django 1.7, có lớp nâng cao hơn django.db.models.Prefetch cho phép bạn thực hiện điều đó. Với Prefetch bạn có thể tùy chỉnh queryset sử dụng để prefetch đối tượng liên quan như thế này:

foo = A.objects.prefetch_related(
    Prefetch('a', queryset=B.objects.select_related('z')) 
).get(pk=1) 

Điều này dẫn đến chỉ có hai câu hỏi (như trái ngược với ba khi sử dụng prefetch_related('a__z')) và cho phép các cơ sở dữ liệu chăm sóc thứ hai tham gia, mà nên về mặt lý thuyết, kết quả hoạt động tốt hơn một chút.

+4

Điều này là tuyệt vời! Tôi không biết về Prefetch. Cảm ơn. Lưu ý cho bất cứ ai sử dụng nó trong tương lai: 'Prefetch' là trong không gian nhập mô hình, do đó, để nhập nó để sử dụng nó như trong ví dụ:' from django.db.models import Prefetch ' –

+1

Điểm tốt, tôi đã thêm nhập đường dẫn đến câu trả lời, cũng như liên kết tới tài liệu. Cám ơn vì sự gợi ý. – koniiiik

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