class Product(models.Model):
products = models.CharField(max_length=256)
def __unicode__(self):
return self.products
class PurchaseOrder(models.Model):
product = models.ManyToManyField('Product')
vendor = models.ForeignKey('VendorProfile')
dollar_amount = models.FloatField(verbose_name='Price')
我有那个密码。不幸的是,错误出现在 admin.py 中
ManyToManyField
class PurchaseOrderAdmin(admin.ModelAdmin):
fields = ['product', 'dollar_amount']
list_display = ('product', 'vendor')
错误说:
'PurchaseOrderAdmin.list_display[0]', 'product' 是 ManyToManyField 这是不支持的。
但是,当我从
'product'
中取出 list_display
时,它会编译。那么如何在 'product'
中显示 list_display
而不会出错?
edit:也许更好的问题是如何在
ManyToManyField
中显示list_display
?
您可能无法直接进行。 来自
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')
你可以通过这种方式做到这一点,请检查以下代码片段:
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')
如果你想保存额外的查询,你可以在get_queryset
方法中使用
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()])
根据 Docs,通过这种方式,只需要一个额外的查询来获取所有
Product
实例的相关 PurchaseOrder
项,而不是每个 PurchaseOrder
实例需要一个查询。
例如,
Category
和Product
模型具有多对多关系,如下所示。 *我使用Django 4.2.1:
# "models.py"
from django.db import models
class Category(models.Model):
name = models.CharField(max_length=20)
def __str__(self):
return self.name
class Product(models.Model):
categories = models.ManyToManyField(Category)
name = models.CharField(max_length=50)
price = models.DecimalField(decimal_places=2, max_digits=5)
然后就是
Category
和Product
管理员如下图:
from django.contrib import admin
from .models import Category, Product
@admin.register(Category)
class CategoryAdmin(admin.ModelAdmin):
list_display = ('id', 'name')
ordering = ('id',)
@admin.register(Product)
class ProductAdmin(admin.ModelAdmin):
list_display = ('id', 'name', 'price')
ordering = ('id',)
然后,
Category
admin 有 5 个对象,如下所示:
并且,
Product
admin 有 6 个对象,如下所示:
现在,用
@admin.display()定义
get_products
和get_categories()
,然后分别在Category
和Product
admins中将它们设置为list_display,如下所示。 *
description
中的参数 @admin.display()
可以将 Django Admin 中的列从 GET PRODUCTS
和 GET CATEGORIES
分别重命名为 PRODUCTS
和 CATEGORIES
:
# "admin.py"
@admin.register(Category)
class CategoryAdmin(admin.ModelAdmin):
list_display = ('id', 'name', 'get_products')
ordering = ('id',) # Here
# Here
@admin.display(description='products')
def get_products(self, obj):
return [product.name for product in obj.product_set.all()]
@admin.register(Product)
class ProductAdmin(admin.ModelAdmin): # Here
list_display = ('id', 'name', 'price', 'get_categories')
ordering = ('id',)
# Here
@admin.display(description='categories')
def get_categories(self, obj):
return [category.name for category in obj.categories.all()]
然后,
PRODUCTS
列显示在Category
管理中,如下所示:
然后,
CATEGORIES
列显示在Product
管理中,如下所示:
此外,您还可以通过在
PRODUCTS
和CATEGORIES
模型中分别定义get_products()
和get_categories()
和@admin.display()
来显示Category
和Product
列,如下所示:
# "models.py"
from django.db import models
from django.contrib import admin
class Category(models.Model):
name = models.CharField(max_length=20)
def __str__(self):
return self.name
# Here
@admin.display(description='products')
def get_products(self):
return [product.name for product in self.product_set.all()]
class Product(models.Model):
categories = models.ManyToManyField(Category)
name = models.CharField(max_length=50)
price = models.DecimalField(decimal_places=2, max_digits=5)
# Here
@admin.display(description='categories')
def get_categories(self):
return [category.name for category in self.categories.all()]
然后在
list_display
和Category
管理员分别设置为Product
如下图:
# "admin.py"
...
@admin.register(Category)
class CategoryAdmin(admin.ModelAdmin):
list_display = ('id', 'name', 'get_products')
ordering = ('id',) # Here
@admin.register(Product)
class ProductAdmin(admin.ModelAdmin): # Here
list_display = ('id', 'name', 'price', 'get_categories')
ordering = ('id',)