文章目录
- 1. contenttype组件作用
- 2. contenttype组件示例
1) contenttype组件帮助我们 生成了所有关联数据库的表
,使用ForeignKey与contenttype表直接关联就可以
2)在模型类中使用GenericForeignKey可以帮助我们 快速插入数据
,实现content_type操作
3)在模型类中使用GenericRelation可以实现 快速查找
,不用自己去连表
有这样的业务场景,课程分为普通课程和VIP课程,需要为这两种课程设置价值策略。在价格策略表中需要记录两种课程的课程ID,为了区分是哪个表的课程ID,还需要记录表名称。表设计如下:
创建表,models.py:
from django.db import models
from django.contrib.contenttypes.models import ContentType
# Create your models here.
class Course(models.Model):
"""
普通课程
"""
name = models.CharField(max_length=32, help_text='课程的名称')
class VipCourse(models.Model):
"""
VIP普通课程
"""
name = models.CharField(max_length=32, help_text='Vip课程的名称')
class PricePolicy(models.Model):
"""
价格策略
"""
price = models.FloatField(help_text='价格')
period = models.IntegerField(help_text='时间周期')
# table_name = models.CharField(verbose_name='关联的表名称')
# course_id = models.IntegerField(verbose_name='关联的表中的数据行的ID,即课程ID')
table_name = models.ForeignKey(ContentType, verbose_name='关联的表名称') # ContentType表中有表名称字段
course_id = models.IntegerField(verbose_name='关联的表中的数据行的ID,即课程ID')
在models.py中设置的价格策略的字段table_name在生成表的时候变成了table_name_id,下面将使用content_type来替换table_name,这样生成表的字段就是content_type_id,这将更方便我们知道该字段关联content_type表。
我们用 常规的方式
在 views.py
中为课程添加价格策略,
urls.py:
from django.urls import path
from app import views
urlpatterns = [
# path('admin/', admin.site.urls),
path('test/', views.test)
]
views.py:
from django.shortcuts import render, HttpResponse
from app import models
# Create your views here.
def test(request):
"""
# 添加之前向两个课程表中添加数据
models.Course.objects.create(name='Python')
models.Course.objects.create(name='Flask')
models.Course.objects.create(name='Django')
models.VipCourse.objects.create(name='DRF')
models.VipCourse.objects.create(name='VUE')
models.VipCourse.objects.create(name='Scrapy')
"""
"""
添加一条普通课程为“Python”价格为99.9,学习周期为3个月的价格策略记录(首先还要查询相关字段的值)
"""
course_obj = models.Course.objects.filter(name='Python').first()
print(course_obj) # Course object (1)
# 首先需要获取根据课程的名称获取课程的id
course_id = course_obj.id
# 然后还要获取content_type表中course表对应的id
content_type_obj = models.ContentType.objects.filter(model='course').first()
content_type_id = content_type_obj.id
models.PricePolicy.objects.create(price=99.9, period=3, course_id=course_id, content_type_id=content_type_id)
return HttpResponse('...')
这样就成功创建策略:
1)这样为课程添加价格策略未免有些麻烦,借助contenttype组件可以帮助我们快速实现content_type操作
。修改 models.py
:
...
from django.contrib.contenttypes.fields import GenericForeignKey
...
class PricePolicy(models.Model):
"""
价格策略
"""
price = models.FloatField(help_text='价格')
period = models.IntegerField(help_text='时间周期')
content_type = models.ForeignKey(ContentType, verbose_name='关联的表名称',
on_delete=models.CASCADE) # ContentType表中有表名称字段
course_id = models.IntegerField(verbose_name='关联的表中的数据行的ID,即课程ID')
content_object = GenericForeignKey('content_type', 'course_id')
因此添加策略的时候可以这样:
from django.shortcuts import render, HttpResponse
from app import models
# Create your views here.
def test(request):
"""
# 添加之前向两个课程表中添加数据
models.Course.objects.create(name='Python')
models.Course.objects.create(name='Flask')
models.Course.objects.create(name='Django')
models.VipCourse.objects.create(name='DRF')
models.VipCourse.objects.create(name='VUE')
models.VipCourse.objects.create(name='Scrapy')
"""
"""
# 添加一条普通课程为“Python”价格为99.9,学习周期为3个月的价格策略记录(首先还要查询相关字段的值)
course_obj = models.Course.objects.filter(name='Python').first()
print(course_obj) # Course object (1)
# 首先需要获取根据课程的名称获取课程的id
course_id = course_obj.id
# 然后还要获取content_type表中course表对应的id
content_type_obj = models.ContentType.objects.filter(model='course').first()
content_type_id = content_type_obj.id
models.PricePolicy.objects.create(price=99.9, period=3, course_id=course_id, content_type_id=content_type_id)
"""
"""
1.借助content_type快速实现数据插入(content_type)操作
"""
course_obj = models.Course.objects.filter(name='Python').first()
models.PricePolicy.objects.create(price=99.9, period=3, content_object=course_obj)
return HttpResponse('...')
只需要两行代码即可以,不需要查课程的ID和课程对应content_type表中的ID。表中成功插入一条课程策略记录:
2)根据课程ID获取该课程所有的价格策略,这里可以使用contenttype组件中的GenericRelation来实现反向查找,需要修改 models.py:
from django.db import models
from django.contrib.contenttypes.models import ContentType
from django.contrib.contenttypes.fields import GenericForeignKey, GenericRelation
# Create your models here.
class Course(models.Model):
"""
普通课程
"""
name = models.CharField(max_length=32, help_text='课程的名称')
# 仅仅用于反向查找(无须修改表结构)
price_policy_list = GenericRelation('PricePolicy')
class VipCourse(models.Model):
"""
VIP普通课程
"""
name = models.CharField(max_length=32, help_text='Vip课程的名称')
# 仅仅用于反向查找(无须修改表结构)
price_policy_list = GenericRelation('PricePolicy')
class PricePolicy(models.Model):
"""
价格策略
"""
price = models.FloatField(help_text='价格')
period = models.IntegerField(help_text='时间周期')
# table_name = models.CharField(verbose_name='关联的表名称')
# course_id = models.IntegerField(verbose_name='关联的表中的数据行的ID,即课程ID')
content_type = models.ForeignKey(ContentType, verbose_name='关联的表名称', on_delete=models.CASCADE)
"""
课程的ID,要使用object_id,不要使用course_id,这是个坑
"""
object_id = models.IntegerField(verbose_name='关联的表中的数据行的ID,即课程ID')
# 仅仅用于快速操作content_type(无须修改表结构)
content_object = GenericForeignKey('content_type', 'object_id')
views.py:
from django.shortcuts import render, HttpResponse
from app import models
# Create your views here.
def test(request):
"""
# 添加之前向两个课程表中添加数据
models.Course.objects.create(name='Python')
models.Course.objects.create(name='Flask')
models.Course.objects.create(name='Django')
models.VipCourse.objects.create(name='DRF')
models.VipCourse.objects.create(name='VUE')
models.VipCourse.objects.create(name='Scrapy')
"""
"""
# 添加一条普通课程为“Python”价格为99.9,学习周期为3个月的价格策略记录(首先还要查询相关字段的值)
course_obj = models.Course.objects.filter(name='Python').first()
print(course_obj) # Course object (1)
# 首先需要获取根据课程的名称获取课程的id
course_id = course_obj.id
# 然后还要获取content_type表中course表对应的id
content_type_obj = models.ContentType.objects.filter(model='course').first()
content_type_id = content_type_obj.id
models.PricePolicy.objects.create(price=99.9, period=3, course_id=course_id, content_type_id=content_type_id)
"""
"""
1. 借助content_type快速实现数据插入(content_type)操作
1. 借助content_type快速实现数据插入(content_type)操作
course_obj = models.Course.objects.filter(name='Python').first()
models.PricePolicy.objects.create(price=99.9, period=3, content_object=course_obj)
"""
"""
2. 根据课程ID获取该课程所有的价格策略(借助GenericRelation实现反向查找)
"""
try:
course_obj = models.Course.objects.filter(id=1).first() # id=1是Python课程
price_policy_list = course_obj.price_policy_list.all()
print(
price_policy_list) # , ]>
for i in price_policy_list:
print(i)
"""
PricePolicy object (1)
PricePolicy object (2)
"""
except Exception as e:
print(
e) # Cannot resolve keyword 'object_id' into field. Choices are: content_object, content_type, content_type_id, course_id, id, period, price
return HttpResponse('...')
代码参考:
https://github.com/ThanlonSmith/contenttype-django