239👍
You may not be able to do it directly. From the documentation of list_display
ManyToManyField fields aren’t supported, because that would entail
executing a separate SQL statement for each row in the table. If you
want to do this nonetheless, give your model a custom method, and add
that method’s name to list_display. (See below for more on custom
methods in list_display.)
You can do something like this:
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()])
OR define a model method, and use that
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()])
and in the admin list_display
list_display = ('get_products', 'vendor')
29👍
This way you can do it, kindly checkout the following snippet:
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)
And in your admin.py module call method as follows:
class categories(admin.ModelAdmin):
list_display = ('title', 'get_parents', 'when')
- [Django]-POST jQuery array to Django
- [Django]-Django aggregate or annotate
- [Django]-Iterating over related objects in Django: loop over query set or use one-liner select_related (or prefetch_related)
17👍
If you want to save extra queries, you can use prefetch_related in the get_queryset
method like below:
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()])
According to the Docs, In this way, there would be just one extra query needed to fetch related Product
items of all PurchaseOrder
instances instead of needing one query per each PurchaseOrder
instance.
- [Django]-Django: How to get related objects of a queryset?
- [Django]-Running a specific test case in Django when your app has a tests directory
- [Django]-ImproperlyConfigured: You must either define the environment variable DJANGO_SETTINGS_MODULE or call settings.configure() before accessing settings
2👍
For example, there are Category
and Product
models which have many-to-many relationship as shown below. *I use 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)
Then, there are Category
and Product
admins as shown below:
# "admin.py"
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',)
Then, Category
admin has 5 objects as shown below:
And, Product
admin has 6 objects as shown below:
Now, define get_products
and get_categories()
with @admin.display(), then set them to list_display in Category
and Product
admins respectively as shown below. *description
argument in @admin.display()
can rename the columns in Django Admin from GET PRODUCTS
and GET CATEGORIES
to PRODUCTS
and CATEGORIES
respectively:
# "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()]
Then, PRODUCTS
column is displayed in Category
admin as shown below:
Then, CATEGORIES
column is displayed in Product
admin as shown below:
Also, you can display PRODUCTS
and CATEGORIES
columns by defining get_products()
and get_categories()
with @admin.display()
in Category
and Product
models respectively as shown below:
# "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()]
Then, set them to list_display
in Category
and Product
admins respectively as shown below:
# "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',)
- [Django]-Django – Rotating File Handler stuck when file is equal to maxBytes
- [Django]-MySQL "incorrect string value" error when save unicode string in Django
- [Django]-Django REST framework: non-model serializer