#python #django #django-models #django-rest-framework
#python #django #django-модели #django-rest-framework
Вопрос:
Я создаю серверную часть DRF с тремя типами пользователей: клиент, персональный тренер и владелец тренажерного зала. Я хочу, чтобы все поля в классе CustomUser применялись к каждому типу пользователя. Мне также нужны некоторые специфические атрибуты для каждого типа пользователя (например, фотография только для личного тренера и владельца тренажерного зала). Это правильный способ сделать это?
# models.py
class CustomUser(AbstractUser):
USER_TYPE_CHOICES = (
('customer'),
('personal_trainer'),
('gym_owner'),
)
user_type = models.CharField(blank=False, choices=USER_TYPE_CHOICES)
name = models.CharField(blank=False, max_length=255)
country = models.CharField(blank=False, max_length=255)
city = models.CharField(blank=False, max_length=255)
phone = models.CharField(blank=True, max_length=255)
ratings = models.ForeignKey(Rating, on_delete=models.CASCADE, null=True)
created_at = models.DateField(auto_now_add=True)
def __str__(self):
return self.name
class Customer(models.Model):
user = models.OneToOneField(
CustomUser, on_delete=models.CASCADE, primary_key=True)
class PersonalTrainer(models.Model):
user = models.OneToOneField(
CustomUser, on_delete=models.CASCADE, primary_key=True)
photo = models.ImageField(upload_to='photos/%Y/%m/%d/', blank=True)
class GymOwner(models.Model):
user = models.OneToOneField(
CustomUser, on_delete=models.CASCADE, primary_key=True)
photo = models.ImageField(upload_to='photos/%Y/%m/%d/', blank=True)
У меня также есть модель рейтингов. Я хочу иметь возможность оставлять рейтинг в качестве клиента личному тренеру или тренажерному залу. Каждый рейтинг будет иметь отношение один к одному с его владельцем и его целью. Однако я не уверен, как я могу установить отношения ..?
# models.py
class Rating(models.Model):
STAR_CONVERSION = (
(1, 'One Star'),
(2, 'Two Stars'),
(3, 'Three Stars'),
(4, 'Four Stars'),
(5, 'Five Stars'),
)
rating = models.PositiveSmallIntegerField(choices=STAR_CONVERSION)
caption = models.TextField(blank=True)
owner = models.OneToOneField(Customer, on_delete=models.CASCADE)
# I want a target as a one to one relation to either PersonalTrainer or GymOwner
target = models.OneToOneField(*either personal trainer or gym owner*)
Ответ №1:
Вам нужно сделать оба owner
и target
ForeignKey
вместо OneToOneField
a. С последним вы могли бы иметь только один рейтинг для каждого клиента и один для каждого поставщика, что было бы немного ограничительно :).
Для PersonalTrainer
и GymOwner
вам необходимо наследование модели. Родительская модель должна быть либо абстрактным классом (с данными, сохраненными в таблицах отдельных дочерних моделей), либо (предпочтительно в этом случае, поскольку поля обеих моделей одинаковы) данные будут сохранены в родительской модели (например, Provider
), в то время как дочерние модели будут прокси-моделями, основанными на данных родительской модели, но обеспечивающими другое поведение, где это уместно.
В документах Django довольно много говорится о различных вариантах наследования.
class Provider(models.Model):
user = models.OneToOneField(
CustomUser, on_delete=models.CASCADE, primary_key=True)
photo = models.ImageField(upload_to='photos/%Y/%m/%d/', blank=True)
class PersonalTrainer(Provider):
class Meta:
proxy = True
class GymOwner(Provider):
class Meta:
proxy = True
class Rating(models.Model):
# ...
owner = models.ForeignKey(Customer, on_delete=models.CASCADE)
target = models.ForeignKey(Provider, on_delete=models.CASCADE)
Комментарии:
1. Поскольку
owner
иtarget
являются полями FK, возможно, придется подумать о введении некоторогоunique_together
ограничения. Если только не требуется разрешить одному и тому же клиенту «проверять-бомбить» одного и того же поставщика, то есть. Даже если рейтинг будет дополнительно привязан к дате или определенному курсу, я чувствую, что разрешить более одного рейтинга для каждого клиента, поставщика и контекста звучит неправильно.2. @shmee Это важное соображение, да. Если вам нужен только один отзыв на пару клиент / поставщик,
unique_together
достаточно; для других ограничений (например, один отзыв в течение определенного времени и т.д.) Вам нужен либо код Python, либо дополнительные поля модели.