Viele-zu-Viele in der Liste zeigen Django an

87
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

Ich habe diesen Code. Leider kommt der Fehler in admin.py mit demManyToManyField

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

Der Fehler lautet:

'PurchaseOrderAdmin.list_display [0]', 'product' ist ein ManyToManyField, das nicht unterstützt wird.

Allerdings stellt es , wenn ich nehme 'product'von out list_display. So wie kann ich Anzeige 'product'in list_displayohne es eine Fehlermeldung?

bearbeiten : Vielleicht wäre eine bessere Frage, wie Sie ein ManyToManyFieldin anzeigen list_display?

Mdjon26
quelle

Antworten:

165

Möglicherweise können Sie dies nicht direkt tun. Aus der Dokumentation vonlist_display

ManyToManyField-Felder werden nicht unterstützt, da dazu für jede Zeile in der Tabelle eine separate SQL-Anweisung ausgeführt werden müsste. Wenn Sie dies dennoch tun möchten, geben Sie Ihrem Modell eine benutzerdefinierte Methode und fügen Sie den Namen dieser Methode zu list_display hinzu. (Weitere Informationen zu benutzerdefinierten Methoden finden Sie weiter unten in list_display.)

Sie können so etwas tun:

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

ODER definieren Sie eine Modellmethode und verwenden Sie diese

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

und im admin list_display

list_display = ('get_products', 'vendor')
karthikr
quelle
Das sieht nach einer wirklich guten Lösung aus. Danke dir. Obwohl jetzt eine Fehlermeldung angezeigt wird, dass "Nullwert in Spalte" product_id "die Nicht-Null-Einschränkung verletzt." Haben Sie eine Idee, was dies bedeutet?
Mdjon26
3
Wie würden Sie dies mit select_related () oder prefetch_related () tun, um die Leistung zu verbessern, da dies die Datenbank in die Knie zwingt?
Cloud Artisans
3
Nur für den Fall, dass die Optimierungsfrage immer noch interessant ist, hatte ich das gleiche Problem und fand heraus, dass Sie einfach eine optimierte get_queryset()Methode für Ihre implementieren können ModelAdmin, siehe stackoverflow.com/questions/12354099/…
goetz
1
@ SebastiánVansteenkiste Gute Idee, vielleicht cached_propertywürde helfen. Aber ich denke es würde wahrscheinlich nicht. Wenn Sie eine optimierte Version verwenden get_queryset, können Sie beispielsweise die Daten dort mit Anmerkungen versehen / vorverarbeiten, z. B. die Verkettung von Produkten in SQL anstelle von Django, und Ihre benutzerdefinierten Daten in Ihrem Abfragesatz speichern. Dann müssten Sie diese Logik nur einmal in SQL ausführen und nicht für jede Zeile, wenn auf die Eigenschaft zugegriffen wird.
Goetz
1
Guter Punkt. Ich sollte versuchen, meine eigenen optimierten zu machen get_queryset, ich bin einfach nicht dazu gekommen, die vollständigen Dokumente zu lesen (noch habe ich ein einfaches Beispiel dafür gefunden, was ich tun sollte)
Sebastián Vansteenkiste
16

Auf diese Weise können Sie das folgende Snippet überprüfen:

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)

Rufen Sie in Ihrem Modul admin.py die folgende Methode auf:

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