Reputation: 263
I want to know how I can display the "highest value" from my ManyToMany Field in the admin. This is my models.py
file:
class Personal(models.Model):
lastname = models.CharField(max_length = 100)
firstname = models.CharField(max_length = 100)
degree = models.ManyToManyField('Degree')
def __str__(self):
return self.lastname
class Degree(models.Model):
name_degree = models.CharField(verbose_name = 'Degree', max_length = 200, blank = False)
rank = models.PositiveIntegerField(default = 0)
def __str__(self):
return self.name_degree
In my backend, I have created different types of Degree's, all with a "ranking". In my case, the highest degree you can have is "Doctoral Degree", with a rank of "6".
So if a User is creating himself in "Personal" he will have the option to select all the Degree's he has achieved. But for my Personal list, I just to want to see the highest one, e.g. if the User selects "Bachelor's Degree" and "Master's Degree", the Personal list should only contain "Master's Degree", because 5 > 4.
Someone with an idea on how my admin.py
file should look like?
class PersonalAdmin(admin.ModelAdmin):
list_display = ('lastname', 'firstname', ) # 'degree'
Big thanks in advance!
Upvotes: 0
Views: 601
Reputation: 476750
You can define a method in your ModelAdmin
to calculate the maximum degree:
class PersonalAdmin(admin.ModelAdmin):
list_display = ('lastname', 'firstname', 'highest_degree')
@admin.display(description='Highest degree')
def highest_degree(self, obj):
deg = Degree.objects.filter(personal=obj).first()
if deg:
return deg.name_degree
return None
This is however quite inefficient if we want to render a lot of Personal
s, since that will require an extra query per item.
We can let the database do the work for us with a subquery expression:
from django.db.models import OuterRef, Subquery
class PersonalAdmin(admin.ModelAdmin):
list_display = ('lastname', 'firstname', 'highest_degree')
def get_queryset(self, request):
return Personal.objects.annotate(
highest_degree=Subquery(
Degree.objects.filter(
personal=OuterRef('pk')
).order_by('-rank').values('name_degree')[:1]
)
)
@admin.display(description='Highest degree')
def highest_degree(self, obj):
return obj.highest_degree
This will calculate the name of the degrees in bulk.
Upvotes: 1