使用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来处理大量的外键关系

 

posted @ 2019-02-13 19:08  王剑威  阅读(225)  评论(0编辑  收藏  举报