many-to-many dalam daftar menampilkan 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

Saya memiliki kode itu. Sayangnya, kesalahan muncul di admin.py denganManyToManyField

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

Kesalahannya mengatakan:

'PurchaseOrderAdmin.list_display [0]', 'product' adalah ManyToManyField yang tidak didukung.

Namun, itu dikompilasi saat saya 'product'mengeluarkan list_display. Jadi bagaimana saya bisa menampilkan 'product'di list_displaytanpa memberikan kesalahan?

edit : Mungkin pertanyaan yang lebih baik adalah bagaimana Anda menampilkan ManyToManyFieldin list_display?

Mdjon26
sumber

Jawaban:

171

Anda mungkin tidak dapat melakukannya secara langsung. Dari dokumentasilist_display

Bidang ManyToManyField tidak didukung, karena itu akan memerlukan eksekusi pernyataan SQL terpisah untuk setiap baris dalam tabel. Jika Anda tetap ingin melakukan ini, berikan model Anda metode kustom, dan tambahkan nama metode tersebut ke list_display. (Lihat di bawah untuk lebih lanjut tentang metode kustom di list_display.)

Anda bisa melakukan sesuatu seperti ini:

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

ATAU tentukan metode model, dan gunakan itu

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

dan di admin list_display

list_display = ('get_products', 'vendor')
karthikr
sumber
Sepertinya ini solusi yang sangat bagus. Terima kasih. Meskipun, sekarang saya mendapatkan pesan kesalahan yang mengatakan "nilai null di kolom" product_id "melanggar batasan bukan-null" Tahu apa artinya ini?
Mdjon26
3
Karena ini membuat database bertekuk lutut, bagaimana Anda akan melakukannya dengan select_related () atau prefetch_related () untuk meningkatkan kinerja?
Cloud Artisan
3
Kalau-kalau pertanyaan pengoptimalan masih menarik, saya baru saja mengalami masalah yang sama dan menemukan bahwa Anda dapat dengan mudah menerapkan get_queryset()metode yang dioptimalkan untuk Anda ModelAdmin, lihat stackoverflow.com/questions/12354099/…
goetz
1
@ SebastiánVansteenkiste Ide bagus, mungkin cached_propertybisa membantu. Tapi saya pikir mungkin tidak. Ketika Anda menggunakan yang dioptimalkan get_queryset, Anda dapat misalnya membuat anotasi / pra-proses data di sana, seperti melakukan penggabungan produk dalam SQL daripada di Django, dan menyimpan data khusus Anda di queryset Anda. Maka Anda hanya perlu menjalankan logika itu sekali dalam SQL dan tidak untuk setiap baris saat properti diakses.
goetz
1
Poin yang bagus. Saya harus melakukan pengoptimalan sendiri get_queryset, saya hanya belum sempat membaca dokumen lengkapnya (atau menemukan contoh yang cukup sederhana tentang apa yang seharusnya saya lakukan)
Sebastián Vansteenkiste
16

Dengan cara ini Anda dapat melakukannya, silakan periksa cuplikan berikut:

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)

Dan dalam metode pemanggilan modul admin.py Anda sebagai berikut:

class categories(admin.ModelAdmin):
    list_display    = ('title', 'get_parents', 'when')
JKV
sumber