1. 程式人生 > 實用技巧 >16 多表設計

16 多表設計

1.表設計

'''
BaseModel基表
    is_delete、create_time、orders、updated_time
下面四表繼承基表,可以繼承兩個欄位
    Book表:
        name、price、img、authors、publish
        is_delete、create_time、orders、updated_time
    Publish表:
        name、address
        is_delete、create_time、orders、updated_time
    Author表:
        name、age
        is_delete、create_time、orders、updated_time
    AuthorDetail表:
        mobile, author
        is_delete、create_time、orders、updated_time
'''

2. 基表建立 (注意設定abstract = True)

from django.db import models


class BaseModel(models.Model):
    """公共模型"""
    orders = models.IntegerField(default=1, verbose_name="排序", help_text='排序')
    # 預設不是刪除,資料庫中是0/1
    is_delete = models.BooleanField(default=False, verbose_name="是否刪除", help_text='是否刪除')
    created_time = models.DateTimeField(auto_now_add=True, verbose_name="新增時間", help_text='新增時間')
    updated_time = models.DateTimeField(auto_now=True, verbose_name="修改時間", help_text='修改時間')

    class Meta:
        # 設定當前模型為抽象模型,在資料遷移的時候django就不會為它單獨建立一張表
        abstract = True  # 宣告該表只是一個抽象表不出現在資料庫中

3.斷關聯多表關係

db_constraint=False (設定了這個就是斷關聯,設定在外來鍵,刪除了作者詳情,也不會刪除作者)

3.1 作用

  1. 物理上斷開關係提升查詢效率
  2. 防止環裝表關係,導致表關係成為死表(即不能在操作表,如果想要在重新操作表,需要刪庫)

3.2 欄位設計

1、外來鍵位置:
	一對多  -- 外來鍵放在多的一方
    一對一  —— 從邏輯正反向考慮,如作者表與作者詳情表,作者刪除級聯作者詳情也刪除,詳情刪除作者依舊存在,所以建議外來鍵在 詳情表 中
    多對多  -- 外來鍵在關係表中
2、ORM正向方向連表查詢
	正向:通過外來鍵欄位 eg:author_detial_obj.author  # 外來鍵設定在作者詳情表,在作者詳情表中查詢作者直接 .author就可以
    反向:通過設定反向查詢related_name的值 eg:author_obj.detail  #外來鍵沒有設定在作者表中,在作者表中通過設定反向查詢.detail查詢作者詳情

3、連表操作關係(外來鍵建在作者詳情表中)
	1)作者刪除,詳情級聯 - on_delete=models.CASCADE    #跟著一起刪除
    2)作者刪除,詳情置空 - null=True, on_delete=models.SET_NULL   #外來鍵欄位清空
    3)作者刪除,詳情重置 - default=0, on_delete=models.SET_DEFAULT
    4)作者刪除,詳情不動 - on_delete=models.DO_NOTHING

4.模型表設計

class BaseModel(models.Model):
    is_delete = models.BooleanField(default=False)  # 預設不是刪除,資料庫中是0/1
    create_time = models.DateTimeField(auto_now_add=True, verbose_name='建立時間')

    # 設定 abstract = True 來宣告基表,作為基表的Model不能在資料庫中形成對應的表
    class Meta:
        abstract = True  # 宣告該表只是一個抽象表不出現在資料庫中


class Book(BaseModel):
    name = models.CharField(max_length=64)
    price = models.DecimalField(max_digits=5, decimal_places=2)
    img = models.ImageField(upload_to='img', default='img/default.jpg')

    # 關聯作者表
    authors = models.ManyToManyField(
        to='Author',
        db_constraint=True,  # 斷開關聯
        related_name='books'  # 反向查詢欄位
    )
    # 關聯出版社表
    publish = models.ForeignKey(
        to='Publish',  # 關聯publish表
        db_constraint=False,  # 斷關聯(斷開Book表和Publish表的關聯,方便刪資料,雖然斷開了關聯但是還能正常使用)
        related_name='books',  # 反向查詢欄位:publish_obj.books就能查出當前出版社出版的的所有書籍
        on_delete=models.DO_NOTHING,  # 設定連表操作關係
    )

    @property
    def publish_name(self):
        return self.publish.name

    @property
    def authorlist(self):
        return self.authors.values('name', 'age', 'detail__mobile').all()

    class Meta:
        db_table = 'book'
        verbose_name = '書籍'
        verbose_name_plural = verbose_name

    def __str__(self):
        return self.name


# 出版社表
class Publish(BaseModel):
    name = models.CharField(max_length=64)
    addres = models.CharField(max_length=64)

    class Meta:
        db_table = 'publish'
        verbose_name = '出版社'
        verbose_name_plural = verbose_name

    def __str__(self):
        return self.name


# 作者表
class Author(BaseModel):
    name = models.CharField(max_length=64)
    age = models.IntegerField()

    class Meta:
        db_table = 'author'
        verbose_name = '作者'
        verbose_name_plural = verbose_name

    def __str__(self):
        return self.name


# 作者詳情
class AuthorDetail(BaseModel):
    """mobile, author、is_delete、create_time"""
    mobile = models.CharField(max_length=11)
    author = models.OneToOneField(
        to='Author',
        db_constraint=False,
        related_name='detail',
        on_delete=models.CASCADE
    )

    class Meta:
        db_table = 'author_detail'
        verbose_name = '作者詳情'
        verbose_name_plural = verbose_name

    def __str__(self):
        return self.author.name