目錄結構
3.1.第一步:在【helloworld/hello/models.py】裏新增模型類
3.2.第二步:在【helloworld/hello/admin.py】裏註冊模型類
3.3.第三步:在【helloworld/】根目錄下執行生成數據表的相關語句
3.6.第六步:在後臺新增1條銀行卡基本信息(包含銀行卡拓展信息)
4.1.類OneToOneField裏的兩個個必填參數對應入參值的簡單分析
4.1.1.第一步:看類OneToOneField源碼裏的【__init__】方法裏的內容
4.1.2.第二步:結合實際業務代碼,對必填參數【to】的參數值和必填參數【on_delete】的參數值做分析
4.1.2.2.對必填參數【on_delete】的參數值的理解
4.2.類【StackedInline】和類【TabularInline】的具體運用
1.寫這篇博客的目的
主要記錄:
- 如何通過django去創建【一對一】的表關係;
- 以及如何通過【一對一】的表關係去走對應的完整業務操作;
- 通過修改django裏的哪些代碼配置,使當一張【一】表的數據被刪除後,對應另外一張【一】表的數據會有對應的哪些變化?
2.【一對一】表關係對應的業務例子
我們在現實生活裏會遇到很多一對一的場景。
比如一個最常見的例子是:一張銀行卡記錄了銀行卡賬號和銀行卡用戶名,現在我們要開發一個小功能用來記錄用戶的銀行卡綁定的手機號和綁定的郵箱和綁定的住址,爲了不影響最初的存儲銀行卡數據的數據表【CardInfo】的表結構,可以新增一張數據表【Card_of_Expand_information】來存儲這些新增的表字段;
數據表【CardInfo】裏的一條數據A的主鍵是數據表【Card_of_Expand_information】裏的一條數據B的外鍵,且數據A只能關聯數據B,且數據B只能關聯數據A,那麼這兩張表就是一對一的關係;
完整操作流程可以看接下來的內容;
3.完整操作流程
3.1.第一步:在【helloworld/hello/models.py】裏新增模型類
細節:
- 模型類【Bank】和模型類【CardInfo】是之前就已經創建過的模型類,我們這次只是新增了模型類【Card_of_Expand_information】,但爲了體現這三個模型類存在表關係就都把這三個模型類的代碼都貼出來了;
from django.db import models class Bank(models.Model): '''銀行信息''' bank_name = models.CharField(max_length=50,verbose_name="銀行名稱") city = models.CharField(max_length=30,verbose_name="所在城市") point = models.CharField(max_length=60,verbose_name="所在網點") class Meta: verbose_name_plural = "銀行" def __str__(self): return self.bank_name class CardInfo(models.Model): '''銀行卡基本信息''' card_id = models.CharField(max_length=30, verbose_name="卡號") card_name = models.CharField(max_length=10, verbose_name="姓名") card_info = models.ForeignKey(to=Bank,on_delete=models.CASCADE,verbose_name="選擇銀行",) # card_info = models.ForeignKey(to=Bank,on_delete=models.PROTECT,verbose_name="選擇銀行",) # card_info = models.ForeignKey(to=Bank,on_delete=models.SET_NULL,verbose_name="選擇銀行",null=True) # card_info = models.ForeignKey(to=Bank,on_delete=models.SET_DEFAULT,verbose_name="選擇銀行",default=999999999) # card_info = models.ForeignKey(to=Bank,on_delete=models.SET(value=7777777),verbose_name="選擇銀行",) # card_info = models.ForeignKey(to=Bank,on_delete=models.DO_NOTHING,verbose_name="選擇銀行",) class Meta: verbose_name_plural = '銀行卡基本信息' verbose_name = '銀行卡基本信息詳情頁' # def __str__(self): # return self.card_id class Card_of_Expand_information(models.Model): '''銀行卡拓展信息''' card_number = models.OneToOneField(to=CardInfo, on_delete=models.CASCADE, ) tel = models.CharField(max_length=30, verbose_name="電話", default="") mail = models.CharField(max_length=30, verbose_name="郵箱", default="") city = models.CharField(max_length=10, verbose_name="城市", default="") address = models.CharField(max_length=30, verbose_name="詳細地址", default="") class Meta: verbose_name_plural = '銀行卡拓展信息' verbose_name = "銀行卡拓展信息詳情頁"
3.2.第二步:在【helloworld/hello/admin.py】裏註冊模型類
細節:
- 標註紅色的代碼是這次新增的;
- 爲了能讓數據表【Card_of_Expand_information】的數據能跟數據表【CardInfo】的數據在同一個詳情頁面展示,即爲了讓銀行卡基本信息和銀行卡拓展信息在同一個詳情頁展示,就需要在註冊類【ControlCardInfo】裏重寫屬性inlines的值,且屬性inlines的值的數據類型必須是list,且list裏的值必須是類tackedInline對應的一個子類類名。
- 類【StackedInline】的作用:讓銀行卡拓展信息表的表字段在詳情頁縱向展示(主流都選擇用這個類);
- 類【TabularInline】的作用:讓銀行卡拓展信息表的表字段在詳情頁橫向展示;
具體實際運用可以看下面的代碼塊:
from django.contrib import admin # Register your models here. from hello import models class ControlBank(admin.ModelAdmin): '''銀行信息''' # 顯示的字段 list_display = ["id","bank_name","city","point"] class MoreInfo(admin.StackedInline): model = models.Card_of_Expand_information class ControlCardInfo(admin.ModelAdmin): '''銀行卡信息''' # 顯示的字段 list_display = ["id","card_id","card_name","card_info"] # 在銀行卡基本信息詳情頁面裏顯示銀行卡拓展信息 inlines = [MoreInfo] admin.site.register(models.Bank,ControlBank) admin.site.register(models.CardInfo,ControlCardInfo)
3.3.第三步:在【helloworld/】根目錄下執行生成數據表的相關語句
執行的相關語句和順序是:
- 首先,先執行語句【python manage.py makemigrations】
- 最後,再執行語句【python manage.py migrate】
相關結果如下:
- 會生成一張對應的數據表【hello_card_of_expand_information】;
3.4.第四步:重啓服務
3.5.第五步:成功登陸admin管理後臺
3.6.第六步:在後臺新增1條銀行卡基本信息(包含銀行卡拓展信息)
4.相關知識點
4.1.類OneToOneField裏的兩個必填參數對應入參值的簡單分析
細節:
- 從類OneToOneField的類名,可以直觀知道單詞OneToOneField的中文含義是【一對一】;
4.1.1.第一步:看類OneToOneField源碼裏的【__init__】方法裏的內容
class OneToOneField(ForeignKey): """ A OneToOneField is essentially the same as a ForeignKey, with the exception that it always carries a "unique" constraint with it and the reverse relation always returns the object pointed to (since there will only ever be one), rather than returning a list. """ # Field flags many_to_many = False many_to_one = False one_to_many = False one_to_one = True related_accessor_class = ReverseOneToOneDescriptor forward_related_accessor_class = ForwardOneToOneDescriptor rel_class = OneToOneRel description = _("One-to-one relationship") def __init__(self, to, on_delete, to_field=None, **kwargs): kwargs['unique'] = True super().__init__(to, on_delete, to_field=to_field, **kwargs)
截取這部分源碼:
def __init__(self, to, on_delete, to_field=None, **kwargs): kwargs['unique'] = True super().__init__(to, on_delete, to_field=to_field, **kwargs)
從這部分源碼可以簡單看出來:類OneToOneField被實例化時,必須給兩個必填參數【to】和【on_delete】分別賦值,其他入參的入參值一般情況下保持默認值即可;
4.1.2.第二步:結合實際業務代碼,對必填參數【to】的參數值和必填參數【on_delete】的參數值做分析
實際業務代碼如下:
class Card_of_Expand_information(models.Model): '''銀行卡拓展信息''' card_number = models.OneToOneField(to=CardInfo, on_delete=models.CASCADE, ) tel = models.CharField(max_length=30, verbose_name="電話", default="") mail = models.CharField(max_length=30, verbose_name="郵箱", default="") city = models.CharField(max_length=10, verbose_name="城市", default="") address = models.CharField(max_length=30, verbose_name="詳細地址", default="") class Meta: verbose_name_plural = '銀行卡拓展信息' verbose_name = "銀行卡拓展信息詳情頁"
截取這部分業務代碼:
card_number = models.OneToOneField(to=CardInfo, on_delete=models.CASCADE, )
4.1.2.1.對必填參數【to】的參數值的理解
參數【to】的含義是:關聯到對應的一張表(這張表在一對一表關係裏是兩張表裏被關聯的那張表);
參數【to】的參數值:必須只能是這個【一對一表關係裏的】兩個模型類裏的其中一個被關聯的模型類的模型類名;
4.1.2.2.對必填參數【on_delete】的參數值的理解
參數【on_delete】的含義是:通過類OneToOneField關聯起來的表關係爲一對一的兩張表,當爲一的表的表數據被物理刪除後,在爲一的另外一張表的表裏跟這些被物理刪除的表數據關聯的表數據會發生對應的變化;
參數【on_delete】的參數值有哪些並各自有哪些使用場景,可以參考之前寫的這篇博客(因爲這篇博客已經寫的很詳細了,所以在這篇博客裏就不重複寫一遍了),這篇博客地址爲:4.1.2.2.對必填參數【on_delete】的參數值的理解;
4.2.類【StackedInline】和類【TabularInline】的具體運用
首先,我們要知道這兩個類分別實現的功能是:
- 類【StackedInline】的作用:讓銀行卡拓展信息表的表字段在詳情頁縱向展示(主流都選擇用這個類);
- 類【TabularInline】的作用:讓銀行卡拓展信息表的表字段在詳情頁橫向展示;
4.2.1.類【StackedInline】的具體運用
假如現在實際代碼塊如下(看標註紅色的代碼):
class ControlBank(admin.ModelAdmin): '''銀行信息''' # 顯示的字段 list_display = ["id","bank_name","city","point"] class MoreInfo(admin.StackedInline): model = models.Card_of_Expand_information class ControlCardInfo(admin.ModelAdmin): '''銀行卡信息''' # 顯示的字段 list_display = ["id","card_id","card_name","card_info"] # 在銀行卡基本信息詳情頁面裏顯示銀行卡拓展信息 inlines = [MoreInfo] admin.site.register(models.Bank,ControlBank) admin.site.register(models.CardInfo,ControlCardInfo)
對應的詳情頁面裏的內容展示效果如下:
4.2.2.類【TabularInline】的具體運用
假如現在實際代碼塊如下(看標註紅色的代碼):
class ControlBank(admin.ModelAdmin): '''銀行信息''' # 顯示的字段 list_display = ["id","bank_name","city","point"] class MoreInfo(admin.TabularInline): model = models.Card_of_Expand_information class ControlCardInfo(admin.ModelAdmin): '''銀行卡信息''' # 顯示的字段 list_display = ["id","card_id","card_name","card_info"] # 在銀行卡基本信息詳情頁面裏顯示銀行卡拓展信息 inlines = [MoreInfo] admin.site.register(models.Bank,ControlBank) admin.site.register(models.CardInfo,ControlCardInfo)
對應的詳情頁面裏的內容展示效果如下: