python 如何在Django Admin中显示多对多字段的“list_display”?

ukdjmx9f  于 2023-05-21  发布在  Python
关注(0)|答案(4)|浏览(235)
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。
但是,当我从list_display中取出'product'时,它会编译。那么,如何在list_display中显示'product'而不出错呢?

edit:也许更好的问题是如何在list_display中显示ManyToManyField

llycmphe

llycmphe1#

你可能无法直接做到。来自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()])

在admin list_display

list_display = ('get_products', 'vendor')
nhaq1z21

nhaq1z212#

这样你就可以做到这一点,请检查以下片段:

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')
gr8qqesn

gr8qqesn3#

如果你想保存额外的查询,你可以在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()])

根据文档,这样,只需要一个额外的查询来获取所有PurchaseOrder示例的相关Product项,而不是每个PurchaseOrder示例都需要一个查询。

tcomlyy6

tcomlyy64#

例如,CategoryProduct模型具有多对多关系,如下所示。* 我使用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)

然后,有CategoryProduct管理员,如下所示:

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_productsget_categories(),然后分别在CategoryProduct管理员中将它们设置为list_display,如下所示。* @admin.display()中的description参数可以将Django Admin中的列分别从GET PRODUCTSGET CATEGORIES重命名为PRODUCTSCATEGORIES

# "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 admin中显示如下:

然后,CATEGORIESProduct admin中显示如下:

此外,您还可以通过在CategoryProduct型号中分别定义get_products()get_categories()@admin.display()来显示PRODUCTSCATEGORIES列,如下所示:

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

然后在CategoryProduct管理员中分别设置为list_display,如下所示:

# "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',)

相关问题