列表显示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]”,“产品”是不支持的ManyToManyField。

然而,当我把它编译'product'出来list_display。所以,我怎么能显示'product'list_display没有给它的错误?

编辑:也许一个更好的问题是你如何显示ManyToManyFieldlist_display

Answers:


171

您可能无法直接执行此操作。从文档list_display

不支持ManyToManyField字段,因为这将需要对表中的每一行执行单独的SQL语句。如果仍然要执行此操作,请为模型提供一个自定义方法,然后将该方法的名称添加到list_display。(有关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/…–
goetz

1
@SebastiánVansteenkiste好主意,也许cached_property会有所帮助。但我认为可能不会。当您使用Optimized时get_queryset,您可以例如在其中注释/预处理数据,例如在SQL中而不是在Django中进行产品串联,然后将自定义数据存储在queryset中。这样,您只需在SQL中执行一次该逻辑即可,而无需在访问该属性时对每一行执行一次。
goetz

1
好点子。我应该考虑做我自己的优化get_queryset,我只是还没有得到周围阅读完整的文档(也没有发现什么,我应该做一个很简单的例子)
塞巴斯蒂安Vansteenkiste

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')
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.