ContentType组件

一、什么是ContentTypes

django提供的一个 快速连表操作的组件

contenttypes 是Django内置的一个应用,可以追踪项目中所有app和model的对应关系,并记录在ContentType表中。models.py文件的表结构写好后,通过makemigrations和migrate两条命令迁移数据后,在数据库中会自动生成一个django_content_type表:

每当我们创建了新的model并执行数据库迁移后,ContentType表中就会自动新增一条记录。比如我在应用api的models.py中创建表class Electrics(models.Model): pass。从数据库查看ContentType表,显示如下:

那么这个表有什么作用呢?这里提供一个场景,网上商城购物时,会有各种各样的优惠券,比如通用优惠券,满减券,或者是仅限特定品类的优惠券。在数据库中,可以通过外键将优惠券和不同品类的商品表关联起来:

from django.db import models


class Electrics(models.Model):
    """
    id    name
     1   日立冰箱
     2   三星电视
     3   小天鹅洗衣机
    """
    name = models.CharField(max_length=32)

class Foods(models.Model):
    """
    id   name
    1    面包
    2    烤鸭
    """
    name = models.CharField(max_length=32)

class Clothes(models.Model):
    name = models.CharField(max_length=32)


class Coupon(models.Model):  # 特殊关系表
""" 
  id    name    electric_id   food_id   cloth_id   more...   # 每增加一张表,关系表的结构就要多加一个字段。
    1   通用优惠券   null       null      null 
    2   冰箱满减券   2         null     null 
    3   面包狂欢节   null        1      null 
""" 
name = models.CharField(max_length=32) 
electric = models.ForeignKey(to='Electrics', null=True) 
food = models.ForeignKey(to='Foods', null=True) 
cloth = models.ForeignKey(to='Clothes', null=True)

如果是通用优惠券,那么所有的ForeignKey为null,如果仅限某些商品,那么对应商品ForeignKey记录该商品的id,不相关的记录为null。但是这样做是有问题的:实

际中商品品类繁多,而且很可能还会持续增加,那么优惠券表中的外键将越来越多,但是每条记录仅使用其中的一个或某几个外键字段。

contenttypes 应用

通过使用contenttypes 应用中提供的特殊字段GenericForeignKey,我们可以很好的解决这个问题。只需要以下三步: 

  1. 在model中定义ForeignKey字段,并关联到ContentType表。通常这个字段命名为“content_type”
  2. 在model中定义PositiveIntegerField字段,用来存储关联表中的主键。通常这个字段命名为“object_id”
  3. 在model中定义GenericForeignKey字段,传入上述两个字段的名字。

为了更方便查询商品的优惠券,我们还可以在商品类中通过GenericRelation字段定义反向关系。  

 

 

ContentType

示例:

通过Django提供的ContentType表,来构建

 

models层创建:

from django.db import models

from django.contrib.contenttypes.models import ContentType
from django.contrib.contenttypes.fields import GenericForeignKey, GenericRelation


class Course(models.Model):
    title = models.CharField(max_length=32)
    # 不会在数据库中生成字段,只用于数据库操作
    # policy = GenericRelation('PricePolicy',object_id_field='object_id',content_type_field='contentType')


class DegreeCourse(models.Model):
    title = models.CharField(max_length=32)


class PricePolicy(models.Model):
    # 跟ContentType表做外键关联
    contentType = models.ForeignKey(to=ContentType)
    # 正数
    object_id = models.PositiveIntegerField()

    # 引入一个字段,不会在数据库中创建,只用来做数据库操作
    # content_obj = GenericForeignKey('contentType', 'object_id')

    period = models.CharField(max_length=32)
    price = models.FloatField()

 

views层:

from app01 import models
def test(request):
    import json
    # 方式一插入价格规则
    # ret=models.ContentType.objects.filter(model='course').first()
    # course=models.Course.objects.filter(pk=1).first()
    # print(ret.id)
    # models.PricePolicy.objects.create(period='30',price=100,object_id=course.id,contentType_id=ret.id)

    # 方式二插入价格规则
    # course=models.Course.objects.filter(pk=1).first()
    # # content_obj=course  会自动的把课程id放到object_id上,并且去ContentType表中查询课程表的id,放到contentType上
    # models.PricePolicy.objects.create(period='60',price=800,content_obj=course)
    # 增加学位课,价格规则
    # degreecourse = models.DegreeCourse.objects.filter(pk=1).first()
    # models.PricePolicy.objects.create(period='60', price=800, content_obj=degreecourse)

    # 查询所有价格策略,并且显示对应的课程名称
    # ret=models.PricePolicy.objects.all()
    # for i in ret:
    #     print(i.price)
    #     print(i.period)
    #     # content_obj 就是代指关联的课程,或者学位课程的那个对象
    #     print(type(i.content_obj))
    #     print(i.content_obj.title)

    # 通过课程id,获取课程信息和价格策略
    course=models.Course.objects.filter(pk=1).first()
    print(course.policy.all())




    return render(request,'test.html')

 

posted @ 2019-03-01 23:01  萤huo虫  阅读(125)  评论(0编辑  收藏  举报