ContentType使用
场景, 给商品添加优惠券
from django.db import models class Food(models.Model): """ id title 1 面包 2 馒头 """ title = models.CharField(max_length=32) class Fruit(models.Model): """ id title 1 苹果 2 橘子 """ title = models.CharField(max_length=32) """ 对于以上两张表, 现在要为每个食品添加对应的优惠券 那么普通的想法怎么做呢? id title food_id fruit_id 1 面包优惠券 2 null 2 水果优惠券 null 2 这样通过外键的联系可以实现功能, 但是问题来了>>> 如果商品类型特别对, 我一个面包的优惠券就要对应除了自己能用到的字段,剩下的都是无用的字段.别的商品也类似 >>>改进<<< 改进的方法就是, 列外新建一张MyTable的表格, 记录app的名字, 和表的名字 id title MyTable_id object_id 1 馒头 1 2 2 橘子 2 2 这张表记录的东西就是MyTable_id对应的appname和tablename,来确定是哪张表, object_id, 确定这张表的那个物品 对于以上的实现方式, DRF给出了这张表格, 记录app和表的对应关系(django_content_type) """ # class MyTable(models.Model): # """ # id appname tablename # 1 app02 Food # 2 app02 Fruit # """ # # 放app的名字 # app_name = models.CharField(max_length=32) # # 表名字 # table_name = models.CharField(max_length=32)
使用ContentType解决
ContentType组件
ContentType是Django的内置一个应用, 可以追踪项目中所有的APP和model的对应关系, 并记录ContentType表中.
ContentType组件应用
- 在model中定义ForeignKey字段, 并关联到ContentType表, 通常这个字段命名为content-type
- 在model中定义PositiveIntergerField字段, 用来存储关联表中的主键, 通常我们用object_id
- 在model中定义GeneriaForeignKey字段, 传入上面两个字段的名字
- 方便反向查询可以定义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 title 1 面包 2 馒头 """ title = models.CharField(max_length=32) class Fruit(models.Model): """ id title 1 苹果 2 橘子 """ title = models.CharField(max_length=32) class Appliance(models.Model): name = models.CharField(max_length=64) coupons = GenericRelation(to="Coupon") class Coupon(models.Model): name = models.CharField("活动名称", max_length=32) # 第一步 代表那个app下的那张表 content_type = models.ForeignKey(to=ContentType, null=True, blank=True) # 第二步 代表那张表的对象id object_id = models.PositiveIntegerField("绑定商品", null=True, blank=True) # 第三步 不会生成额外的列 content_object = GenericForeignKey("content_type", "object_id")

class TestView(APIView): def get(self, request): # 给山东大馒头加优惠券 food_obj = Food.objects.filter(id=1).first() # Coupon.objects.create(title="买一赠一", content_obj=food_obj) # 查看山东大馒头有哪些优惠券 for coupon in food_obj.coupons.all(): print(coupon.title) # 查看优惠券绑定的商品 coupon_obj = Coupon.objects.first() print(coupon_obj.content_obj.title) return Response("ok")