Внешний ключ модели Django для той модели, которая его вызывает

Я возвращаюсь к Django после нескольких лет работы и столкнулся со следующей проблемой. Я создаю систему, в которой есть 2 модели: опрос и обновление. Я хочу сделать модель уведомлений, в которую автоматически добавлялся бы объект при добавлении объекта опроса или обновления, а объект уведомления имел бы внешний ключ к объекту модели, который вызвал его добавление.

Однако я натыкаюсь на кирпичную стену, пытаясь понять, как мне это сделать, чтобы иметь модель с внешним ключом, который может относиться к одной из двух моделей, и который будет автоматически устанавливаться на объект модели, который его создает. Любая помощь в этом вопросе будет оценена по достоинству.

Я пытаюсь создать модель, которая выглядит примерно так (psuedocode):

class notification(models.model):
     source = models.ForeignKey(to model that created it) #this is what I need help with
     start_date = models.DateTimeField(inherited from model that created it)
     end_date = models.DateTimeField(inherited from model that created it)

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

from .models import notification

notifications = notification.objects.filter(start_date__lte=now, end_date__gte=now).order_by('-start_date')

for notification in notifications:
     if notification.__class__.__name__ == "survey_question":
          survey = notification.survey_question.all()
          question = survey.question()
     elif notification.__class__.__name__ == "update":
          update = notification.update.all()
          update = update.update()

Я также делаю это вместо того, чтобы объединять 2 запроса и затем сортировать их по дате, поскольку я хочу иметь уведомления для каждого конкретного пользователя, так что мой план состоит в том, чтобы (в дальнейшем) иметь уведомление, созданное для каждого пользователя.

Вот мои модели (на которые я ссылаюсь в вопросе):

from django.db import models
from datetime import timedelta
from django.utils import timezone

def tmrw():
    return timezone.now() + timedelta(days=1)

class update(models.Model):
    update = models.TextField()
    start_date = models.DateTimeField(default=timezone.now, null=True, blank=True)
    end_date = models.DateTimeField(default=tmrw, null=True, blank=True)

    class Meta:
        verbose_name = 'Update'
        verbose_name_plural = f'{verbose_name}s'

class survey_question(models.Model):
    question = models.TextField()
    start_date = models.DateTimeField(default=timezone.now, null=True, blank=True)
    end_date = models.DateTimeField(default=tmrw, null=True, blank=True)

    class Meta:
        verbose_name = 'Survey'
        verbose_name_plural = f'{verbose_name}s'

Возможно, существует какой-то контекст, в котором это может понадобиться, и способ его реализации, однако я не вижу ни того, ни другого. source = models.ForeignKey(to model that created it) будет pk той модели, которая его создала , но тогда это означает, что source может иметь дублирующее значение, одно, когда экземпляр notification создается update, и, возможно, то же самое значение, когда экземпляр notification создается survey_question. В конце концов, фактическое значение pk, в вашем случае просто целое число, может быть одинаковым как для экземпляра update, так и для экземпляра survey_question.

Не совсем понятно, почему нельзя просто добавить в опрос еще одно поле, указывающее, было ли это обновление или опрос. Это также устранило бы необходимость в отдельной модели уведомлений.

class SurveyQuestion(models.Model):    # Note use of PascalCase for class name

    SURVEY = "SV"
    UPDATE = "UP"

    SURVEY_TYPE_CHOICES = {
        SURVEY: "Survey",
        UPDATE: "Update",
    }
    survey_type = models.CharField(
        max_length=2,
        choices=SURVEY_TYPE_CHOICES,
        default=SURVEY,
    )
    question = models.TextField()
    start_date = models.DateTimeField(default=timezone.now, null=True, blank=True)
    end_date = models.DateTimeField(default=tmrw, null=True, blank=True)

Тогда вы можете легко отфильтровать по survey_type.

GenericForeignKey на помощь:

Обычный ForeignKey может «указывать» только на одну другую модель, что означает, что если бы модель TaggedItem использовала ForeignKey, то ей пришлось бы выбрать одну и только одну модель для хранения тегов. Приложение contenttypes предоставляет специальный тип поля (GenericForeignKey), который позволяет обойти эту проблему и установить связь с любой моделью

.
from django.contrib.contenttypes.fields import GenericForeignKey
from django.contrib.contenttypes.models import ContentType

class notification(models.model):
    content_type = models.ForeignKey(ContentType, on_delete=models.CASCADE)
    object_id    = models.PositiveIntegerField()
    source       = GenericForeignKey("content_type", "object_id")
Вернуться на верх