muchos a muchos en la lista de visualización 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

Yo tengo ese codigo. Desafortunadamente, el error viene en admin.py con elManyToManyField

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

El error dice:

'PurchaseOrderAdmin.list_display [0]', 'product' es un ManyToManyField que no es compatible.

Sin embargo, se compila cuando saco 'product'de list_display. Entonces, ¿cómo puedo mostrar 'product'en list_displaysin darle errores?

Editar : Tal vez una mejor pregunta sería ¿cómo mostrar una ManyToManyFielden list_display?

Mdjon26
fuente

Respuestas:

171

Es posible que no pueda hacerlo directamente. De la documentación delist_display

Los campos ManyToManyField no son compatibles, porque eso implicaría ejecutar una instrucción SQL separada para cada fila de la tabla. No obstante, si desea hacer esto, asigne a su modelo un método personalizado y agregue el nombre de ese método a list_display. (Consulte a continuación para obtener más información sobre los métodos personalizados en list_display).

Puedes hacer algo como esto:

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

O definir un método modelo y usarlo

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

y en el administrador list_display

list_display = ('get_products', 'vendor')
karthikr
fuente
Esta parece una muy buena solución. Gracias. Aunque, ahora recibo un error que dice que "el valor nulo en la columna" product_id "viola la restricción no nula" ¿Alguna idea de lo que esto significa?
Mdjon26
3
Dado que esto hace que la base de datos caiga de rodillas, ¿cómo lo haría con select_related () o prefetch_related () para mejorar el rendimiento?
Cloud Artisans
3
En caso de que la pregunta de optimización siga siendo interesante, acabo de tener el mismo problema y descubrí que simplemente podría implementar un get_queryset()método optimizado para usted ModelAdmin, consulte stackoverflow.com/questions/12354099/…
goetz
1
@ SebastiánVansteenkiste Buena idea, tal vez cached_propertyayudaría. Pero creo que probablemente no lo haría. Cuando usa un optimizado get_queryset, puede, por ejemplo, anotar / preprocesar los datos allí, como hacer la concatenación de productos en SQL en lugar de en Django, y almacenar sus datos personalizados en su conjunto de consultas. Entonces solo necesitaría ejecutar esa lógica una vez en SQL y no para cada fila cuando se acceda a la propiedad.
goetz
1
Buen punto. Debería buscar hacer mi propia optimización get_queryset, simplemente no he podido leer los documentos completos (ni encontré un ejemplo lo suficientemente simple de lo que debería estar haciendo)
Sebastián Vansteenkiste
16

De esta manera, puede hacerlo, consulte el siguiente fragmento:

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)

Y en su método de llamada del módulo admin.py de la siguiente manera:

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