使用ContentType处理大量的外键关系
问题分析
在之前的一个商城的项目中使用了mysql, 提到mysql就是外键, 多对多等等一系列的表关系
因为是一个商城的项目, 这里面有优惠券, 商品有很多的分类, 不同的商品又有不同的优惠券
其实要说的也就是商品和优惠券的关系,
说到关系那肯定就是用外键, 优惠券外键商品, 但是有一个问题, 一个外键只能指向一张表
现在假如有10个商品表, 一张优惠券表, 要想在一张表中给另外10张表创建外键关系, 那就需要10个外键关系, 10个外键字段
可想而知, 这种方法是不可行的
其实有一种办法那就是, 在优惠券表不直接关联商品表, 而是搞一个中间表, 关联这个中间表, 那这个中间表应该张什么样子呢?
这张表中存储是的app名字和表的名字
id app_name model_name 1 mian Human_insurance 2 main Life_insurance
然后优惠券表就这张表建立外键关系, 然后在优惠券中在存储一个object_id, 通过外键找到关联的表, 通过object_id找到表中的对象, 这样就OK了
上面的正常人的想法, django的开发者也是正常人, 哈哈, 他们也想到了, 所以django提供了这样的一张表.
使用ContentType处理外键关系
下面是我写的一个小demo, 这里面就利用了django提供的ContentType来处理外键关系
模型表
from django.db import models from django.contrib.contenttypes.fields import GenericRelation, GenericForeignKey from django.contrib.contenttypes.models import ContentType class Book(models.Model): title = models.CharField(max_length=32) price = models.FloatField() category_choices = (("chinese", "中文"), ("english", "英文"), ("development", "开发"), ("network", "网络")) category = models.CharField(choices=category_choices, max_length=32) pub_date = models.DateTimeField(null=True, blank=True) content_type = models.ForeignKey(ContentType, blank=True, null=True, on_delete=models.CASCADE) # 定位对象的id object_id = models.PositiveIntegerField(blank=True, null=True) # 定位对象 content_object = GenericForeignKey('content_type', 'object_id') def __str__(self): return self.title class Publish(models.Model): name = models.CharField(max_length=32) address = models.CharField(max_length=128) books = GenericRelation("Book") def __str__(self): return self.name
book表中的字段介绍
content_type: 是一个外键字段, 关联的表就是和上面自己构造的表结构一致, 只不过是Django提供的
这样就方便了很多.
object_id: 这个字段存储的就是某张表中的某个对象的id, 所以就是用数字类型进行存储
content_object: 这个字段是一个GenericForeignKey, 这个字段给我们提供了很大的方便, 但是这个字段不会真实的在数据库中创建,
为什么说提供了很大的方便呢?
因为, 在创建book对象的时候可以给content_object传一个对象, 这个字段能够自动找到这个对象的app_name和model_name, 并且填充到content_type和object_id中
这样就不用我们自己去查了
下面就使用这个字段对数据库进行操作
查看书籍的出版社
a = models.Book.objects.filter(id=5).first() print(a.content_object) #content_object通过content_type和object_id定位到对象
创建book
创建book的时候需要关联出版社, 这就用道了contentType, 只传一个content_object参数就可以了
# 先查询出出版社 b = models.Publish.objects.filter(id=3).first() # 创建book c = models.Book.objects.create(title="test", price=99.9, category="english", content_object=b) print(c)
修改book的出版社
e = models.Book.objects.filter(title="test").first() e.content_object = models.Publish.objects.filter(id=4).first() e.save()
删除
因为我使用的的django2.0, 在创建外键的时候必须指定参数on_delete=models.CASCADE, 将出版社删除了book也就没了
models.Publish.objects.filter(id=1).delete()
总结
使用ContentType来处理大量的外键关系