I have a few models having User as Foreign Key. The User list is displaying the username, but I'd like to customize it. Do I have to extend the User model with a custom model and write my own __str__
function? Is there an easier way? I don't think you can use a callable for fieldset, right?
I think __unicode__()
method is not the correct, you should use __str__()
method.
For Python 2.x
, __str__()
method will return str(bytes) and __unicode__()
method will return unicode (text).
The print statement and the str built-in call
__str__()
to determine the human-readable representation of an object. The unicode built-in calls__unicode__()
if it exists, and otherwise falls back to__str__()
and decodes the result with the system encoding. Conversely, the Model base class automatically derives__str__()
from__unicode__()
by encoding to UTF-8. read here complete
But in Python 3.x
there is just __str__()
, no __unicode__()
method.
Django provides a simple way to define
__str__()
and__unicode__()
methods that work on Python 2 and 3: you must define a__str__()
method returning text and to apply the python_2_unicode_compatible () decorator.On Python 3, the decorator is a no-op. On Python 2, it defines appropriate
__unicode__()
and__str__()
methods (replacing the original__str__()
method in the process).
Here is an example from django docs.
from django.utils.encoding import python_2_unicode_compatible
@python_2_unicode_compatible
class MyClass(object):
def __str__(self):
return "Instance of my class"
SOLUTION : Decorate in the same way, as done above for your Class and in models.py
, add a method which will be get added to the User model.
from django.contrib.auth.models import User
def get_name(self):
return '{} {}'.format(self.first_name, self.last_name)
User.add_to_class("__str__", get_name)
ForeignKeys
in Django forms are represented by ModelChoiceFields
. The ModelChoiceField
class has a label_from_instance
method, which decides how to render the choice. So in order to change this representation in the Admin, you need to modify this form field.
Here is a simple example.
class MyModelAdmin(admin.ModelAdmin):
def formfield_for_foreignkey(self, db_field, request, **kwargs):
field = super(MyModelAdmin, self).formfield_for_foreignkey(db_field, request, **kwargs)
if db_field.name == "user":
field.label_from_instance = lambda u: "My Object #%i" % u.id
return field
You can change the string representation of the Django default User by overriding the User __unicode__
method. Add the code below somewhere in your app, perhaps in models.py
def custom_user_display(self):
return self.email + ', ' self.first_name # write your representation here
User.add_to_class("__unicode__", custom_user_display) # override the __unicode__ method
Assume you have a model like this
class UserProfile(models.Model):
user = models.OneToOneField(User, unique=True, verbose_name=_('user'), related_name='profile')
city = models.CharField(max_length=128, null=True, blank=True)
And you want to show the user's email instead of username or userid in admin page, then you can do something like this
class UserProfileAdmin(admin.ModelAdmin):
list_display = ('get_user', 'city')
def get_user(self, obj):
return obj.user.email
get_user.short_description = 'User'
get_user.admin_order_field = 'user__id'
I had the same problem and I had to extend @Todor 's solution for many models and different apps.
In the end, it was better to override the default AdminSite and hook on register to customize the User form fields.
from django.contrib import admin
from django.contrib.admin import ModelAdmin
from django.contrib.auth import get_user_model
def user_admin_str(instance: get_user_model()) -> str:
return f"{instance.last_name}-chan"
def formfield_for_foreignkey(self, db_field, request, **kwargs):
field = super(ModelAdmin, self).formfield_for_foreignkey(
db_field, request, **kwargs)
if isinstance(db_field.related_model(), get_user_model()):
field.label_from_instance = user_admin_str
return field
def formfield_for_manytomany(self, db_field, request, **kwargs):
field = super(ModelAdmin, self).formfield_for_manytomany(
db_field, request, **kwargs)
if isinstance(db_field.related_model(), get_user_model()):
field.label_from_instance = user_admin_str
return field
class CustomAdminSite(admin.AdminSite):
def register(self, model_or_iterable, admin_class=None, **options):
setattr(admin_class, "formfield_for_foreignkey",
formfield_for_foreignkey)
setattr(admin_class, "formfield_for_manytomany",
formfield_for_manytomany)
super().register(model_or_iterable, admin_class=admin_class, **options)
No need to modify every ModelAdmin
then.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.