前戏
假设现在我们有很多张表,比如Food表,Fruit表等等。有一天这些东西都要打折,那我们要新建一张表,里面写的打折信息,要把所有的表都关联在一起,这样的话就会在一张表里有很多的外键,例如下面的。
from django.db import models class Food(models.Model): """ id name 1 麻婆豆腐 2 木耳炒牛肉 3 西红柿炒鸡蛋 """ name = models.CharField(max_length=32) class Fruit(models.Model): """ id name 1 香蕉 2 苹果 """ name = models.CharField(max_length=32) class Coupon(models.Model): """ id title food_id fruit_id .......... 1 麻婆豆腐买一送一 1 null 2 香蕉2折 null 2 """ title = models.CharField(max_length=32) food = models.ForeignKey(to="Food") fruit = models.ForeignKey(to="Fruit")
优化表结构
既然一张表里有这么多的外键,那我们可不可以新建一张表,专门用来存放app和表名的,如下
from django.db import models class Food(models.Model): """ id name 1 麻婆豆腐 2 木耳炒牛肉 3 西红柿炒鸡蛋 """ name = models.CharField(max_length=32) class Fruit(models.Model): """ id name 1 香蕉 2 苹果 """ name = models.CharField(max_length=32) class Coupon(models.Model): """ id title food_id fruit_id .......... 1 麻婆豆腐买一送一 1 null 2 香蕉2折 null 2 """ 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 2 Demo Fruit """ app_name = models.CharField(max_length=32) table_name = models.CharField(max_length=32)
Mytables表里存放了我们所有的app名和表名,在Coupon表里通过外键关系关联到MyTables表,这样就解决了一张表里多个外键的问题
ContentType
Django在生成数据表的时候已经给我们提供了这张表“MyTables”,表名叫content_type,里面的字段含义和我们自定义的一样
所以第三张表就不用我们自己创建了,直接使用Django自带的就可以了
from django.db import models from django.contrib.contenttypes.models import ContentType from django.contrib.contenttypes.fields import GenericForeignKey, 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) content_type = models.ForeignKey(to=ContentType) object_id = models.IntegerField() # 不会生成字段 只用于关联到对象的 content_object = GenericForeignKey("content_type", "object_id")
使用ORM添加数据
from django.shortcuts import render from rest_framework.views import APIView from django.http import HttpResponse from .models import Food, Fruit, Coupon from django.contrib.contenttypes.models import ContentType class TestView(APIView): def get(self, request): # 找到表id以及表对象 food_obj = Food.objects.filter(id=1).first() # 往Coupon表里插数据 Coupon.objects.create(title="水密桃大甩卖", content_object=food_obj) return HttpResponse("ok")
查询数据
from django.shortcuts import render from rest_framework.views import APIView from django.http import HttpResponse from .models import Food, Fruit, Coupon from django.contrib.contenttypes.models import ContentType class TestView(APIView): def get(self, request): # 查询出来的是Food或者Fruit对象 coupon_obj = Coupon.objects.filter(id=1).first() # 通过content_object.name拿到对应的name值 print(coupon_obj.content_object.name) # 查某个对象的优惠券 food_obj = Food.objects.filter(id=1).first() print(food_obj.coupons.all()) return HttpResponse("ok")