Django之contenttype组件

文章目录

            • 1. contenttype组件作用
            • 2. contenttype组件示例

1. contenttype组件作用

1) contenttype组件帮助我们 生成了所有关联数据库的表,使用ForeignKey与contenttype表直接关联就可以

2)在模型类中使用GenericForeignKey可以帮助我们 快速插入数据,实现content_type操作

3)在模型类中使用GenericRelation可以实现 快速查找,不用自己去连表

2. contenttype组件示例

有这样的业务场景,课程分为普通课程和VIP课程,需要为这两种课程设置价值策略。在价格策略表中需要记录两种课程的课程ID,为了区分是哪个表的课程ID,还需要记录表名称。表设计如下:
Django之contenttype组件_第1张图片
创建表,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')

Django之contenttype组件_第2张图片
Django之contenttype组件_第3张图片
在models.py中设置的价格策略的字段table_name在生成表的时候变成了table_name_id,下面将使用content_type来替换table_name,这样生成表的字段就是content_type_id,这将更方便我们知道该字段关联content_type表。
Django之contenttype组件_第4张图片
我们用 常规的方式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('...')

这样就成功创建策略:
Django之contenttype组件_第5张图片
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。表中成功插入一条课程策略记录:
Django之contenttype组件_第6张图片
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

你可能感兴趣的:(Django,django,python,contenttype,contenttype组件)