首页 文章

扩展auth.User模型,代理字段和Django管理员

提问于
浏览
1

(编辑:我知道Django中有一个完全独立的功能称为“代理模型” . 该功能对我没有帮助,因为我需要能够向UserProfile添加字段 . )

所以我正在开始一个新的Django应用程序,我正在创建一个UserProfile模型,它是django.contrib.auth.models.User的扩展,并且失败的属性请求返回给User,如下所示:

from django.db import models
from django.contrib.auth.models import User

class UserProfile(models.Model):
    user = models.OneToOneField(User, related_name='profile')

    def __getattr__(self, name, *args):
        if name == 'user' or name == '_user_cache':
            raise AttributeError(name)

        try:
            return getattr(self.user, name, *args)
        except AttributeError, e:
            raise AttributeError(name)

这通常很好,但是当我尝试在UserProfileAdmin.list_display中使用 User 字段时会中断 . 问题在于管理验证代码:

def validate(cls, model):
    """
    Does basic ModelAdmin option validation. Calls custom validation
    classmethod in the end if it is provided in cls. The signature of the
    custom validation classmethod should be: def validate(cls, model).
    """
    # Before we can introspect models, they need to be fully loaded so that
    # inter-relations are set up correctly. We force that here.
    models.get_apps()

    opts = model._meta
    validate_base(cls, model)

    # list_display
    if hasattr(cls, 'list_display'):
        check_isseq(cls, 'list_display', cls.list_display)
        for idx, field in enumerate(cls.list_display):
            if not callable(field):
                if not hasattr(cls, field):
                    if not hasattr(model, field):
                        try:
                            opts.get_field(field)
                        except models.FieldDoesNotExist:
                            raise ImproperlyConfigured("%s.list_display[%d], %r is not a callable or an attribute of %r or found in the model %r."
                                % (cls.__name__, idx, field, cls.__name__, model._meta.object_name))

问题是,虽然UserProfile的实例将具有代理字段,例如电子邮件,UserProfile类本身没有 . 在Django shell中演示:

>>> hasattr(UserProfile, 'email')
False
>>> hasattr(UserProfile.objects.all()[0], 'email')
True

经过一番挖掘,看起来我想要为UserProfile._meta覆盖django.db.models.options.Options.get_field . 但似乎没有一种非hacky方式来做到这一点(我现在有一个非常hacky的解决方案,涉及猴子修补UserProfile._meta . [get_field,get_field_by_name])...任何建议?谢谢 .

3 回答

  • 2

    把事情简单化 . 以下是我们使用的库中UserProfile模型的示例:

    class UserProfile(models.Model):
        user = models.OneToOneField(User)
        accountcode = models.PositiveIntegerField(null=True, blank=True)
    

    's it. Don'打扰了 __getattr__ 覆盖 . 改为自定义管理界面:

    from django.contrib.auth.admin import UserAdmin
    from django.contrib.auth.models import User
    
    class UserProfileInline(admin.StackedInline):
        model = UserProfile
    
    class StaffAdmin(UserAdmin):
        inlines = [UserProfileInline]
        # provide further customisations here
    
    admin.site.register(User, StaffAdmin)
    

    这允许您CRUD User 对象,可以访问UserProfile作为内联 . 现在,您不必将UserProfile中的属性查找代理到User模型 . 要从 User u 的实例访问 UserProfile ,请使用 u.get_profile()

  • 0

    这不是代理类,而是一种关系 . 在Proxy Model上查看更多信息,这是原始模型的子类, Meta.proxy = True

  • 0

    如果您只想让User中的字段位于UserProfileAdmin中的list_display中,请尝试:

    class UserProfileAdmin(admin.ModelAdmin):
        list_display = ('user__email',)
    

    如果您希望将其作为表单的一部分,请将其作为额外字段添加到UserProfileForm中,并在表单中对其进行验证 .

相关问题