[英]How to change User representation in Django Admin when used as Foreign Key?
我有几个模型将用户作为外键。 用户列表显示用户名,但我想对其进行自定义。 我是否必须使用自定义 model 扩展用户 model 并编写自己的__str__
function? 有没有更简单的方法? 我不认为你可以使用可调用的字段集,对吧?
我认为__unicode__()
方法不正确,你应该使用__str__()
方法。
对于Python 2.x
, __str__()
str __str__()
方法将返回str(bytes)和__unicode__()
方法将返回unicode(文本)。
print语句和str内置调用
__str__()
来确定对象的人类可读表示。 unicode内置调用__unicode__()
如果存在),否则返回__str__()
并使用系统编码解码结果。 相反,Model基类通过编码为UTF-8自动从__unicode__()
派生__str__()
。 在这里阅读完整
但是在Python 3.x
中只有__str__()
,没有__unicode__()
方法。
Django提供了一种简单的方法来定义适用于Python 2和3的
__str__()
和__unicode__()
方法:您必须定义一个__str__()
方法返回文本并应用python_2_unicode_compatible ()装饰器。在Python 3上,装饰器是无操作的。 在Python 2上,它定义了适当的
__unicode__()
和__str__()
方法(替换了进程中的原始__str__()
方法)。
这是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"
解决方案:以相同的方式进行装饰,如上面针对您的类和models.py
所做的那样,添加一个将添加到User模型的方法。
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)
Django表单中的ForeignKeys
由ModelChoiceFields
表示。 ModelChoiceField
类有一个label_from_instance
方法,该方法决定如何呈现选择。 因此,为了在Admin中更改此表示,您需要修改此表单字段。
这是一个简单的例子。
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
您可以通过覆盖User __unicode__
方法来更改Django默认用户的字符串表示形式。 在应用中的某个位置添加代码,也许在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
假设你有这样的模型
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)
并且您想在管理页面中显示用户的电子邮件而不是用户名或用户ID,然后您可以执行此类操作
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'
我遇到了同样的问题,我不得不为许多模型和不同的应用程序扩展@Todor 的解决方案。
最后,最好覆盖默认的 AdminSite并挂钩注册以自定义用户表单字段。
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)
然后不需要修改每个ModelAdmin
。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.