2015-11-07 13 views
7

Tôi có một mô hình cuốn sách và một mô hình đánh giá,Django SQL truy vấn lặp lại n lần

class Book(models.Model): 
    title = models.CharField(max_length=255) 
    slug = AutoSlugField(unique=True, populate_from='title') 
    description = models.TextField() 
    # more fields 

class Rating(models.Model): 
    book = models.ForeignKey('library.Book') 
    score = models.DecimalField(max_digits=2, decimal_places=1) 

Query,

books = {'books': Book.objects.filter(pk__in=Rating.objects.all().order_by('-score' 
      ).values_list('book__id', flat=True))[:10] } 

mẫu,

{% for i in books %} 
    {{ i.title }}, {{ i.rating_set.all.first.score }} <br/> 
{% endfor %} 

ám chỉ rằng mô hình để các mẫu, nhưng thanh công cụ gỡ lỗi django hiển thị dưới dạng n lần trùng lặp trong đó n là số đối tượng trong danh sách. khi tôi sử dụng bộ nhớ đệm truy vấn, bình thường của nó.

enter image description here

những gì đang xảy ra phía sau, làm cách nào để khắc phục sự cố này?

cảm ơn.

Trả lời

4

Đọc về select_relatedprefetch_related.

Book.objects.filter(pk__in=Rating.objects.all().order_by('-score').values_list('book__id', flat=True)).preferch_related('rating_set')[:10] 

Trong mẫu Bạn muốn truy cập vào đánh giá sách {{ i.rating_set.all.0.score }}. Nếu không có select_related/prefetch_related Django trong mỗi hàng sẽ tạo truy vấn mới. Với prefetch_related Django đã thực hiện 1 truy vấn và tìm nạp tất cả các xếp hạng.

Trong trường hợp của bạn, sự cố có thể ở số .first..

+0

không có gì thay đổi, điều gì đó đã xảy ra khi mẫu ở phần '{{i.rating_set.all.first.score}}' – Rivadiz

+0

làm cách nào để khắc phục sự cố này? – Rivadiz

+1

đã thay đổi 'đầu tiên' thành' 0' và bây giờ không sao – Rivadiz

5

Không kiểm tra nhưng bạn chắc chắn nên prefetch rating_set để không làm cho thêm cơ sở dữ liệu hit cho mỗi cuốn sách để tìm điểm cao nhất của họ:

rated_books = Rating.objects.all().order_by('-score').values_list('book', flat=True) 
books = Book.objects.prefetch_related('rating_set').filter(pk__in=rated_books)[:10] 

Trong mẫu, tôi cũng nghi ngờ .first.all vì chúng có thể gây ra một cú đánh db bổ sung. Bên cạnh đó, bạn không cần phải gọi số .first vì chúng tôi đã biết những sách này được xếp hạng có ít nhất một đối tượng xếp hạng.

{% for book in books %} 
    {{ book.title }}, {{ book.rating_set.0.score }} <br/> 
{% endfor %} 
Các vấn đề liên quan