Django 學習筆記之模型高級用法

[TOC]html

1 複雜的字段類型

通過前面的學習,咱們知道模型的字段類型一方面是指定數據庫表的列名稱和數據類型,另外一方面決定 HTML 中的表單標籤類型。前端

1.1 整數類型的區別

Django 的整數類型有三個,分別是 IntegerFieldBigIntegerFieldSmallIntegerField。這三個字段區別在於取值範圍。IntegerField 在 Django 全部支持的數據庫中,合法取值範圍是 -2147483648 到 2147483647。而 BigIntegerField 是一個 64 位整數,它容許的值範圍是 -9223372036854775808 到 9223372036854775807。因此在數據庫遷移的時候,特別數據庫中有 Sqlite 時,要更加註意數字的取值範圍。SmallIntegerField 取值範圍是 -32768 到 32767。python

1.2 自增類型的區別

AutoFiledBigAutoFiled 都是自增類型,它們都是由整數類型演化而來。AutoFiled 是一個根據實際 ID 自動增加的 IntegerField。一般不須要直接使用它,若是表中沒有設置主鍵時,Django 將會自動添加一個自增主鍵。BigAutoField 其實也是一個 BigIntegerField,但它支持 ID 自動增加。因此它的取值範圍不能爲負數和零了。正則表達式

1.3 時間類型

DateField 和 DateTimeField 中的兩個重要屬性 auto_nowauto_now_add 默認值都是 Flase。 設置 auto_now 或者 auto_now_add 的值爲 True,間接給該字段設置了 editable=False 和 blank=True 。給參數賦值須要傳遞一個 datetime.date 對象。若是時間是一串字符串,則轉化爲 date 對象。數據庫

DateField 支持輸入值的形式以下:django

['%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

該字段是用於保存文件路徑信息的。默認最大長度爲 100,當可經過 max_length 參數自定義。它包含幾個重要的參數:服務器

path:必傳參數。記錄目錄或者文件的絕對路徑。例如:/home/monkey match:可選參數,它是一個正則表達式,主要用於匹配過濾出文件名。 recursive:可選參數,表示是否包含子目錄。默認值爲 Flase。 allow_files:可選參數,表示是否將文件名包括在內,默認值爲 True。 allow_folders:可選參數,表示是否將目錄名包括在內默認值爲 Flase。函數

Django 規定 allow_files 和 allow_folders 二者之間必須有一個值爲 True。學習

1.5 FileField

上傳文件字段,常見於表單中。通常而言,文件都是保存在服務器的硬盤中。所以,該字段在數據庫中實際上是一個字符串類型,默認最大長度100,能夠經過max_length參數自定義。

FileField 有兩個重要的可選參數: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 中設置,表示上傳文件的根目錄。另外還須要設置 MEDIA_URL, 它表示上傳文件對外能訪問的 url 地址。

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

1.6 ImageField

保存圖像文件的字段。ImageField 用法跟 FileField 相似。除了須要在 seeting.py 中增長相關配置,還都擁有共同的 upload_to 字段選項。

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

2 關係字段

以前文章講了三種關係字段的類型、定義、做用。今天講下其中的一些字段選項。

2.1 ForeignKey

2.1.1on_delete

在 Django 2.0 中,設置外鍵時須要添加一個 on_delete 選項。外鍵自己涉及到兩個表的數據,何況外鍵在數據庫中是有約束行爲。因此 on_delete 參數是 Django 模擬 SQL 約束的行爲。

on_delete 有幾個可選值:

  • CASCADE:這就是默認的選項,級聯刪除,你無需顯性指定它。
  • PROTECT: 保護模式,若是採用該選項,刪除的時候,會拋出 ProtectedError 錯誤。
  • SET_NULL: 置空模式,刪除的時候,外鍵字段被設置爲空,前提就是blank=True, null=True,定義該字段的時候,容許爲空。
  • SET_DEFAULT: 置默認值,刪除的時候,外鍵字段設置爲默認值,因此定義外鍵的時候注意加上一個默認值。
  • SET(): 自定義對應的實體的值。

2.1.2limit_choices_to

該參數用於限制外鍵所能關聯的對象,只能用於 Django 的 ModelForm(Django的表單模塊)和 admin 後臺,對其它場合無限制功能。該值接受是一個字典、返回一個字典的函數

db_constraint 默認狀況下,這個參數被設爲 True,表示遵循數據庫約束。若是設爲 False,那麼將沒法保證數據的完整性和合法性。

2.1.3related_name

用於關聯對象反向引用模型的名稱。主要用於反向查詢,即外鍵源模型實例經過管理器返回第一個模型的全部實例。

默認狀況下,這個管理器的名字爲 foo_set,其中 foo 是源模型名字的小寫。例如:

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

若是咱們設置 related_name='novels',那麼上面的代碼將變爲:

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

2.1.4related_query_name

反向查詢的關係查詢集名稱。用於從目標模型反向過濾模型對象的名稱。具體用法以下:

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)

# 如今可使用 tag做爲查詢名
Article.objects.filter(tag__name="important")

3 字段選項

字段選項是給每一個 Field 指定一些屬性。

db_column: 指定當前數據庫表中該字段的列名。若是沒有指定,Django 默認將 Field 名做爲字段名。

db_index: 若是賦值爲 True, 將會爲這個字段建立數據庫索引。

db_tablespace:若是該字段已經設置了索引,db_tablespace 用於指定字段索引的數據庫表空間的名字。另外還須要看使用的數據庫支不支持表空間。若是不支持,該參數設置沒有效果。

editable:設置該字段是否能被編輯,默認是 True。若是設爲 False , 這個字段將不會出如今 admin 或者其餘 ModelForm 中。 同時也會跳過 模型驗證 。

error_messages:用於自定義錯誤提示信息。參數接受的是字典類型的值。字典的 key 能夠是 null, blank, invalid, invalid_choice, unique, 和 unique_for_dat 其中的一個。

help_text:用於前端頁面上顯示提示信息。要確保頁面不存在 XXS 漏洞,須要使用django.utils.html.escape() 對內容進行轉義。

unique_for_date:設置爲 DateField 或者 DateTimeField 字段的名字,表示要求該字段對於相應的日期字段值是惟一的。例如,字段 title 設置了 unique_for_date="pub_date" ,那麼Django將不會容許在同一 pub_date 的兩條記錄的 title 相同。

unique_for_month:用法跟 unique_for_date 相似。

unique_for_year:用法跟 unique_for_date 相似。

verbose_name:爲字段設置別名。對於每個字段類型,除了 ForeignKey、ManyToManyField和 OneToOneField 這三個特殊的關係類型,其第一可選位置參數都是 verbose_name。若是用戶沒有定義該選項, Django會自動將自動建立,內容是該字段屬性名中的下劃線轉換爲空格的結果。

好比這個例子中描述名是 person's first name:

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

而沒有主動設置時,則是 first name:

first_name = models.CharField(max_length=30)

對於外鍵、多對多和一對一字字段,因爲第一個參數須要用來指定關聯的模型。所以必須用關鍵字參數 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 不用大寫首字母,在必要的時候 Django 會自動大寫首字母。

validators:該字段將要運行的一個驗證器的列表。例如 RegexValidator、EmailValidator。

4模型的元數據Meta

除了抽象模型,在模型中定義的字段都會成爲表中的列。若是咱們須要給模型指定其餘一些信息,例如排序方式、數據庫表名等,就須要用到 Meta。Meta 是一個可選的類,具體用法以下:

class Author(models.Model):
    name = models.CharField(max_length=40)
    email = models.EmailField()

    class Meta:
        managed = True
        db_table = 'author'

不知你是否對上述代碼有影響。經過 Django 將數據庫表反向生成模型時,Django 會默認帶上 managed 和 db_table 信息。

我主要說下 Meta 一些重要的屬性,其餘屬性你能夠經過文檔信息進行學習。

abstract: 若是 abstract = True,模型會指定爲抽象模型。它至關於面向對象編程中的抽象基類。

proxy:若是設置了proxy = True,表示使用代理模式的模型繼承方式。

db_table:指定當前模型在數據庫的表名。

managed:該屬性默認值爲 True,表示能建立模型和操做數據庫表。

ordering:指定該模型生成的全部對象的排序方式。默認按升序排列,若是在字段名前加上字符 「-」 則表示按降序排列,若是使用字符問號 「?」 表示隨機排列。

ordering = ['pub_date']             # 表示按'pub_date'字段進行升序排列
ordering = ['-pub_date']            # 表示按'pub_date'字段進行降序排列
ordering = ['-pub_date', 'author']  # 表示先按'pub_date'字段進行降序排列,再按`author`字段進行升序排列。

verbose_name:給模型設置別名。若是不指定它,Django 會使用小寫的模型名做爲默認值。

verbose_name = "book"
verbose_name = "圖書"

verbose_name_plural:由於英語單詞有單數和複數兩種形式,這個屬性是模型對象的複數名。中文則跟 verbose_name 值一致。若是不指定該選項,那麼默認的複數名字是 verbose_name 加上 ‘s’ 。

verbose_name_plural = "books"
verbose_name_plural = "圖書"

indexes:爲當前模型創建索引列表。用法以下:

from django.db import models

class Customer(models.Model):
    first_name = models.CharField(max_length=100)
    last_name = models.CharField(max_length=100)

    class Meta:
        indexes = [
            models.Index(fields=['last_name', 'first_name']),
            models.Index(fields=['first_name'], name='first_name_idx'),
        ]

5模型的繼承

根據模型的 Meta 信息設置,模型繼承方式能夠分爲三種:

5.1抽象模型

模型的 Meta 類中含有 abstract = True 屬性。抽象模型通常被看成基類,它持有子類共有的字段。值得注意的是,抽象模型在數據庫中不會生成表。

from django.db import models

# 抽象模型
class Person(models.Model):
    name = models.CharField(max_length=500)
    age = models.PositiveIntegerField()
    
    class Meta:
        abstract = True

# 子模型
class Student(Person):
    school_name = models.CharField(max_length=20)

子模型若是沒有定義 Meta 類,那麼會繼承抽象模型的 Meta 類。可是 abstract 屬性不會被繼承。

5.2多表繼承

這種方式繼承方式,子模型的父模型能夠一個或者多個。

當父類模型是正常的模型,即不是抽象模型,在數據庫中有對應表。

雖然在 Model 層不推薦使用多重繼承,但 Django 的 ORM 仍是支持這樣的使用方式。若是使用多表繼承,子模型跟每一個父模型都會添加一個一對一的關係。

from django.db import models

# 父模型 one
class Model_One(models.Model):
    attr1 = models.CharField(max_length=10)

# 父模型 two
class Model_Two(models.Model):
    attr2 = models.CharField(max_length=10)

# 子模型
class Multiple(Model_One, Model_Two):
    attr3 = models.CharField(max_length=10)

多重繼承的時候,子類的 ORM 映射會選擇第一個父類做爲主鍵管理,其餘的父類做爲通常的外鍵管理。

5.3代理模型

使用多表繼承時,父類的每一個子類都會建立一張新數據表。可是咱們只是想擴展一些方法,而不想改變模型的數據存儲結構。咱們能夠將在 Meta 類中增長約束proxy=True 來實現。此時子模型稱爲父模型代理類,子類中只能增長方法,而不能增長屬性。

from django.db import models
from django.contrib.auth.models import User

class Person(User):
    name = models.CharField(max_length=10)
    
    class Meta:
        proxy = True

    def do_something(self):
        pass

class Man(Person):
    job = models.CharField(max_length=20)

class Woman(Person):
    makeup = models.CharField(max_length=20)
相關文章
相關標籤/搜索