nhiều-nhiều trong danh sách hiển thị django


91
class PurchaseOrder(models.Model):
    product = models.ManyToManyField('Product')
    vendor = models.ForeignKey('VendorProfile')
    dollar_amount = models.FloatField(verbose_name='Price')


class Product(models.Model):
   products = models.CharField(max_length=256)

   def __unicode__(self):
       return self.products

Tôi có mã đó. Rất tiếc, lỗi xảy ra trong admin.py vớiManyToManyField

class PurchaseOrderAdmin(admin.ModelAdmin):
    fields = ['product', 'dollar_amount']
    list_display = ('product', 'vendor')

Lỗi cho biết:

'PurchaseOrderAdmin.list_display [0]', 'product' là ManyToManyField không được hỗ trợ.

Tuy nhiên, nó biên dịch khi tôi lấy 'product'ra list_display. Vì vậy, làm thế nào tôi có thể hiển thị 'product'trong list_displaymà không cho nó lỗi?

chỉnh sửa : Có lẽ một câu hỏi tốt hơn sẽ là làm thế nào để bạn hiển thị một ManyToManyFieldtrong list_display?

Câu trả lời:


171

Bạn có thể không trực tiếp làm được. Từ tài liệu củalist_display

Trường ManyToManyField không được hỗ trợ, vì điều đó sẽ đòi hỏi phải thực thi một câu lệnh SQL riêng cho mỗi hàng trong bảng. Tuy nhiên, nếu bạn muốn làm điều này, hãy cung cấp cho mô hình của bạn một phương thức tùy chỉnh và thêm tên của phương thức đó vào list_display. (Xem bên dưới để biết thêm về các phương pháp tùy chỉnh trong list_display.)

Bạn có thể làm điều gì đó như sau:

class PurchaseOrderAdmin(admin.ModelAdmin):
    fields = ['product', 'dollar_amount']
    list_display = ('get_products', 'vendor')

    def get_products(self, obj):
        return "\n".join([p.products for p in obj.product.all()])

HOẶC xác định một phương pháp mô hình và sử dụng

class PurchaseOrder(models.Model):
    product = models.ManyToManyField('Product')
    vendor = models.ForeignKey('VendorProfile')
    dollar_amount = models.FloatField(verbose_name='Price')

    def get_products(self):
        return "\n".join([p.products for p in self.product.all()])

và trong quản trị viên list_display

list_display = ('get_products', 'vendor')

Đây có vẻ là một giải pháp thực sự tốt. Cảm ơn bạn. Mặc dù, bây giờ tôi đang gặp lỗi nói rằng "giá trị null trong cột" product_id "vi phạm ràng buộc not-null" Bạn có biết điều này có nghĩa là gì không?
Mdjon26

3
Vì điều này khiến cơ sở dữ liệu bị sụp đổ, bạn sẽ làm thế nào với select_osystem () hoặc prefetch_inity () để cải thiện hiệu suất?
Cloud Artisans

3
Chỉ trong trường hợp các câu hỏi tối ưu hóa vẫn thú vị, tôi chỉ có cùng một vấn đề và phát hiện ra rằng bạn chỉ có thể thực hiện một tối ưu hóa get_queryset()phương pháp của bạn ModelAdmin, xem stackoverflow.com/questions/12354099/...
Goetz

1
@ SebastiánVansteenkiste Ý kiến ​​hay, có thể cached_propertysẽ hữu ích. Nhưng tôi nghĩ nó có lẽ sẽ không. Khi bạn sử dụng một tối ưu hóa get_queryset, bạn có thể ví dụ: chú thích / xử lý trước dữ liệu ở đó, như thực hiện nối các sản phẩm trong SQL thay vì trong Django và lưu trữ dữ liệu tùy chỉnh của bạn trong bộ truy vấn của bạn. Sau đó, bạn sẽ chỉ cần thực thi logic đó một lần trong SQL và không phải cho mọi hàng khi thuộc tính được truy cập.
goetz

1
Điểm tốt. Tôi nên xem xét việc tối ưu hóa của riêng mình get_queryset, tôi chỉ chưa đọc được toàn bộ tài liệu (cũng không tìm thấy một ví dụ đủ đơn giản về những gì tôi nên làm)
Sebastián Vansteenkiste

16

Bạn có thể làm theo cách này, vui lòng xem đoạn mã sau:

class Categories(models.Model):
    """ Base category model class """

    title       = models.CharField(max_length=100)
    description = models.TextField()
    parent      = models.ManyToManyField('self', default=None, blank=True)
    when        = models.DateTimeField('date created', auto_now_add=True)

    def get_parents(self):
        return ",".join([str(p) for p in self.parent.all()])

    def __unicode__(self):
        return "{0}".format(self.title)

Và trong phương thức gọi mô-đun admin.py của bạn như sau:

class categories(admin.ModelAdmin):
    list_display    = ('title', 'get_parents', 'when')
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.