2009-07-10 29 views
5

Tôi đã chảy nước dãi trên Django cả ngày trong khi mã hóa một trang web nội bộ trong thời gian kỷ lục, nhưng bây giờ tôi nhận thấy rằng một cái gì đó rất không hiệu quả với ForeignKeys của tôi trong mô hình.Rất nhiều truy vấn từ các trường ngoại ngữ django

Tôi có một mô hình có 6 khóa ngoại, là bảng tra cứu cơ bản. Khi tôi truy vấn tất cả các đối tượng và hiển thị chúng trong một mẫu, nó chạy khoảng 10 truy vấn cho mỗi mục. Dưới đây là một số mã, mà nên giải thích nó tốt hơn:

class Website(models.Model): 
    domain_name = models.CharField(max_length=100) 
    registrant = models.ForeignKey('Registrant') 
    account = models.ForeignKey('Account') 
    registrar = models.ForeignKey('Registrar') 
    server = models.ForeignKey('Server', related_name='server') 
    host = models.ForeignKey('Host') 
    target_server = models.ForeignKey('Server', related_name='target') 

class Registrant(models.Model): 
    name = models.CharField(max_length=100) 

... và 5 bảng đơn giản khác. Có 155 bản ghi trang web và trong chế độ xem tôi đang sử dụng:

Website.objects.all() 

Nó kết thúc thực hiện 1544 truy vấn. Trong mẫu, tôi đang sử dụng tất cả các trường nước ngoài, như sau:

<span class="value">Registrant:</span> <a href="/filter/registrant/{{ website.registrant.id }}">{{ website.registrant.name }}</a><br /> 

Vì vậy, tôi biết nó sẽ chạy nhiều truy vấn ... nhưng có vẻ như điều này quá mức. Điều này có bình thường không? Tôi có nên không làm theo cách này không?

Tôi khá mới đối với Django, vì vậy hy vọng tôi chỉ đang làm điều gì đó ngu ngốc. Nó chắc chắn là một khuôn khổ khá tuyệt vời.

Trả lời

5

Bạn nên sử dụng select_related function, ví dụ:

Website.objects.select_related() 

sao cho nó sẽ tự động tham gia và theo tất cả các khóa ngoại khi truy vấn được thực hiện thay vì tải chúng theo yêu cầu khi chúng được sử dụng. Django tải dữ liệu từ cơ sở dữ liệu một cách uể oải, vì vậy theo mặc định, bạn nhận được hành vi sau đây

# one database query 
website = Website.objects.get(id=123) 

# first time account is referenced, so another query 
print website.account.username 

# account has already been loaded, so no new query 
print website.account.email_address 

# first time registrar is referenced, so another query 
print website.registrar.name 

v.v. Nếu bạn sử dụng liên quan đã chọn, thì một phép nối được thực hiện phía sau hậu trường và tất cả các khóa ngoài này sẽ tự động được theo sau và được nạp vào truy vấn đầu tiên, do đó chỉ có một truy vấn cơ sở dữ liệu được thực hiện. Vì vậy, trong ví dụ trên, bạn sẽ nhận được

# one database query with a join and all foreign keys followed 
website = Website.objects.select_related().get(id=123) 

# no additional query is needed because the data is already loaded 
print website.account.username 
print website.account.email_address 
print website.registrar.name 
+0

Cảm ơn bạn! Điều đó chắc chắn làm cho rất nhiều ý nghĩa để có chức năng đó. Bây giờ nó đang chạy 9 truy vấn. Kể từ khi các bảng nhỏ, tôi không quan tâm rằng nó đang tải tất cả các dữ liệu (và rõ ràng nó là cách tốt hơn để). –

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