2010-10-28 3 views
1

У меня есть несколько моделей профилей пользователей, унаследованных от одного базового класса, как это:Джанго: Доступ к Дочерний класс абстрактной модели

class BaseProfile(models.Model): 
    user = models.ForeignKey(User) 
    name = models.CharField(max_length=100) 
    ... 
    class Meta: 
     abstract = True 

class DoctorProfile(BaseProfile): 
    license_no = models.CharField(max_length=10) 
    ... 

class PharmacistProfile(BaseProfile): 
    pass 

Когда у меня есть пользовательский экземпляр, я хотел бы получить свой профиль.

Мне не хочется проверять, имеет ли пользователь профиль один за другим с помощью sth. например:

if user.doctorprofile_set.all().count() == 1: 
    return user.doctorprofile_set.all()[0] 
elif user.pharmacistprofile_set.all().count() == 1: 
    return user.pharmacistprofile_set.all()[0] 
... 

для каждого профиля - лучший способ, поскольку он не является СУХОЙ и требует дополнительных запросов в базе данных.

Каков наилучший способ для этого?

редактировать: бы неплохо определить AUTH_PROFILE_MODULE в настройках, чтобы указать на базовую модель, как AUTH_PROFILE_MODULE = 'profiles.baseprofile' и быть в состоянии использовать user.get_profile() на каждом пользователе с различными классами профилей, полученных из того же базового профиля.

+0

Могу ли я спросить почему вы решили использовать наследование, а не состав или агрегацию, как ваш способ разграничения между разными типами пользователей? Почему бы ни один класс профиля с флагом «is_a» не был правильным способом? Тогда вы можете использовать get_profile(), с одной стороны. –

+0

Пример, который я предоставляю, является упрощенным. В реальном случае существует около 10 различных типов профилей со многими обычными и необычными атрибутами. Чтобы сохранить модели DRY, наследование кажется мне более естественным. И даже если бы я использовал композицию, я считаю, что у меня все еще будет такая же проблема при попытке получить профиль для пользователя, не так ли? – omat

ответ

1

Сделать это OneToOneField вместо FK затем сделать user.doctorprofile и т.д. OneToOne выбросит Foo.DoesNotExist или Foo.MultipleObjectsReturned, хотя, если что-то пойдет не так, так что будьте готовы, чтобы поймать эти исключения

+0

спасибо, это сделает вещи более аккуратными. но этот подход требует запроса каждой возможности профиля один за другим, что означает дополнительные обращения к базе данных и не очень сухие, потому что, если вводится новый профиль, в код, который извлекает профили, должен быть добавлен другой блок ... кроме блока. было бы неплохо использовать get_profile() в классе BaseProfile. я обновлю свой вопрос. – omat

+1

Я не сказал, что это было прекрасно. По-моему, расширение модели User в Django не станет приятнее до 1.3/1.4. И вы всегда можете добавить код (как и я), который кэширует профиль в первый раз, когда это необходимо, а затем делает недействительным его ключ, когда модель снова сохраняется. –

+0

Ну, я пришел из будущего, чтобы сказать, что до Django 1.9 у нас ничего нет даже близко к этому. –

Смежные вопросы