如何在Django Admin中改变用户表示作为外键使用?

nx7onnlm  于 2022-12-14  发布在  Go
关注(0)|答案(5)|浏览(120)

我有一些模型有用户作为外键。用户列表显示用户名,但我想定制它。我必须用定制模型扩展用户模型并编写我自己的__str__函数吗?有更简单的方法吗?我不认为你可以使用fieldset的可调用对象,对吗?

qyzbxkaa

qyzbxkaa1#

我认为__unicode__()方法不正确,您应该使用__str__()方法。
对于Python 2.x__str__()方法将返回str(字节),__unicode__()方法将返回unicode(文本)。
print语句和str内置函数调用__str__()来确定对象的人类可读表示。unicode内置函数调用__unicode__()(如果存在),否则福尔斯__str__()并使用系统编码解码结果。相反,Model基类通过编码为UTF-8自动从__unicode__()派生__str__()。阅读此处完成
但是在Python 3.x中只有__str__(),没有__unicode__()方法。
Django提供了一种简单的方法来定义__str__()__unicode__()方法,这些方法可以在Python 2和3上工作:你必须定义一个__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中,添加一个将被添加到用户模型中的方法。

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)
3npbholx

3npbholx2#

Django表单中的ForeignKeysModelChoiceFields表示。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
vuktfyat

vuktfyat3#

你可以通过重写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
utugiqy6

utugiqy64#

假设您有一个类似的模型

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'
eqzww0vc

eqzww0vc5#

我也遇到了同样的问题,我不得不将@Todor的解决方案扩展到许多型号和不同的应用程序。
最后,最好覆盖默认的AdminSite并挂钩register以定制User表单字段。

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了。

相关问题