Django 學(xué)習(xí)筆記之模型高級(jí)用法(上)

題圖:by thefolkpr0ject from Instagram

前面有兩篇文章簡(jiǎn)單介紹 Django 的模型,這一部分算是基礎(chǔ)知識(shí)。我自己近期也總做了下總結(jié),將花大概兩篇的篇幅來分享下模型的一些高級(jí)用法。

如果想熟悉 Django 的用法,我認(rèn)為應(yīng)該一開始要熟悉一些細(xì)節(jié)用法,后面再了解 Django 的實(shí)現(xiàn)原理。而細(xì)節(jié)用法往往體現(xiàn)在一些差別用法,難以理解的知識(shí)點(diǎn)上。

1 復(fù)雜的字段類型

經(jīng)過前面的學(xué)習(xí),我們知道模型的字段類型一方面是指定數(shù)據(jù)庫(kù)表的列名稱和數(shù)據(jù)類型,另一方面決定 HTML 中的表單標(biāo)簽類型。

1.1 整數(shù)類型的區(qū)別

Django 的整數(shù)類型有三個(gè),分別是 IntegerFieldBigIntegerFieldSmallIntegerField。這三個(gè)字段區(qū)別在于取值范圍。IntegerField 在 Django 所有支持的數(shù)據(jù)庫(kù)中,合法取值范圍是 -2147483648 到 2147483647。而 BigIntegerField 是一個(gè) 64 位整數(shù),它允許的值范圍是 -9223372036854775808 到 9223372036854775807。所以在數(shù)據(jù)庫(kù)遷移的時(shí)候,特別數(shù)據(jù)庫(kù)中有 Sqlite 時(shí),要更加注意數(shù)字的取值范圍。SmallIntegerField 取值范圍是 -32768 到 32767。

1.2 自增類型的區(qū)別

AutoFiledBigAutoFiled 都是自增類型,它們都是由整數(shù)類型演化而來。AutoFiled 是一個(gè)根據(jù)實(shí)際 ID 自動(dòng)增長(zhǎng)的 IntegerField。通常不需要直接使用它,如果表中沒有設(shè)置主鍵時(shí),Django 將會(huì)自動(dòng)添加一個(gè)自增主鍵。BigAutoField 其實(shí)也是一個(gè) BigIntegerField,但它支持 ID 自動(dòng)增長(zhǎng)。所以它的取值范圍不能為負(fù)數(shù)和零了。

1.3 時(shí)間類型

DateField 和 DateTimeField 中的兩個(gè)重要屬性 auto_nowauto_now_add 默認(rèn)值都是 Flase。 設(shè)置 auto_now 或者 auto_now_add 的值為 True,間接給該字段設(shè)置了 editable=False 和 blank=True 。給參數(shù)賦值需要傳遞一個(gè) datetime.date 對(duì)象。如果時(shí)間是一串字符串,則轉(zhuǎn)化為 date 對(duì)象。

DateField 支持輸入值的形式如下:

['%Y-%m-%d',      # '2006-10-25'
 '%m/%d/%Y',      # '10/25/2006'
 '%m/%d/%y']      # '10/25/06'

DateTimeField 支持輸入值的形式如下:

['%b %d %Y',      # 'Oct 25 2006'
 '%b %d, %Y',     # 'Oct 25, 2006'
 '%d %b %Y',      # '25 Oct 2006'
 '%d %b, %Y',     # '25 Oct, 2006'
 '%B %d %Y',      # 'October 25 2006'
 '%B %d, %Y',     # 'October 25, 2006'
 '%d %B %Y',      # '25 October 2006'
 '%d %B, %Y']     # '25 October, 2006'

1.4 FilePathField

該字段是用于保存文件路徑信息的。默認(rèn)最大長(zhǎng)度為 100,當(dāng)可通過 max_length 參數(shù)自定義。它包含幾個(gè)重要的參數(shù):

path:必傳參數(shù)。記錄目錄或者文件的絕對(duì)路徑。例如:/home/monkey
match:可選參數(shù),它是一個(gè)正則表達(dá)式,主要用于匹配過濾出文件名。
recursive:可選參數(shù),表示是否包含子目錄。默認(rèn)值為 Flase。
allow_files:可選參數(shù),表示是否將文件名包括在內(nèi),默認(rèn)值為 True。
allow_folders:可選參數(shù),表示是否將目錄名包括在內(nèi)默認(rèn)值為 Flase。

Django 規(guī)定 allow_files 和 allow_folders 兩者之間必須有一個(gè)值為 True。

1.5 FileField

上傳文件字段,常見于表單中。一般而言,文件都是保存在服務(wù)器的硬盤中。因此,該字段在數(shù)據(jù)庫(kù)中其實(shí)是一個(gè)字符串類型,默認(rèn)最大長(zhǎng)度100,可以通過max_length參數(shù)自定義。

FileField 有兩個(gè)重要的可選參數(shù):upload_tostorage

  • upload_to
    upload_to 是指定文件上傳的目錄。用法如下:
class MyModel(models.Model):
    # 文件上傳到 MEDIA_ROOT/uploads
    upload = models.FileField(upload_to='uploads/')
    # 或者
    # 文件上傳到 MEDIA_ROOT/uploads/2015/01/30
    upload = models.FileField(upload_to='uploads/%Y/%m/%d/')

其中 MEDIA_ROOT 是在 settings.py 中設(shè)置,表示上傳文件的根目錄。另外還需要設(shè)置 MEDIA_URL, 它表示上傳文件對(duì)外能訪問的 url 地址。

  • Storage
    Storage 是一個(gè)文件操作對(duì)象。它提供 size(path)、open(path).read()、delete(path)、exists(path)等方法來操作文件。

1.6 ImageField

保存圖像文件的字段。ImageField 用法跟 FileField 類似。除了需要在 seeting.py 中增加相關(guān)配置,還都擁有共同的 upload_to 字段選項(xiàng)。

它還有額外的可選參數(shù):一個(gè)是 height_field,表示保存圖片的高度。 另一個(gè)是 width_field,表示保存圖片的寬度。

2 關(guān)系字段

之前文章講了三種關(guān)系字段的類型、定義、作用。今天講下其中的一些字段選項(xiàng)。

2.1 ForeignKey

1) on_delete
在 Django 2.0 中,設(shè)置外鍵時(shí)需要添加一個(gè) on_delete 選項(xiàng)。外鍵本身涉及到兩個(gè)表的數(shù)據(jù),況且外鍵在數(shù)據(jù)庫(kù)中是有約束行為。所以 on_delete 參數(shù)是 Django 模擬 SQL 約束的行為。

on_delete 有幾個(gè)可選值:

  • CASCADE:這就是默認(rèn)的選項(xiàng),級(jí)聯(lián)刪除,你無需顯性指定它。
  • PROTECT: 保護(hù)模式,如果采用該選項(xiàng),刪除的時(shí)候,會(huì)拋出 ProtectedError 錯(cuò)誤。
  • SET_NULL: 置空模式,刪除的時(shí)候,外鍵字段被設(shè)置為空,前提就是blank=True, null=True,定義該字段的時(shí)候,允許為空。
  • SET_DEFAULT: 置默認(rèn)值,刪除的時(shí)候,外鍵字段設(shè)置為默認(rèn)值,所以定義外鍵的時(shí)候注意加上一個(gè)默認(rèn)值。
  • SET(): 自定義對(duì)應(yīng)的實(shí)體的值。

2)limit_choices_to
該參數(shù)用于限制外鍵所能關(guān)聯(lián)的對(duì)象,只能用于 Django 的 ModelForm(Django的表單模塊)和 admin 后臺(tái),對(duì)其它場(chǎng)合無限制功能。該值接受是一個(gè)字典、返回一個(gè)字典的函數(shù)

  1. db_constraint
    默認(rèn)情況下,這個(gè)參數(shù)被設(shè)為 True,表示遵循數(shù)據(jù)庫(kù)約束。如果設(shè)為 False,那么將無法保證數(shù)據(jù)的完整性和合法性。

4) related_name
用于關(guān)聯(lián)對(duì)象反向引用模型的名稱。主要用于反向查詢,即外鍵源模型實(shí)例通過管理器返回第一個(gè)模型的所有實(shí)例。

默認(rèn)情況下,這個(gè)管理器的名字為 foo_set,其中 foo 是源模型名字的小寫。例如:

# 在終端下使用 Django
>>>b = Book.objects.get(id=1)
# 其中 entry_set 為默認(rèn)的 related_name
>>>b.entry_set.all() 
>>>b.entry_set.filter(headline__contains='天龍八部')
>>>b.entry_set.count()

如果我們?cè)O(shè)置 related_name='novels',那么上面的代碼將變?yōu)椋?/p>

# 在終端下使用 Django
>>>b = Book.objects.get(id=1)
# 其中 entry_set 為默認(rèn)的 related_name
>>>b.novels.all() 
>>>b.novels.filter(headline__contains='天龍八部')
>>>b.novels.count()

5)related_query_name
反向查詢的關(guān)系查詢集名稱。用于從目標(biāo)模型反向過濾模型對(duì)象的名稱。具體用法如下:

class Tag(models.Model):
    article = models.ForeignKey(
        Article,
        on_delete=models.CASCADE,
        related_name="tags",
        related_query_name="tag",
    )
    name = models.CharField(max_length=255)

# 現(xiàn)在可以使用 tag作為查詢名
Article.objects.filter(tag__name="important")

3 字段選項(xiàng)

字段選項(xiàng)是給每個(gè) Field 指定一些屬性。

db_column: 指定當(dāng)前數(shù)據(jù)庫(kù)表中該字段的列名。如果沒有指定,Django 默認(rèn)將 Field 名作為字段名。

db_index: 如果賦值為 True, 將會(huì)為這個(gè)字段創(chuàng)建數(shù)據(jù)庫(kù)索引。

db_tablespace:如果該字段已經(jīng)設(shè)置了索引,db_tablespace 用于指定字段索引的數(shù)據(jù)庫(kù)表空間的名字。另外還需要看使用的數(shù)據(jù)庫(kù)支不支持表空間。如果不支持,該參數(shù)設(shè)置沒有效果。

editable:設(shè)置該字段是否能被編輯,默認(rèn)是 True。如果設(shè)為 False , 這個(gè)字段將不會(huì)出現(xiàn)在 admin 或者其他 ModelForm 中。 同時(shí)也會(huì)跳過 模型驗(yàn)證 。

error_messages:用于自定義錯(cuò)誤提示信息。參數(shù)接受的是字典類型的值。字典的 key 可以是 null, blank, invalid, invalid_choice, unique, 和 unique_for_dat 其中的一個(gè)。

help_text:用于前端頁(yè)面上顯示提示信息。要確保頁(yè)面不存在 XXS 漏洞,需要使用django.utils.html.escape() 對(duì)內(nèi)容進(jìn)行轉(zhuǎn)義。

unique_for_date:設(shè)置為 DateField 或者 DateTimeField 字段的名字,表示要求該字段對(duì)于相應(yīng)的日期字段值是唯一的。例如,字段 title 設(shè)置了 unique_for_date="pub_date" ,那么Django將不會(huì)允許在同一 pub_date 的兩條記錄的 title 相同。

unique_for_month:用法跟 unique_for_date 類似。

unique_for_year:用法跟 unique_for_date 類似。

verbose_name:為字段設(shè)置別名。對(duì)于每一個(gè)字段類型,除了 ForeignKey、ManyToManyField和 OneToOneField 這三個(gè)特殊的關(guān)系類型,其第一可選位置參數(shù)都是 verbose_name。如果用戶沒有定義該選項(xiàng), Django會(huì)自動(dòng)將自動(dòng)創(chuàng)建,內(nèi)容是該字段屬性名中的下劃線轉(zhuǎn)換為空格的結(jié)果。

比如這個(gè)例子中描述名是 person's first name:

first_name = models.CharField("person's first name", max_length=30)

而沒有主動(dòng)設(shè)置時(shí),則是 first name:

first_name = models.CharField(max_length=30)

對(duì)于外鍵、多對(duì)多和一對(duì)一字字段,由于第一個(gè)參數(shù)需要用來指定關(guān)聯(lián)的模型。因此必須用關(guān)鍵字參數(shù) verbose_name 來明確指定。如下:

poll = models.ForeignKey(
    Poll,
    on_delete=models.CASCADE,
    verbose_name="the related poll",
)
sites = models.ManyToManyField(Site, verbose_name="list of sites")
place = models.OneToOneField(
    Place,
    on_delete=models.CASCADE,
    verbose_name="related place",
)

另外 verbose_name 不用大寫首字母,在必要的時(shí)候 Django 會(huì)自動(dòng)大寫首字母。

validators:該字段將要運(yùn)行的一個(gè)驗(yàn)證器的列表。例如 RegexValidator、EmailValidator。

4 寫在最后

我新建一個(gè) Python Web 學(xué)習(xí)交流 QQ 群,群號(hào):701534112。歡迎大家加群,一起交流,一起學(xué)習(xí),一起進(jìn)步。


Python Web 學(xué)習(xí)交流群

往前 Django 學(xué)習(xí)筆記文章
Django 學(xué)習(xí)筆記之環(huán)境搭建
Django 學(xué)習(xí)筆記之初始
Django 學(xué)習(xí)筆記之視圖與URL配置
Django 學(xué)習(xí)筆記之模板
Django 學(xué)習(xí)筆記之模型(上)
Django 學(xué)習(xí)筆記之模型(下)
Django 學(xué)習(xí)筆記之后臺(tái)管理
Django 學(xué)習(xí)筆記之模型表單
Django 學(xué)習(xí)筆記之使用舊數(shù)據(jù)庫(kù)
Django 實(shí)戰(zhàn)1:搭建屬于自己社工查詢系統(tǒng)(上)
Django 實(shí)戰(zhàn)1:搭建屬于自己社工查詢系統(tǒng)(下)


本文原創(chuàng)發(fā)布于微信公眾號(hào)「極客猴」,歡迎關(guān)注第一時(shí)間獲取更多原創(chuàng)分享

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容