(Правка: я знаю, что в Django есть совершенно отдельная функция, называемая "Proxy Models". Эта функция мне не помогает, потому что мне нужно иметь возможность добавлять поля в UserProfile.)
ИтакЯ запускаю новое приложение Django и создаю модель UserProfile, которая является расширением django.contrib.auth.models.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)
В целом это работает нормально, но ломается, когда я пытаюсь использовать поле User
в UserProfileAdmin.list_display.Проблема в коде проверки администратора здесь:
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:
>>> hasattr(UserProfile, 'email')
False
>>> hasattr(UserProfile.objects.all()[0], 'email')
True
После некоторого копания похоже, что я бы хотел переопределить django.db.models.options.Options.get_field для UserProfile._meta.Но, похоже, не существует нехакерского способа сделать это (у меня сейчас очень хакерское решение, которое включает в себя мартовское исправление UserProfile._meta. [Get_field, get_field_by_name]) ... какие-нибудь предложения?Спасибо.