(编辑:我知道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])...任何建议?感谢。
答案 0 :(得分:2)
保持简单。以下是我们使用的库中UserProfile模型的示例:
class UserProfile(models.Model):
user = models.OneToOneField(User)
accountcode = models.PositiveIntegerField(null=True, blank=True)
就是这样。不要打扰__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模型。要从UserProfile
的实例访问User u
,请使用u.get_profile()
答案 1 :(得分:0)
这不是代理类,而是一种关系。详情请见Proxy Model s,它是原始模型的子类,Meta.proxy = True
答案 2 :(得分:0)
如果您只想让User中的某个字段位于UserProfileAdmin中的list_display中,请尝试:
class UserProfileAdmin(admin.ModelAdmin):
list_display = ('user__email',)
如果您希望将其作为表单的一部分,请将其作为额外字段添加到UserProfileForm中,并在表单中对其进行验证。