Джанго - условный внешний ключ - PullRequest
0 голосов
/ 05 мая 2018

В моей программе 4 модели: пользователь, бренд, агентство и создатель.

Пользователь является надмножеством бренда, агентства и создателя.

Пользователь может быть брендом, агентством или создателем. Они не могут взять на себя более одной роли. Их роль определяется свойством accountType. Если они не установлены (то есть 0), то формальной связи не существует.

Как мне выразить это в моей модели?

Модель пользователя

class User(models.Model):
    id = models.UUIDField(primary_key=True, default=uuid4, editable=False)
    email = models.EmailField(max_length=255, null=True, default=None)
    password = models.CharField(max_length=255, null=True, default=None)
    ACCOUNT_CHOICE_UNSET = 0
    ACCOUNT_CHOICE_BRAND = 1
    ACCOUNT_CHOICE_CREATOR = 2
    ACCOUNT_CHOICE_AGENCY = 3
    ACCOUNT_CHOICES = (
        (ACCOUNT_CHOICE_UNSET, 'Unset'),
        (ACCOUNT_CHOICE_BRAND, 'Brand'),
        (ACCOUNT_CHOICE_CREATOR, 'Creator'),
        (ACCOUNT_CHOICE_AGENCY, 'Agency'),
    )
    account_id = models.ForeignKey(Brand)
    account_type = models.IntegerField(choices=ACCOUNT_CHOICES, default=ACCOUNT_CHOICE_UNSET)

    class Meta:
        verbose_name_plural = "Users"

    def __str__(self):
        return "%s" % self.email

Марка модели

class Brand(models.Model):
    id = models.UUIDField(primary_key=True, default=uuid4, editable=False)
    name = models.CharField(max_length=255, null=True, default=None)
    brand = models.CharField(max_length=255, null=True, default=None)
    email = models.EmailField(max_length=255, null=True, default=None)
    phone = models.CharField(max_length=255, null=True, default=None)
    website = models.CharField(max_length=255, null=True, default=None)

    class Meta:
        verbose_name_plural = "Brands"

    def __str__(self):
        return "%s" % self.brand

Создатель модели

class Creator(models.Model):
    id = models.UUIDField(primary_key=True, default=uuid4, editable=False)
    first_name = models.CharField(max_length=255, null=True, default=None)
    last_name = models.CharField(max_length=255, null=True, default=None)
    email = models.EmailField(max_length=255, null=True, default=None)
    youtube_channel_username = models.CharField(max_length=255, null=True, default=None)
    youtube_channel_url = models.CharField(max_length=255, null=True, default=None)
    youtube_channel_title = models.CharField(max_length=255, null=True, default=None)
    youtube_channel_description = models.CharField(max_length=255, null=True, default=None)
    photo = models.CharField(max_length=255, null=True, default=None)
    youtube_channel_start_date = models.CharField(max_length=255, null=True, default=None)
    keywords = models.CharField(max_length=255, null=True, default=None)
    no_of_subscribers = models.IntegerField(default=0)
    no_of_videos = models.IntegerField(default=0)
    no_of_views = models.IntegerField(default=0)
    no_of_likes = models.IntegerField(default=0)
    no_of_dislikes = models.IntegerField(default=0)
    location = models.CharField(max_length=255, null=True, default=None)
    avg_views = models.IntegerField(default=0)
    GENDER_CHOICE_UNSET = 0
    GENDER_CHOICE_MALE = 1
    GENDER_CHOICE_FEMALE = 2
    GENDER_CHOICES = (
        (GENDER_CHOICE_UNSET, 'Unset'),
        (GENDER_CHOICE_MALE, 'Male'),
        (GENDER_CHOICE_FEMALE, 'Female'),
    )
    gender = models.IntegerField(choices=GENDER_CHOICES, default=GENDER_CHOICE_UNSET)

    class Meta:
        verbose_name_plural = "Creators"

    def __str__(self):
        return "%s %s" % (self.first_name,self.last_name)

Модель агентства

class Agency(models.Model):
    id = models.UUIDField(primary_key=True, default=uuid4, editable=False)
    name = models.CharField(max_length=255, null=True, default=None)
    agency = models.CharField(max_length=255, null=True, default=None)
    email = models.EmailField(max_length=255, null=True, default=None)
    phone = models.CharField(max_length=255, null=True, default=None)
    website = models.CharField(max_length=255, null=True, default=None)

    class Meta:
        verbose_name_plural = "Agencies"

    def __str__(self):
        return "%s" % self.agency

Обновление:

Итак, я урезал это здесь, в модели:

ACCOUNT_CHOICE_UNSET = 0
ACCOUNT_CHOICE_BRAND = 1
ACCOUNT_CHOICE_CREATOR = 2
ACCOUNT_CHOICE_AGENCY = 3
ACCOUNT_CHOICES = (
    (ACCOUNT_CHOICE_UNSET, 'Unset'),
    (ACCOUNT_CHOICE_BRAND, 'Brand'),
    (ACCOUNT_CHOICE_CREATOR, 'Creator'),
    (ACCOUNT_CHOICE_AGENCY, 'Agency'),
)
account_type = models.IntegerField(choices=ACCOUNT_CHOICES, default=ACCOUNT_CHOICE_UNSET)
limit = models.Q(app_label='api', model='Brand') | \
        models.Q(app_label='api', model='Creator') | \
        models.Q(app_label='api', model='Agency')
content_type = models.ForeignKey(ContentType, limit_choices_to=get_content_type_choices(), related_name='user_content_type')
content_object = GenericForeignKey('content_type', 'email')
  • Если account_type = 1, тогда ссылка на модель бренда
  • Если account_type = 2, тогда ссылка на модель создателя
  • Если account_type = 3, тогда ссылка на модель агентства

Как мне это сделать? Получение этой ошибки:

  File "/Users/projects/adsoma-api/api/models.py", line 7, in <module>
    class User(models.Model):
  File "/Users/projects/adsoma-api/api/models.py", line 28, in User
    content_type = models.ForeignKey(ContentType, limit_choices_to=get_content_type_choices(), related_name='user_content_type')
NameError: name 'get_content_type_choices' is not defined

1 Ответ

0 голосов
/ 05 мая 2018

Вы пытались исследовать поле GenericForeignKey Джанго?

class User(models.Model):
    ...
    limit = models.Q(app_label='your_app_label', model='brand') | 
            models.Q(app_label='your_app_label', model='creator') | 
            models.Q(app_label='your_app_label', model='agency')
    content_type = models.ForeignKey(ContentType, limit_choices_to=limit, related_name='user_content_type')
    object_id = models.UUIDField()
    content_object = GenericForeignKey('content_type', 'object_id')

Вы можете получить доступ к бренду / создателю / агентству пользователя, используя следующую запись:

User.objects.get(pk=1).content_object

Это будет экземпляр Brand / Creator / Agency согласно content_type.

https://docs.djangoproject.com/en/stable/ref/contrib/contenttypes/#django.contrib.contenttypes.fields.GenericForeignKey

Обновление на основе вашего комментария

Re 1: Использование электронной почты:

class User(models.Model):
    ...
    email = models.EmailField(max_length=255, unique=True)
    limit = models.Q(app_label='your_app_label', model='brand') | 
            models.Q(app_label='your_app_label', model='creator') | 
            models.Q(app_label='your_app_label', model='agency')
    content_type = models.ForeignKey(ContentType, limit_choices_to=get_content_type_choices, related_name='user_content_type')
    content_object = GenericForeignKey('content_type', 'email')

Примечание: электронная почта не может быть пустым полем, если вы используете этот подход! Также этот подход кажется ошибочным / неправильным, поскольку поле email теперь объявлено в нескольких местах; и значение может измениться, если вы переназначите объекты содержимого. Намного понятнее связать GenericForeignKey с помощью дискретного UUIDField на каждой из трех других моделей

Re 2: Использование поля account_type:

ContentType, как ожидается, будет ссылкой на модель Джанго; поэтому он требует выбора моделей, а не целых чисел. Функция limit_choices_to состоит в том, чтобы выполнить фильтрацию таким образом, чтобы все возможные модели не отображались как потенциальные GenericForeignKey

class ContentType(models.Model):
    app_label = models.CharField(max_length=100)
    model = models.CharField(_('python model class name'), max_length=100)
    objects = ContentTypeManager()

Однако limit_choices_to принимает вызовы; так что вы можете написать вспомогательный метод, который переведет ваш account_type в правильный Model

Мне не ясно, как должен работать этот переход; так что я оставляю это тебе.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...