日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

Django Model设计详解

發(fā)布時間:2023/12/20 编程问答 38 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Django Model设计详解 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

Django Model 設(shè)計

Django Model設(shè)計是Django五項基礎(chǔ)核心設(shè)計之一(Model設(shè)計,URL配置,View編寫,Template設(shè)計,From使用),也是MVC模式中重要的環(huán)節(jié)。

如果圖片無法訪問,大家可以移步GitHub Django Model 設(shè)計查看

Model是數(shù)據(jù)模型,并不是數(shù)據(jù)庫,它描述了數(shù)據(jù)的構(gòu)成和他們之間的邏輯關(guān)系,在Django中,Model設(shè)計實質(zhì)上就是一個類,所以我們可以直接站在類的角度來看Model,這樣可以盡量避免一些晦澀的概念影響理解。

下面是python中一個基本類的構(gòu)成

class ClassName(object):# 屬性(類屬性)Attribute = ""# 方法def Method():pass

根據(jù)上面python中的類,我們依次研究Django Model

  • 基類:定義Django Model的類必須繼承自models.Model
  • 類名:在Django Model設(shè)計中,類名會被當(dāng)作是這個數(shù)據(jù)模型的名稱。
  • 類屬性:Django Model設(shè)計過程中,類屬性有兩方面的作用,一是申明字段,二是申明關(guān)系(一對多,多對多,一對一)
  • 方法:由于是派生類,所以我們不需要自己定義很多方法,Model基類已經(jīng)做的足夠完善了,只是在有必要的時候我們需要重寫一些方法,如常見的__str__等
  • 內(nèi)嵌類Meta:Django Model設(shè)計過程中,內(nèi)嵌類Meta用來定義元數(shù)據(jù),所謂元數(shù)據(jù)就是不是字段的任何數(shù)據(jù),比如定義排序規(guī)則等

下面依次介紹字段,關(guān)系,Meta

1.字段 Field

都說官方文檔才是學(xué)習(xí)一門語言最好的教程,訪問官方文檔

1.1 字段類型(Field types)

字面意思,用來申明該字段的類型,比如常見的字符,數(shù)字,日期,郵箱等待,下面列舉常見的字段類型

AutoField(主鍵)

這一個字段一般不需要我們手動定義,主要用于ID的自動遞增,Django會默認為我們創(chuàng)建一個id

# 每一個Model Django都會為我們添加這個字段 id = models.AutoField(primary_key=True)

如果想把自己定義的字段設(shè)置為主鍵,需要添加參數(shù)primary_key,這時(顯式設(shè)置主鍵)Django將不會為我們添加ID字段

與之類似還有一個BigAutoField,它支持更大的范圍,最大到9223372036854775807(九百二十億億)足夠絕大多數(shù)的使用

IntegerField(整數(shù)字段)

字面意思,用來保存整數(shù)的字段,支持 -2147483648 到 2147483647 的數(shù)字

同樣與之類似有BigIntegerField 支持-9223372036854775808 到 9223372036854775807 的數(shù)字

類似還有FloatField,支持浮點數(shù)

BooleanField(布爾字段)

用來存儲布爾值,與之類似的還有NullBooleanField,NullBooleanField相當(dāng)于BooleanField(null=true),不過在Django 2.1 之后不建議使用后者,應(yīng)為它有可能在未來版本被棄用

CharField(字符字段)

這應(yīng)該是最常用的一個字段了吧,用于少量的字符串的儲存(大量字符串請使用TextField)這個字段有一個必須參數(shù)max_length用來申明允許儲存的最大長度

class CharField(Field):description = _("String (up to %(max_length)s)")# ...def _check_max_length_attribute(self, **kwargs):if self.max_length is None:return [checks.Error("CharFields must define a 'max_length' attribute.",obj=self,id='fields.E120',)]

根據(jù)源碼,我們可以發(fā)現(xiàn)如果不指定max_length會直接報"CharFields must define a ‘max_length’ attribute."

DateField(時間日期字段)

該字段有兩個常用參數(shù) auto_now 和 auto_now_add

  • auto_now :指定這個參數(shù),可以在每次調(diào)用save()時將當(dāng)前時間作為字段的值(會覆蓋默認值或之前的值),但使用QuerySet.update()等方法不會跟新值
  • auto_now_add : 在初始化會以當(dāng)前時間戳作為值給字段賦值,不管你有沒有定義默認值,定義了也會被覆蓋
  • 區(qū)別:使用auto_now會在每次save()時修改字段值,而auto_now_add只是在首次創(chuàng)建對象時才會把當(dāng)前時間給字段。
  • 如果你想能夠修改這個字段的值,請使用default=date.today需要引入from datetime.date.today()
  • auto_now,auto_now_add與default是互斥的,任何一種組合都會出錯
  • 將auto_now或auto_now_add設(shè)置為True的結(jié)果與editable = False和blank = True的效果一樣

與DateField類似的還有DateTimeField

  • 如果使用DateTimeField想要修改字段的值,需要使用default=timezone.now 同樣需要引入from django.utils.timezone.now()
  • 另外還有TimeField,用來表示時間,接受的參數(shù)與DateField一樣

[外鏈圖片轉(zhuǎn)存失敗(img-w7TfUVCo-1567244122546)(…/image/DjangoModel_01.png)]

EmailField

實質(zhì)上是CharField,不過使用EmailValidator檢查了字符串是否是有效電子郵件地址而已,默認max_length=254

TextField

實質(zhì)上也是一個CharField,是一個比較大的文本字段

FileField

class FileField(upload_to=None, max_length=100, **options)

正如文檔所說,這是一個文件上傳字段,有兩個可選參數(shù)upload_to和max_length,后者默認100

upload_to

見名知意,upload_to用來申明上傳目錄,如果給定一個字符串類型初值,Django會在他后面添加時間(就是以上傳時間分類文件),用戶上傳文件一般保存到media目錄中,media目錄路徑需要在setting.py里定義

MEDIA_ROOT = os.path.join(BASE_DIR, "media")

這個media文件夾如果我們沒有建立,保存文件時Django會自動創(chuàng)建

class MyModel(models.Model):# file will be uploaded to MEDIA_ROOT/uploadsupload = models.FileField(upload_to='uploads/')# or...# file will be saved to MEDIA_ROOT/uploads/2015/01/30upload = models.FileField(upload_to='uploads/%Y/%m/%d/')

如果需要動態(tài)存儲文件,如按用戶存儲,可以把一個函數(shù)的返回值作為upload_to的值,這個函數(shù)必須接受兩個參數(shù):instance(主鍵,傳給當(dāng)前文件的唯一實例)和filename(文件名),如:

def user_directory_path(instance, filename):# file will be uploaded to MEDIA_ROOT/user_<id>/<filename>return 'user_{0}/{1}'.format(instance.user.id, filename)class MyModel(models.Model):upload = models.FileField(upload_to=user_directory_path)

這里看著有點復(fù)雜,其實也不難,instance是當(dāng)前FileField的模型實例的模型實例,也就是我們定義的字段,上面的示例是的user是和User表對應(yīng)的,當(dāng)然也可以不是user,比如:

def user_directory_path(instance, filename):# 我沒有用user,而是自己定義了一個name字段return 'user_{0}/{1}'.format(instance.name, filename)class Diary(models.Model):name = models.CharField(max_length=10)creat_time = models.DateTimeField(auto_now_add=True)time = models.TimeField(auto_now=True)upload = models.FileField(upload_to=user_directory_path,default="")class Meta:verbose_name = "Diary"verbose_name_plural = "Diarys"

[外鏈圖片轉(zhuǎn)存失敗(img-SGnfpXgs-1567244122548)(…/image/DjangoModel_02.png)]

保存之后就可以看見項目根目錄下的文件了

[外鏈圖片轉(zhuǎn)存失敗(img-KUPPj7yc-1567244122552)(…/image/DjangoModel_03.png)]

使用時間也是一樣的

class Diary(models.Model):name = models.CharField(max_length=10)creat_time = models.DateTimeField(auto_now_add=True)time = models.TimeField(auto_now=True)# upload = models.FileField(upload_to=user_directory_path,default="")upload = models.FileField(upload_to='user_123/%Y/%m/%d/',default="")class Meta:verbose_name = "Diary"verbose_name_plural = "Diarys"def __str__(self):return self.name

[外鏈圖片轉(zhuǎn)存失敗(img-oPc8recT-1567244122558)(…/image/DjangoModel_04.png)]

FileField 和 FieldFile

當(dāng)您訪問model上的FileField時,會獲得一個FieldFile的實例作為訪問基礎(chǔ)文件的代理。它是繼承自python的File的,有read(),write()等,還自己封裝了一些方法,如url,name等,看官網(wǎng)

ImageField

class ImageField(FileField):attr_class = ImageFieldFiledescriptor_class = ImageFileDescriptordescription = _("Image")def __init__(self, verbose_name=None, name=None, width_field=None, height_field=None, **kwargs):self.width_field, self.height_field = width_field, height_fieldsuper().__init__(verbose_name, name, **kwargs)

由源碼可以看到,ImageField是繼承自FileField的一個字段,除了FileField中的特殊屬性外,它額外添加了width_field, height_field兩個屬性用來描述圖片大小,它會檢查一個文件是否是圖片,其他用法與FileField一樣。

其他

除了上面常見的這些,還有一些字段,諸如用作URL的URLField,還有不同大小的IntField,如PositiveSmallIntegerFieldPositiveIntegerFieldSmallIntegerField,用作IP地址的GenericIPAddressField等待,此外,你也可以自定義字段,看文檔就好。

1.2 參數(shù)總結(jié)

之前遇到很多參數(shù),如max_length,default等,這里再做總結(jié)

null

如果為True,Django將在數(shù)據(jù)庫中將空值存儲為NULL。 默認值為False。

避免在基于字符串的字段(如CharField和TextField)上使用null。 如果基于字符串的字段具有null = True,則表示它具有“無數(shù)據(jù)”的兩個可能值:NULL和空字符串。 在大多數(shù)情況下,為“無數(shù)據(jù)”提供兩個可能的值是多余的; Django約定是使用空字符串,而不是NULL。

blank

如果為真,則允許該字段為空。默認是假的。注意,這與null不同。null純粹與數(shù)據(jù)庫相關(guān),而blank則與驗證相關(guān)。如果字段為blank=True,表單驗證將允許輸入空值。如果字段為空=False,則需要該字段。

choices

為字段提供選項,首先他的值應(yīng)該是一個可迭代對象,如列表或元組,其次每一項中都應(yīng)該包含兩個元素,第一個是要存儲到數(shù)據(jù)庫中的真實值,第二個是展示給人的值,比如

class Diary(models.Model):SEX_CHOICES = (('boy', 'BOY'),('girl', 'GIRL'),('else', 'ELSE'))sex = models.CharField(max_length=10,choices=SEX_CHOICES,default="")

這個Model展示在admin頁面是這樣的,請忽略其他字段,那是之前寫的

[外鏈圖片轉(zhuǎn)存失敗(img-mRp1xKaa-1567244122563)(…/image/DjangoModel_05.png)]

在隨便存儲一個值后,在MySQL數(shù)據(jù)庫中可以看到是這樣的(最后一項)

[外鏈圖片轉(zhuǎn)存失敗(img-0JWk72Nk-1567244122565)(…/image/DjangoModel_06.png)]

展示給我們的是后面大寫的,而存儲在數(shù)據(jù)庫中的則是前面小寫的

除此之外,如果Model中有多個字段需要選項,可以把這些選項分類放在同一個可迭代對象中,如

MEDIA_CHOICES = (('Audio', (('vinyl', 'Vinyl'),('cd', 'CD'),)),('Video', (('vhs', 'VHS Tape'),('dvd', 'DVD'),)),('unknown', 'Unknown'), )

default

指定默認值,可以是默認字符串也可以是函數(shù)返回值

db_column

用于此字段的數(shù)據(jù)庫列的名稱。 如果沒有給出,Django將使用該字段的名稱。

db_index

如果為True,則將為此字段創(chuàng)建數(shù)據(jù)庫索引。

db_tablespace

如果此字段已編制索引,則用于此字段索引的數(shù)據(jù)庫表空間的名稱。 默認值為項目的DEFAULT_INDEX_TABLESPACE設(shè)置(如果已設(shè)置)或模型的db_tablespace(如果有)。 如果后端不支持索引的表空間,則忽略此選項。

editable

如果為False,則該字段不會顯示在admin或任何其他ModelForm中。 在模型驗證期間也會跳過它們。 默認為True。

error_messages

error_messages參數(shù)允許您覆蓋字段將引發(fā)的默認消息。傳入一個字典,其中的關(guān)鍵字與您要覆蓋的錯誤消息相匹配。

在 表單字段 級別或者 表單 Meta 級別定義的錯誤信息優(yōu)先級總是高于在 模型字段 級別定義的。

在 模型字段 上定義的錯誤信息只有在 模型驗證 步驟引發(fā) ValidationError 時才會使用,并且沒有在表單級定義相應(yīng)的錯誤信息。

您可以通過添加 NON_FIELD_ERRORS 鍵到 ModelForm 內(nèi)部的 Meta 類的 error_messages 中來覆蓋模型驗證引發(fā)的 NON_FIELD_ERRORS 錯誤信息。

help_text

使用表單小部件顯示的額外“幫助”文本。 即使您的字段未在表單上使用,它也對文檔很有用。

請注意,此值不會在自動生成的表單中進行HTML轉(zhuǎn)義。 如果您愿意,這可以讓您在help_text中包含HTML。 例如:

help_text="Please use the following format: <em>YYYY-MM-DD</em>."

primary_key

如果為True,則此字段將作為Model的主鍵

unique

如果需要設(shè)置該字段值唯一,需要把unique設(shè)置為True,如果嘗試保存一個已經(jīng)存在的值,將會引發(fā)django.db.IntegrityError異常,我們需要捕捉這個異常,用于諸如用戶名等方面

總結(jié)

常用的主要這幾個

  • blank:允許為空
  • choices:提供選擇
  • default:提供默認值
  • db_column:提供數(shù)據(jù)表列名
  • unique:設(shè)置是否唯一

2 關(guān)系字段

關(guān)系也是一種字段,只是這個字段的值是別的某個或多個Model,只有三種關(guān)系字段 ForeignKey,ManyToManyField 和 OneToOneField

2.1 ForeignKey

這是一種多對一的關(guān)系。 需要兩個參數(shù):要關(guān)聯(lián)的模型類和on_delete選項。

如果要創(chuàng)建遞歸關(guān)系 ( 與自身具有多對一關(guān)系的對象 )請使用

models.ForeignKey('self',on_delete = models.CASCADE)。

如果需要在尚未定義的模型上創(chuàng)建關(guān)系,可以使用模型的名稱,而不是模型對象本身:

class Diary(models.Model):Ordinary_user = models.ForeignKey('Demo2',on_delete=models.CASCADE,default="")class Demo2(models.Model):email: str = models.EmailField(blank=True,db_column="郵箱",default="")Tel_Num = models.CharField(max_length=20,blank=True,db_column="聯(lián)系電話",default="")address: str = models.CharField(max_length=100,blank=True,db_column="住址",default="")ID_card = models.CharField(max_length=20, db_column="身份證號",default="")

這樣,我們建立了兩張表,Diary表中Ordinary_user字段與Demo2是一個多對一的關(guān)系,先看一下兩張表在MySQL數(shù)據(jù)庫中的樣子

先是diary表,同樣請忽略其他字段,表名是app名_類名

[外鏈圖片轉(zhuǎn)存失敗(img-j7xvKUZD-1567244122568)(…/image/DjangoModel_07.png)]

其次是Demo2表

[外鏈圖片轉(zhuǎn)存失敗(img-uHS783Pt-1567244122571)(…/image/DjangoModel_08.png)]

發(fā)現(xiàn)Django把ForeignKey字段的列名命名為目標(biāo)Model名_id這里之所以是_id是應(yīng)為id是這個表的主鍵,而里面存儲的也是對應(yīng)的id序號,就是通過保存主鍵的方式實現(xiàn)一對多的。

然后再看一下再admin界面的樣子把

[外鏈圖片轉(zhuǎn)存失敗(img-oGREHt43-1567244122573)(…/image/DjangoModel_09.png)]

點加號會打開一個新窗口讓你添加Dome的數(shù)據(jù),應(yīng)該挺方便

[外鏈圖片轉(zhuǎn)存失敗(img-BcLglQBH-1567244122575)(…/image/DjangoModel_10.png)]

on_delete

這是必選參數(shù),當(dāng)刪除ForeignKey引用的對象時,Django將模擬on_delete參數(shù)指定的SQL約束的行為。總共有六種選擇
CASCADE,PROTECT,SET_NULL,SET_DEFAULT,SET(),DO_NOTHING

  • CASCADE:級聯(lián)刪除。 Django模擬SQL約束ON DELETE CASCADE的行為,并刪除包含F(xiàn)oreignKey的對象。
  • PROTECT:通過引發(fā)ProtectedError(django.db.IntegrityError的子類)來防止刪除引用的對象。
  • SET_NULL:將ForeignKey設(shè)置為null; 這只有在null為True時才有可能
  • SET_DEFAULT:將ForeignKey設(shè)置為其默認值; 必須設(shè)置ForeignKey的默認值。
  • SET():將ForeignKey設(shè)置為傳遞給SET()的值,或者如果傳入了回調(diào)函數(shù),則調(diào)用它的結(jié)果。 在大多數(shù)情況下,為了避免在導(dǎo)入models.py時執(zhí)行查詢,必須傳遞一個回調(diào)函數(shù)。
  • DO_NOTHING:不采取行動。 如果數(shù)據(jù)庫后端強制實施參照完整性,則除非您手動將SQL ON DELETE約束添加到數(shù)據(jù)庫字段,否則將導(dǎo)致IntegrityError。

2.2 ManyToManyField

多對多的關(guān)系。 只有一個必須參數(shù):與模型相關(guān)的類,它與ForeignKey的工作方式完全相同,包括遞歸和惰性關(guān)系。

2.2.1 參數(shù)

(1).symmetrical

只有在和自己建立多對多關(guān)系時才有效,為true時建立的是對稱關(guān)系,反之為False建立非對稱關(guān)系,默認為True,例如:

class Demo2(models.Model):friends = models.ManyToManyField("self",symmetrical=False,)

默認為true的情況下,如果建立A時指定friend為B,C,那么在B,C中,A也會被申明為自己的朋友,反之則不會

(2).through

Django將自動生成一個表來管理多對多關(guān)系。 但是,如果要手動指定中間表,可以使用through選項指定表示要使用的中間表的Django模型

此選項最常見的用途是,您希望將額外數(shù)據(jù)與多對多關(guān)系相關(guān)聯(lián)。

如果未指定顯式直通模型,則仍可使用隱式直通模型類來直接訪問為保持關(guān)聯(lián)而創(chuàng)建的表。 它有三個字段來鏈接模型。

如果源模型和目標(biāo)模型不同,表中的字段如下:

  • id: 主鍵
  • <containing_model>_id: 申明多對多關(guān)系的模型id
  • <other_model>_id: 指向的模型id

[外鏈圖片轉(zhuǎn)存失敗(img-A9IklSnF-1567244122579)(…/image/DjangoModel_11.png)]

如果原模型與目標(biāo)Model相同(自己與自己建立多對多關(guān)系),表中的字段如下:

  • id:關(guān)系的主鍵。
  • from_ <model> _id:源實例
  • to_ <model> _id:目標(biāo)模型實例

[外鏈圖片轉(zhuǎn)存失敗(img-pRlQ5pOm-1567244122581)(…/image/DjangoModel_12.png)]

(3).through_fields

僅在指定自定義中間模型時使用。 Django通常會確定要使用哪個中間模型字段,以便自動建立多對多關(guān)系。 但是,請考慮以下情況:

from django.db import modelsclass Person(models.Model):name = models.CharField(max_length=50)class Group(models.Model):name = models.CharField(max_length=128)members = models.ManyToManyField(Person,through='Membership',through_fields=('group', 'person'),)class Membership(models.Model):group = models.ForeignKey(Group, on_delete=models.CASCADE)person = models.ForeignKey(Person, on_delete=models.CASCADE)inviter = models.ForeignKey(Person,on_delete=models.CASCADE,related_name="membership_invites",)invite_reason = models.CharField(max_length=64)

Membership有兩個外鍵(person和inviter),這使得關(guān)系模糊不清,Django無法知道使用哪一個。 在這種情況下,您必須使用through_fields明確指定Django應(yīng)使用哪些外鍵,如上例所示。

through_fields接受2元組(‘field1’,‘field2’),其中field1是定義ManyToManyField的模型的外鍵名稱(在本例中為group),field2是外鍵的名稱。 目標(biāo)模型(本例中的person)。

如果中間模型上有多個外鍵到參與多對多關(guān)系的任何(甚至兩個)模型,則必須指定through_fields。 這也適用于使用中間模型時的遞歸關(guān)系,并且模型有兩個以上的外鍵,或者您想要明確指定Django應(yīng)該使用哪兩個。

使用中間模型的遞歸關(guān)系總是被定義為非對稱的 - 也就是說,symmetrical=False 因此,存在“源”和“目標(biāo)”的概念。 在這種情況下,'field1’將被視為關(guān)系的“源”,'field2’將被視為“目標(biāo)”。

2.3 OneToOneField

一對一的關(guān)系。 從概念上講,這類似于具有unique = True的ForeignKey,但關(guān)系的“反向”一側(cè)將直接返回單個對象。

這作為模型的主鍵是最有用的,它以某種方式“擴展”另一個模型; 例如,通過從子模型向父模型添加隱式一對一關(guān)系來實現(xiàn)多表繼承。

需要一個位置參數(shù):與模型相關(guān)的類。 這與ForeignKey完全相同,包括有關(guān)遞歸和惰性關(guān)系的所有選項。

如果沒有為OneToOneField指定related_name參數(shù),Django將使用當(dāng)前模型的小寫名稱作為默認值。

3. Meta

用來定義元數(shù)據(jù)(除字段以外的別的數(shù)據(jù)),常見的元數(shù)據(jù):

  • app_label:如果你定義的Model不在app目錄下的models.py中,就需要指定該字段為app名稱
  • db_table:自定義數(shù)據(jù)表名,如果不指定,默認用app名_model名
  • db_tablespace:指定某些數(shù)據(jù)庫的表空間
  • ordering:指定排序集
  • verbose_name:可讀的名字
  • verbose_name_plural:Model的復(fù)數(shù)形式

總結(jié)

以上是生活随笔為你收集整理的Django Model设计详解的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。