天天看點

使用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提供的

使用ContentType處理大量的外鍵關系

這樣就友善了很多.

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來處理大量的外鍵關系