Внешний ключ модели 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")