Django ContentType Usage
1. Introduction
ContentType solves the problem where two fields in one table are associated with two (or more) other tables.
# Course Table - Free Courses
# id name
1 Linux Basics
2 Python Basics
# DegreeCourse Table - Degree Courses
# id name
1 Python Full Stack
# PricePolicy Table - Two fields correspond to the id and table name of the above tables
# id day price course_id course_type
1 7 0 1 Free Course
2 7 0 2 Free Course
3 14 9.9 2 Free Course
4 180 18888 1 Degree Course
Modify the PricePolicy table to associate with Django's content_type, which stores all table names in Django.
# PricePolicy Table
# id day price course_id course_type(foreign key)
1 7 0 1 1
2 14 9.9 1 1
3 180 18888 1 2
# ContentType Table
id model app_label
1 course app01
2 degreecourse app01
2. Custom Methods for Operations
Model Definitions
from django.db import models
class Course(models.Model):
name = models.CharField(max_length=32)
def __str__(self):
return self.name
class DegreeCourse(models.Model):
name = models.CharField(max_length=32)
def __str__(self):
return self.name
# Using ContentType but not its methods
from django.contrib.contenttypes.models import ContentType
class PricePolicy(models.Model):
day = models.IntegerField()
price = models.CharField(max_length=8)
course_id = models.IntegerField()
content_type = models.ForeignKey(to=ContentType, null=True) # Will be changed to foreign key
# Custom operations
# 1. Insert a strategy into course data; use _meta.model_name to get table name string
# Method: First query course; get table name through course; insert data into policy table
course = models.DegreeCourse.objects.first()
contenttype = models.ContentType.objects.filter(model=course._meta.model_name).first()
models.PricePolicy.objects.create(day=7, price=0, course_id=course.id, content_type=contenttype)
# 2. Query policies by course
# Method: Same as above
course = models.DegreeCourse.objects.first()
contenttype = models.ContentType.objects.filter(model=course._meta.model_name).first()
price_policy = models.PricePolicy.objects.filter(course_id=course.id, content_type=contenttype).values('day', 'price')
print(price_policy)
# Query course via policy using apps.get_model to retrieve table class
# Method: First query policy table; get table class via get_model; then query data in course table
from django.apps import apps
price_policy_obj = models.PricePolicy.objects.filter(day=7, price=0).first()
model = apps.get_model('API', price_policy_obj.content_type.model) # First parameter is app name, second is table name, returns table class
course = model.objects.filter(pk=price_policy_obj.course_id)
print(course)
3. Using ContentType Methods for Operations
Model Definiitons
from django.db import models
from django.contrib.contenttypes.models import ContentType
from django.contrib.contenttypes.fields import GenericRelation
from django.contrib.contenttypes.fields import GenericForeignKey
class Course(models.Model):
name = models.CharField(max_length=32)
price_policy = GenericRelation(to='PricePolicy')
def __str__(self):
return self.name
class DegreeCourse(models.Model):
name = models.CharField(max_length=32)
price_policy = GenericRelation(to='PricePolicy')
def __str__(self):
return self.name
class PricePolicy(models.Model):
day = models.IntegerField()
price = models.CharField(max_length=8)
object_id = models.IntegerField()
content_type = models.ForeignKey(to=ContentType, null=True)
model_obj = GenericForeignKey()
# Note:
# 1. model_obj refers to DegreeCourse or Course table objects
# 2. object_id refers to course ID, corresponding to parameters in GenericForeignKey
# 3. If customizing object_id and content_type, parameters in GenericForeignKey and GenericRelation must also be modified, e.g.:
# course_id = models.IntegerField()
# course_type = models.ForeignKey(to=ContentType, null=True)
# model_obj = GenericForeignKey(ct_field='course_type', fk_field='course_id')
#
# price_policy = GenericRelation(to='PricePolicy', object_id_field='course_id', content_type_field='course_type')
# 1. Insert a strategy for course data
degree_course = models.DegreeCourse.objects.first()
models.PricePolicy.objects.create(day=180, price=18880, model_obj=degree_course)
# 2. Find all price policies for all courses
price_policy_list = models.PricePolicy.objects.all()
for price_policy in price_policy_list:
print(price_policy.model_obj.name, price_policy.day, price_policy.price)
# 3. Query policies by course
course = models.Course.objects.first()
price_policys = course.price_policy.all()
for price_policy in price_policys:
print(course.name, price_policy.day, price_policy.price)