2012-05-21 35 views
5

Tôi có hai mô hình:Django - truy cập quản lý chìa khóa nước ngoài từ các mẫu django

class Product(models.Model): 
    name = models.CharField(max_length=255) 

class ProductPhoto(models.Model): 
    product = models.ForeignKey('Product', related_name='photos') 
    is_live = models.IntegerField(choices=LIVE_CHOICES, default=1) 

    live = LiveManager() 

class LiveManager(Manager): 
    def get_query_set(self): 
     return super(LiveManager, self).get_query_set().filter(is_live=1) 

tôi đang cố gắng để có được hình ảnh trực tiếp từ chi tiết sản phẩm mẫu.

Cố gắng,

{% for photo in product.photos.live %} 

mà không làm việc và nhìn vào tài liệu và không thể tìm thấy ví dụ. Có thể gọi người quản lý khóa ngoại từ một mẫu không? Tôi có nên tạo một hàm trong Mô hình sản phẩm trả về bộ truy vấn ảnh sản phẩm không?

Cảm ơn bạn.

Trả lời

23

Vâng, cách bạn đang sử dụng nó là sai, dù sao đi nữa. Bạn chỉ cần chuyển người quản lý vào vòng lặp for, không phải là một queryset có thể được lặp lại. Tuy nhiên, photos chính nó là "người quản lý có liên quan", không phải là mô hình thực tế ProductPhoto và người quản lý có liên quan dựa trên người quản lý được liệt kê đầu tiên hoặc objects (người quản lý mặc định).

Kể từ khi, bạn xác định live, nhưng không còn xác định objects, bạn không thực sự có một người quản lý objects trên mô hình này, nghĩa là liên kết này sẽ thất bại: ProductPhoto.objects.all(). Hãy nhớ rằng, nếu bạn xác định người quản lý tùy chỉnh trên mô hình của mình, Django sẽ không còn tự động thêm người quản lý có tên objects nữa.

Các tin tốt là vì live là người quản lý mặc định bây giờ, bạn có thể sử dụng nó giống như:

{% for photo in product.photos.all %} 

Và, bạn sẽ chỉ nhận được "sống" đối tượng. Tin xấu là điều này sẽ phá vỡ rất nhiều thứ khác phụ thuộc vào trình quản lý mặc định là tập hợp đầy đủ các đối tượng (ví dụ như quản trị viên). Về cơ bản, bạn đang ẩn khối đối tượng "không hoạt động".

Những gì bạn cần có là:

class ProductPhoto(models.Model): 
    product = models.ForeignKey('Product', related_name='photos') 
    is_live = models.IntegerField(choices=LIVE_CHOICES, default=1) 

    objects = models.Manager() 
    live = LiveManager() 

ý rằng objects được định nghĩa bằng tay nó đầu tiên, có nghĩa là nó sẽ vẫn là quản lý mặc định. Tuy nhiên, điều đó sẽ không còn cho phép bạn sử dụng trình quản lý live của bạn trong mẫu. Nói chung, đối với một cái gì đó như thế này, tốt nhất là chỉ cần sử dụng một người quản lý đơn và thêm một phương pháp để nó quay trở lại "sống" đối tượng:

class ProductPhotoQuerySet(models.query.QuerySet): 
    def live(self): 
     return self.filter(is_live=1) 

class ProductPhotoManager(models.Manager): 
    use_for_related_fields = True 

    def get_query_set(self): 
     return ProductPhotoQuerySet(self.model) 

    def live(self, *args, **kwargs): 
     return self.get_query_set().live(*args, **kwargs) 

Ở đây, chúng tôi đang thực sự subclassing cả QuerySet Manager. Điều này sẽ cho phép bạn chuỗi live ở bất cứ đâu thay vì chỉ ở phía trước. Ví dụ: nếu bạn chỉ có một người quản lý tùy chỉnh mà không có bộ truy vấn tùy chỉnh, bạn sẽ chỉ có thể làm ProductPhoto.objects.live().filter(...) chứ không phải ProductPhoto.objects.filter(...).live().

Vì vậy, bạn sau đó thêm rằng để mô hình của bạn như objects (lấy nơi mặc định một Django cung cấp):

class ProductPhoto(models.Model): 
    product = models.ForeignKey('Product', related_name='photos') 
    is_live = models.IntegerField(choices=LIVE_CHOICES, default=1) 

    objects = ProductPhotoManager() 

Và, cuối cùng, bạn sẽ có thể sử dụng nó trong mẫu của bạn:

{% for photo in product.photos.live %} 
+2

Cảm ơn bạn Chris vì câu trả lời hay nhất và giải thích kỹ lưỡng. Tôi đã học được rất nhiều. – DavidL

+5

Phương thức 'get_query_set' được đổi tên thành' get_queryset' trong Django 1.6. – allcaps

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