2017-12-14 108 views
5

Tôi có một hệ thống có mối quan hệ nhiều với một số mô hình (nói 1 a -> nhiều b) và nhiều mô hình có mối quan hệ 1-1 với một mô hình khác (nói 1 b -> 1 c). Rút ra như vậy:Django không thể xác định queryset để chuỗi một-nhiều với mối quan hệ một-một

/--- b1 --- c1 
/
a ---- b2 --- c2 
\ 
    \--- b3 --- c3 

tôi đã xác định để tạo ra một phương pháp trong đó thu thập tất cả các 's c tương ứng với a.

Với hệ thống mô hình có cấu trúc giống nhau, tốt nhất tôi có thể đưa ra được thể hiện trong phương pháp: Person.find_important_treats().

Có cách nào tốt hơn không liên quan quá nhiều cuộc gọi đến cơ sở dữ liệu không?

from django.db import models 

class Person(models.Model): 
    """ The 'a' from my above example """ 

    def find_important_treats(self): 
     return (pet.treat for pet in self.pets) 

class Pet(models.Model): 
    """ The 'b' from my above example """ 

    owner = models.ForeignKey(
     to=Person, 
     related_name='pets' 
    ) 

    favourite_treat = models.ForeignKey(
     to=Treat, 
    ) 

class Treat(models.Model): 
    """ The 'c' from my above example """ 
    pass 
+1

Có thể cùng những dòng này bạn sẽ tìm thấy câu trả lời 'Treat.objects.filter (pet__owner__pk = PersonId) '. – aquaman

+1

Bạn có thể cụ thể hơn không, bạn có được trộn lẫn trong toàn bộ các vật thể xử lý hoặc không? Điều đó gây ra một khác biệt lớn! – DhiaTN

+0

@DhiaTN, tôi muốn toàn bộ điều trị (tham lam với tôi), vì nó có thông tin tôi muốn hiển thị trong mẫu của tôi. – Splatmistro

Trả lời

4

tôi đề nghị các giải pháp hai gần như tương tự tùy thuộc vào trường hợp sử dụng của bạn:

  • Sử dụng bộ nhớ đệm
class Person(models.Model): 
     """ The 'a' from my above example """ 

     @property 
     def iter_important_treats(self): 
      return (pet.treat_id for pet in self.pets.all()) # will use the cached objects if they exist 

    person = Person.objects.get(id=person_id).select_related('pets') # to cache the pets list within the person object avoiding future additional queries 
    treats = Treat.objects.filter(id__in=person.iter_importent_treats) 
  • Nếu không có Sử dụng bộ nhớ đệm:
class Person(models.Model): 
     """ The 'a' from my above example """ 

     @property 
     def iter_important_treats(self): 
      return iter(self.pets.values_list('treat_id', flat=True)) # caching will not affect the query behviour 

    person = Person.objects.get(id=person_id) 
    treats = Treat.objects.filter(id__in=person.iter_importent_treats) 

NB:

  1. chúng tôi sử dụng treat_id thay treat__id để tránh thêm tham gia truy vấn, vì django tiết kiệm đã được các treat_id ở cấp đối tượng vật nuôi nhưng nếu bạn sử dụng treat__id sau đó bạn buộc một truy vấn tham gia.
  2. Hạn chế sở hữu một iterator ID là chỉ dành riêng cho đảo ngược và bảo trì vì lợi ích
2

Sau đây nên làm những gì bạn đang sau:

def find_important_treats(self): 
    return Treat.objects.filter(id__in=person.pets.values_list('treat_id')) 

Nó có được tất cả các ids của Treat s mà các con vật nuôi có và sau đó trả về họ.

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