列表显示django中的多对多
Posted
技术标签:
【中文标题】列表显示django中的多对多【英文标题】:many-to-many in list display django 【发布时间】:2013-08-09 03:11:05 【问题描述】: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' 是一个多对多字段 不支持。
但是,当我从 list_display
中取出 'product'
时,它会编译。那么如何在list_display
中显示'product'
而不会出错呢?
编辑:也许更好的问题是如何在list_display
中显示ManyToManyField
?
【问题讨论】:
【参考方案1】:您可能无法直接执行此操作。 From the documentation of 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”列中的空值违反非空约束“知道这意味着什么吗? 既然这会导致数据库崩溃,您将如何使用 select_related() 或 prefetch_related() 来提高性能? 以防万一优化问题仍然有趣,我刚刚遇到同样的问题,发现您可以简单地为您的ModelAdmin
实现优化的get_queryset()
方法,请参阅***.com/questions/12354099/…跨度>
@SebastiánVansteenkiste 好主意,也许cached_property
会有所帮助。但我认为它可能不会。当您使用优化的get_queryset
时,您可以例如在此处注释/预处理数据,例如在 SQL 中而不是在 Django 中连接产品,并将您的自定义数据存储在您的查询集中。然后,您只需在 SQL 中执行一次该逻辑,而不是在访问属性时对每一行执行一次。
好点。我应该考虑做我自己优化的get_queryset
,我只是没有时间阅读完整的文档(也没有找到一个足够简单的例子来说明我应该做什么)【参考方案2】:
这样就可以了,请查看以下sn-p:
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')
【讨论】:
【参考方案3】:如果您想保存额外的查询,您可以添加prefetch_related
class PurchaseOrderAdmin(admin.ModelAdmin):
fields = ['product', 'dollar_amount']
list_display = ('get_products', 'vendor')
def get_queryset(self, request):
qs = super().get_queryset(request)
return qs.prefetch_related('product')
def get_products(self, obj):
return ",".join([p.products for p in obj.product.all()])
【讨论】:
以上是关于列表显示django中的多对多的主要内容,如果未能解决你的问题,请参考以下文章
Django - 查询列表中的任何项目在多对多字段中的任何对象
CASCADE 究竟如何与 Django 中的多对多字段一起工作