django ContentType组件
一,需求
给商品创建优惠券;
看看下面表结构:
class Food(models.Model): """ id name 1 面条 """ name = models.CharField(max_length=32) def __str__(self): return self.name class Fruit(models.Model): """ id name 1 苹果 """ name = models.CharField(max_length=32) coupons = GenericRelation(to="Coupon") # 定义反向查询字段 def __str__(self): return self.name class Coupon(models.Model): """ 优惠券表 id name appliance_id food_id fruit_id 1 通用优惠券 null null null 2 冰箱折扣券 1 null null 3 电视折扣券 2 null null 4 苹果满减卷 null null 1 我每增加一张表就要多增加一个字段 """ name = models.CharField(max_length=32) # 这样写,每增加一张表就要多增加一个字段, 所以我们可以创建第四张表 appliance = models.ForeignKey(to="Appliance") food = models.ForeignKey(to="Food") fruit = models.ForeignKey(to="Fruit")
创建第四张表,改善上面的写法:遇到这种一张表要跟多张表进行外键关联
class Appliance(models.Model): name = models.CharField(max_length=32) class Food(models.Model): """ id name 1 面条 """ name = models.CharField(max_length=32) def __str__(self): return self.name class Fruit(models.Model): """ id name 1 苹果 """ name = models.CharField(max_length=32) coupons = GenericRelation(to="Coupon") # 定义反向查询字段 def __str__(self): return self.name class Coupon(models.Model): """ 优惠券表 id name content_type_id object_id 1 面条优惠券 1 1 1 苹果优惠券 2 1 """ name = models.CharField(max_length=32) # 这样写,每增加一张表就要多增加一个字段, 所以我们可以创建第四张表ContentType content_type_id = object_id = class ContentType(models.Model): # django自带这张表,已经帮我们做好了,就是django的ContentType组件,我们直接拿过来用就行 """ id app_name model_class 1 app01 Food 2 app01 Fruit 3 app01 Appliance """ pass
django已经帮我写好了这张ContentType表,我们只需要导入使用即可;
二 使用django自带的ContentType表
ContentType是Django的内置的一个应用,可以追踪项目中所有的APP和model的对应关系,并记录在ContentType表中。
当我们的项目做数据迁移后,会有很多django自带的表,其中就有django_content_type表;
ContentType组件应用:
-- 在model中定义ForeignKey字段,并关联到ContentType表,通常这个字段命名为content-type
-- 在model中定义PositiveIntergerField字段, 用来存储关联表中的主键,通常我们用object_id
-- 在model中定义GenericForeignKey字段,传入上面两个字段的名字
-- 方便反向查询可以定义GenericRelation字段
from django.db import models
from django.contrib.contenttypes.models import ContentType
from django.contrib.contenttypes.fields import GenericForeignKey, GenericRelation
class Food(models.Model): """ id name 1 面条 """ name = models.CharField(max_length=32) def __str__(self): return self.name class Fruit(models.Model): """ id name 1 苹果 """ name = models.CharField(max_length=32) coupons = GenericRelation(to="Coupon") # 定义反向查询字段 def __str__(self): return self.name class Coupon(models.Model): """ 优惠券表 id name content_type_id object_id 1 面条优惠券 1 1 1 苹果优惠券 2 1 """ name = models.CharField(max_length=32) # 这样写,每增加一张表就要多增加一个字段, 所以我们可以创建第四张表ContentType # appliance = models.ForeignKey(to="Appliance") # food = models.ForeignKey(to="Food") # fruit = models.ForeignKey(to="Fruit") # 第一步 先生成ForeignKey字段 关联ContentType content_type = models.ForeignKey(to=ContentType) # 第二步 生成一个IntergerField 字段关联 object_id = models.PositiveIntegerField() # 第三步 生成一个GenericForeignKey 把上面两个字段注册进去 content_obj = GenericForeignKey("content_type", "object_id") def __str__(self): return self.name
基本的操作:
class Test(APIView): def get(self, request): from django.contrib.contenttypes.models import ContentType # 通过contentType获取表名 content = ContentType.objects.filter(app_label="app01", model="food").first() # 表名都是小写 model_class = content.model_class() # 通过上一步获取的contentType对象获取 里面的表对象 ret = model_class.objects.all() # 查询这个表中所有的信息 print(ret) # 给Food表中的面条创建一个优惠券 noodle_obj = models.Food.objects.filter(id=2).first() # 这里面包含了自己所在的表,和自己这条记录在那张表中的id models.Coupon.objects.create(name="面条优惠券", content_obj=noodle_obj) # 只要传入上面的obj即可 # 查询id为1的优惠券,对应那个商品信息 coupon_obj = models.Coupon.objects.filter(id=1).first() goods_obj = coupon_obj.content_obj # 拿到对应的商品对象 print(goods_obj) print(goods_obj.name, goods_obj.id) # 查询苹果的所有优惠券 # 因为我们定义了反向字段,所以可以这么查: # 首先找苹果对象 apple_obj = models.Fruit.objects.filter(name="苹果").first() coupon_obj_list = apple_obj.coupons.all() # 通过字段反向查询 print(coupon_obj_list) print(coupon_obj_list.first().name) return Response("ok")
学无止境!