I am trying to wrap my head around the usage of a GenericForeignKey, and I am looking for better understanding (or confirmation I am understanding it correctly).
Context
I have three models: Enterprise, Establishment and Activity.
One can quickly reason that Enterprise - Establishment are a one-to-many relation. Activities however, are bound to a specific Establishment, if a Establishment exists. If not, then to an Enterprise (that has only one establishment and thus is not mentioned in Establishment).
Quick example:
Company A has one establishment that sells food, thus this activity entry with label “food” should have a ForeignKey to Enterprise.
Company B has two branches/establishments, one sells tools, another sells wood. The activity labels in this case will have a ForeignKey to the Establishment, and not (directly) to the Enterprise.
With this in mind
from django.contrib.contenttypes.fields import GenericForeignKey
from django.contrib.contenttypes.models import ContentType
from django.db import models
class Enterprise(models.Model):
"""An active enterprise."""
enterprise_id = models.CharField(
primary_key=True,
max_length=14,
help_text="Enterprise ID."
)
status = models.CharField(
max_length=2,
help_text="Status."
)
class Establishment(models.Model):
"""A local establishment of an existing enterprise."""
establishment_id = models.CharField(
primary_key=True,
max_length=14,
help_text="Establishment ID"
)
enterprise_id = models.ForeignKey(
Enterprise, on_delete=models.CASCADE
)
class Activity(models.Model):
"""Description of activity."""
limit = models.Q(app_label='api_nbb', model="enterprise") | models.Q(app_label='api_nbb', model="establishment")
entity = models.ForeignKey(
ContentType,
on_delete=models.CASCADE,
limit_choices_to=limit
)
object_id = models.CharField()
content_object = GenericForeignKey("entity", "object_id")
activity_tag = models.CharField(
max_length=10,
help_text="Short description for activity."
)
Let us pretend I do:
try:
x = Enterprise.objects.get(enterprise_id="1234")
except Enterprise.DoesNotExist:
x = Establishment.objects.get(establishment_id="1234")
activity = Activity(content_object=x, activity_tag="wood")
activity.save()
To me it seems that:
- An activity does not actually refer, in the DB at least, to the instance/row in table Enterprise/Establishment, but is rather a compound key of a class instance of either Enterprise/Establishment, and said instances attribute, in this case the
activity_tag
valuedwood
. - The
on_delete=models.CASCADE
is unnecessary, since it is not linked to an entry in tables Enterprise/Establishment but to the existence of the (Django) models Enterprise/Establishment underdjango_content_type
.
Are both mine assumptions correct here?
And (I know open question but I don’t expect an explanation, rather a nudge or pointer) considering the context, is this a legitimate use of the GenericForeignKey or should I use another strategy when later, I want to identify all information of one Enterprise? (in which case, I’ll have to write a custom query for the activities, I assume).
Thank you for any help and I have to say, new to Django but already a fan!