I am getting back into Django after a few years, and am running into the following problem. I am making a system where there are 2 models; a survey, and an update. I want to make a notification model that would automatically have an object added when I add a survey object or update object, and the notification object would have a foreign key to the model object which caused it to be added.
However I am running into a brick wall figuring out how I would do this, to have a model with a foreign key which can be to one of two models, which would be automatically set to the model object which creates it. Any help with this would be appreciated.
I am trying to make a model that looks something like this (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)
Also, just to add some context to the question and in case I am looking at this from the wrong angle, I am wanting to do this because both surveys and updates will be displayed on the same page, so my plan is to query the notification model, and then have the view do something like this:
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()
I am also doing this instead of combining the 2 queries and then sorting them by date as I want to have notifications for each specific user anyways, so my plan is (down the road) to have a notification created for each user.
Here are my models (that I reference in the question):
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'
GenericForeignKey
to the rescue:
A normal ForeignKey can only “point to” one other model, which means that if the TaggedItem model used a ForeignKey it would have to choose one and only one model to store tags for. The contenttypes application provides a special field type (GenericForeignKey) which works around this and allows the relationship to be with any model
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")
EDIT:
How to use
survey_object = survery_question.objects.first()
notification_for_survey = notification.objects.create(source=survey_object)
update_object = update.objects.first()
notification_for_update = notification.objects.create(source=update_object)