багато-до-багатьох у списку 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

У мене є цей код. На жаль, помилка виникає в admin.py ізManyToManyField

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

Помилка говорить:

'PurchaseOrderAdmin.list_display [0]', 'product' є ManyToManyField, який не підтримується.

Однак він компілюється, коли я виймаю 'product'з list_display. Так як я можу відобразити 'product'в list_displayне даючи йому помилки?

редагувати : Можливо, кращим запитанням було б, як ви відображаєте ManyToManyFieldin list_display?

Відповіді:


171

Можливо, ви не зможете це зробити безпосередньо. З документаціїlist_display

Поля ManyToManyField не підтримуються, оскільки це призведе до виконання окремого оператора SQL для кожного рядка в таблиці. Якщо ви все-таки хочете зробити це, надайте своїй моделі власний метод і додайте ім'я методу до list_display. (Докладніше про власні методи див. Нижче у списку_дисплей.)

Ви можете зробити щось подібне:

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()])

АБО визначте метод моделі та використовуйте його

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()])

і в адмін list_display

list_display = ('get_products', 'vendor')

Це виглядає як справді хороше рішення. Дякую. Хоча зараз я отримую повідомлення про помилку, коли "нульове значення в стовпці" product_id "порушує не нульове обмеження" Будь-яка ідея, що це означає?
Mdjon26,

3
Оскільки це збиває базу даних на коліна, як би ви це зробили за допомогою select_related () або prefetch_related () для підвищення продуктивності?
Cloud Artisans

3
Тільки в тому випадку , питання оптимізації все ще цікаво, я просто була така ж проблема і виявив, що ви могли б просто реалізувати оптимізований get_queryset()метод для ModelAdminсм stackoverflow.com/questions/12354099 / ...
Гетц

1
@ SebastiánVansteenkiste Гарна ідея, можливо cached_property, допоможе. Але я думаю, що, мабуть, не було б. Коли ви використовуєте оптимізований get_queryset, ви можете, наприклад, анотувати / попередньо обробити дані там, наприклад, робити конкатенацію продуктів у SQL замість Django, і зберігати власні дані у наборі запитів. Тоді вам потрібно буде виконати цю логіку лише один раз у SQL, а не для кожного рядка, коли здійснюється доступ до властивості.
goetz

1
Гарна думка. Я мав би зайнятися власною оптимізацією get_queryset, я просто не встиг прочитати цілі документи (і не знайшов досить простого прикладу того, що я маю робити)
Себастьян Ванстінкісті

16

Таким чином ви можете це зробити, будь ласка, перевірте такий фрагмент:

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)

А у вашому модулі admin.py метод виклику такий:

class categories(admin.ModelAdmin):
    list_display    = ('title', 'get_parents', 'when')
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.