0 day streak
python / expert
Snippet

Django ContentType Framework for Generic Relations

Django's ContentType framework enables generic relations, allowing a single Comment model to attach to any other model without creating separate foreign keys. This is ideal for building reusable components like comments, tags, or likes. The GenericRelation on the target models enables reverse lookups, while the compound index on content_type and object_id ensures efficient querying.

snippet.py
python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
from django.db import models
from django.contrib.contenttypes.models import ContentType
from django.contrib.contenttypes.fields import GenericForeignKey, GenericRelation
class Comment(models.Model):
content_type = models.ForeignKey(ContentType, on_delete=models.CASCADE)
object_id = models.PositiveIntegerField()
content_object = GenericForeignKey('content_type', 'object_id')
text = models.TextField()
created_at = models.DateTimeField(auto_now_add=True)
class Meta:
indexes = [
models.Index(fields=['content_type', 'object_id']),
]
class Article(models.Model):
title = models.CharField(max_length=200)
body = models.TextField()
comments = GenericRelation(Comment, related_query_name='articles')
class Product(models.Model):
name = models.CharField(max_length=200)
price = models.DecimalField(max_digits=10, decimal_places=2)
comments = GenericRelation(Comment, related_query_name='products')
# Usage example
def get_recent_comments(obj, limit=5):
content_type = ContentType.objects.get_for_model(obj)
return Comment.objects.filter(
content_type=content_type,
object_id=obj.pk
).order_by('-created_at')[:limit]
django
Breakdown
1
content_type = models.ForeignKey(ContentType, ...)
Stores which model class the comment is attached to
2
object_id = models.PositiveIntegerField()
Stores the primary key of the related object
3
GenericForeignKey('content_type', 'object_id')
Dynamically resolves to the actual related object at runtime
4
GenericRelation(Comment, related_query_name='articles')
Enables Article.comments.all() and Comment.objects.filter(articles=article)
5
ContentType.objects.get_for_model(obj)
Retrieves the ContentType instance for any Django model dynamically
6
models.Index(fields=['content_type', 'object_id'])
Composite index for fast lookups when filtering by content type and ID