Django ContentType组件
需求
现在我们有这样一个需求~我们的商城里有很多的商品~~节日要来了~我们要搞活动~~
那么我们就要设计优惠券~~优惠券都有什么类型呢~~满减的~折扣的~立减的~~
我们对应着我们活动类型~对我们的某类商品设计优惠券~~比如~~
家电是一类商品~~食物是一类商品~那么我们可以设计家电折扣优惠券~~以及食物满减优惠券等~
那么我们看表结构怎么设计~~
第一版本
from django.db import models # 设计表结构 # 第一版设计 class Food(models.Model): name = models.CharField(max_length=32) class Fruit(models.Model): name = models.CharField(max_length=32) class Coupon(models.Model): title = models.CharField(max_length=32) food = models.ForeignKey(to="Food") fruit = models.ForeignKey(to="Fruit")
但是 发现商品太多 name外键也要加很多 name表结构就很不合理
第二版本
from django.db import models class Food(models.Model): """食物表""" name = models.CharField(max_length=32) class Fruit(models.Model): """水果表""" name = models.CharField(max_length=32) class Coupon(models.Model): """优惠券表 这时候 设计字段为 表的id 和 object的对象id 表的id 就是找到对应的表 object的id 就可以找到表里边对应的对象 就是定位的方法 """ title = models.CharField(max_length=32) table = models.ForeignKey(to=MyTables) object_id = models.IntegerField() class MyTables(models.Model): """ id app_name table_name 1 Demo Food # 对应的外键是 1 2 Demo Fruit # 对应的外键是 2 """ app_name = models.CharField(max_length=32) table_name = models.CharField(max_length=32)
就是通过外键到第三张表MyTables找到对应的app中(水果,食物、、)等类的表, 然后通过根据表中对象对应的id拿到具体的对象这样方法可行吗?
其实django已经帮我们设计好了
遇到这种一张表要跟多张表进行外键关联的时候~我们Django提供了ContentType组件~
ContentType组件
注释所有的model文件执行数据库迁移
pythno manage.py migrate
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 # 定位django表使用 from django.contrib.contenttypes.fields import GenericForeignKey # 定位表中字段对应对象使用 from django.contrib.contenttypes.fields import GenericRelation # 反向查询使用 # 设计表结构 # 第三版设计 class Food(models.Model): """食物表""" name = models.CharField(max_length=32) coupons = GenericRelation(to="Coupon") # 不生成字段 只用于方向查询 class Fruit(models.Model): """水果表""" name = models.CharField(max_length=32) coupons = GenericRelation(to="Coupon") # 不生成字段 只用于方向查询 class Coupon(models.Model): """优惠券表""" title = models.CharField(max_length=32) # 第三版 使用Django自带的ContentType表 # 外键到Django自带的ContentType表 content_type = models.ForeignKey(to=ContentType) # 相当于 找到可以定位到表 object_id = models.IntegerField() # 相当于 定位在表的对应的对象id # 不会生成字段 用于关联到对象的(建立关系) content_object = GenericForeignKey("content_type", "object_id")
简单测试
添加食物数据
添加水果数据
添加测试url
from django.conf.urls import url from .views import TestView urlpatterns = [ url(r'^test', TestView.as_view()), ]
from rest_framework.views import APIView from rest_framework.response import Response from .models import Food, Fruit, Coupon from django.contrib.contenttypes.models import ContentType class TestView(APIView): def get(self, request): # 找到表id以及表对象 # content_type_obj = ContentType.objects.filter(app_label="ContentType", model="food").first() # # print(type(content_type_obj), "**", content_type_obj) # 拿到表中表名 # # <class 'django.contrib.contenttypes.models.ContentType'> ** food # # model_class = content_type_obj.model_class() # 拿到模型表对象 # print(model_class) # <class 'ContentType.models.Food'> # # <class 'ContentType.models.Food'> # print(content_type_obj.pk) # 获得表中对应id # (pk和id是一样的) # # 给酱香饼创建优惠券 # food_obj = Food.objects.filter(id=1).first() # 库中的id为1 # Coupon.objects.create(title="酱香饼半价啦", content_object=food_obj) # 在视图中content_object做了关系 # # # 给黑美人西瓜加优惠券 # fruit_obj = Fruit.objects.get(id=2) # 库中的id为2 # Coupon.objects.create(title="黑美人2折", content_type_id=9, object_id=2) # 使用原生方法创建优惠券 # 查询优惠券绑定对象(看看id为1的优惠券是对应那个商品) coupon_obj = Coupon.objects.filter(id=1).first() print(coupon_obj.content_object.name) # 酱香饼 # content_object建立了关系 # 查某个对象的优惠券 food_obj = Food.objects.filter(id=1).first() print(food_obj.coupons.all()) # 拿到queryset集合对象 <QuerySet [<Coupon: Coupon object>]> return Response("ok")