I would like to display the model's username in Django Admin interface but not very sure how to do it..
The models.py:
class Adult(models.Model):
user = models.OneToOneField(User)
fullname = models.CharField(max_length=100,
blank=True)
def __unicode__(self):
return self.user.username
Admin.py:
class AdultAdmin(admin.ModelAdmin):
list_display = ('??', 'Student_Name',)
search_fields = ['??',]
admin.site.register(Adult, AdultAdmin)
What should go inside the ?? above ? I would like to display the unicode or the self.user.username? How do i do it? Need some guidance...
From the list_display documentation there are four things you can add there:
A field
Some method (a callable) that accepts one variable that is the instance for which the row is being displayed.
A string that is the name of a method or attribute defined in the model class.
A string that is the name of a method that is defined in ModelAdmin.
For your case we need #3 for list_display.
For search_fields its easier as you can use follow notation (__) to do lookups.
In the end we come up with this:
class AdultAdmin(admin.ModelAdmin):
list_display = ('__unicode__', 'Student_Name',)
search_fields = ['user__username']
Related
I have two related models.
class Refbook(models.Model):
code = models.CharField(max_length=100, unique=True)
name = models.CharField(max_length=300)
description = models.TextField()
class VersionRefbook(models.Model):
refbook_id = models.ForeignKey('Refbook',
on_delete=models.CASCADE,
related_name='versions')
version = models.CharField(max_length=50)
date = models.DateField()
When I edit a Refbook instance in the admin panel, I want the read-only list of available versions of this Refbook instance to be displayed on the same page.
I know that it is possible to output them through TabularInline . And it seems that there is a read-only property here.
Maybe there is a way to display just a list in a column or row separated by commas?
Now, I have this code in admin.py:
#admin.register(Refbook)
class RefbookAdmin(admin.ModelAdmin):
list_display = ['id', 'code', 'name']
I tried to create a "get_versions(self)" method in models.py in Refbook class, in which I received a queryset using related_name. But I can't display it in the admin panel. Or is it still correct to do this using the model.ModelAdmin parameters?
You can do something like this:
#admin.register(Refbook)
class RefbookAdmin(admin.ModelAdmin):
list_display = ['id', 'code', 'name', 'versions']
def versions(self, obj):
return ', '.join(obj.versions.values_list('version', flat=True))
I have these two models:
class User(AbstractUser):
is_teacher = models.BooleanField(default=False, null=False)
class Course(models.Model):
teacher = models.ForeignKey(User, on_delete=models.CASCADE, related_name='teacher_courses')
students = models.ManyToManyField(User, blank=True, related_name='student_courses')
Course model has a ManyToMany field and a ForeignKey to User model. In django's admin page, you are able to see a course's student/teacher. Is there a way to make it as you can have a list of a user's courses in admin page to see/add/remove courses for a user?
You can define a callable on your ModelAdmin class and add it to list_display. To make the courses editable on an user's page use sub classes of InlineModelAdmin.
class TeacherCourseInlineAdmin(admin.TabularInline):
model = Course
fk_name = "teacher"
class StudentCourseInlineAdmin(admin.TabularInline):
model = Course
fk_name = "student"
class UserAdmin(admin.ModelAdmin):
list_display = ("username", "teacher_courses")
inlines = [TeacherCourseInlineAdmin, StudentCourseInlineAdmin]
def get_queryset(self, *args, **kwargs):
return super().get_queryset(*args, **kwargs).prefetch_related("teacher_courses")
#admin.display(description='Courses')
def teacher_courses(self, user):
return [c.name for c in user.teacher_courses.all()]
Note that it makes sense to override ModelAdmin.get_queryset() to add a call to prefetch_related() so that Django fetches all related courses in one extra query instead of performing one additional query for every user object.
These are my models:
class Partner(models.Model):
name = models.CharField(max_length=200, verbose_name="Organisation name")
class ResearchActivity(models.Model):
title = models.CharField(max_length=200)
partner = models.ManyToManyField(ActivityPartner, blank=True)
I'd like, in the Django administration forms, to have a field in my Partner edit form representing the ResearchActivity linked to that Partner.
Can this be achieved by adding a field to my Partner model (say, naming it linked_partner) and then edit my admin.py like so:
#admin.register(ActivityPartner)
class ActivityPartnerAdmin(admin.ModelAdmin):
search_fields = ['academic',]
autocomplete_fields = ['partnership_type', 'relationship_type', 'academic_links']
def get_changeform_initial_data(self, request):
return {'live_contract': ResearchActivity.objects.all().filter(linked_partner__id=request.ResearchActivity.partner.id)}
?
I have just come across in the display() decorator, new from Django 3.2. With it, I can simply do:
#admin.register(ActivityPartner)
class ActivityPartnerAdmin(admin.ModelAdmin):
search_fields = ['academic',]
autocomplete_fields = ['partnership_type', 'relationship_type', 'academic_links',]
readonly_fields = ('get_ra',)
#admin.display(description='Live contract(s)')
def get_ra(self, obj):
return list(ResearchActivity.objects.filter(partner=obj.id))
to achieve what I want.
If I also wanted to edit those ManyToMany relations, I can use the inlines option:
class LiveContractsInline(admin.TabularInline):
model = ResearchActivity.partner.through
#admin.register(ActivityPartner)
class ActivityPartnerAdmin(admin.ModelAdmin):
inlines = [
LiveContractsInline,
]
I have a simple Model like this:
class Artist(models.Model):
class Meta:
verbose_name = "Artist"
verbose_name_plural = "Artists"
name = models.CharField(max_length=128, unique=True, blank=False)
def test_function(self):
return 'xyz'
And Admin:
class ArtistAdmin(admin.ModelAdmin):
list_display = ['name', 'test_function']
search_fields = ['name']
readonly_fields = []
Now in the list view, the function field is verbosed as TEST_FUNCTION:
In a normal field I would use the Field.verbose_name parameter.
How do I achieve that with the function field?
In object terms thinking, I would try to return a mocked CharField instead of a simple string. Would this work somehow?
As per the documentation, you can give the function an attribute called short_description:
class PersonAdmin(admin.ModelAdmin):
list_display = ('upper_case_name',)
def upper_case_name(self, obj):
return ("%s %s" % (obj.first_name, obj.last_name)).upper()
upper_case_name.short_description = 'Name'
If set, the Django Admin will show this description rather than the function name. Even better, change it into _('Name') to allow for different translations!
I have a many to many field like this:
class Retailer(models.Model):
name = models.CharField(max_length=100, db_index=True)
city_gps = models.ManyToManyField(City, blank=True, related_name='retailers', db_index=True)
def __str__(self):
retailer_city = ""
if self.city_gps:
retailer_city = self.city_gps.all().first().name
return slugify(self.name) + slugify(retailer_city)
I would like the admin to show a combination of the name and all related cities. However, when I set the admin to show this field like this:
class RetailerAdmin(admin.ModelAdmin):
search_fields = ['name']
list_display = ['name', 'city_gps', 'icon_tag', 'logo_tag', 'header_tag']
I get the error:
: (admin.E109) The value of
'list_display[1]' must not be a ManyToManyField.
So, how can I solve this? Is there a way to show the value of the __str__ method in the the admin?
As said in the docs for list_display in Django:
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.)
So you can define this custom method either in your models.py or (I think the more explicit way), directly in your admin.py:
class RetailerAdmin(admin.ModelAdmin):
search_fields = ['name']
list_display = ['name', 'icon_tag', 'logo_tag', 'header_tag', 'retailer_city']
def retailer_city(self, obj):
city_gps = obj.city_gps
retailer_city = city_gps.all().first().name if city_gps else ''
return slugify(obj.name) + slugify(retailer_city)
Note that retailer_city is added in list_display.