python3之Django模型(一)

一、模型概述

模型是關於您的數據的惟一,明確的信息來源,它包含您正在存儲的數據的重要字段和行爲。一般,每一個模型映射到單個數據庫表。html

每一個模型都是一個子類的python類django.db.models.Model前端

模型的每一個屬性表示一個數據字段python

綜上所述,Django爲您提供了一個自動生成的數據庫訪問API。git

簡單實例:在app下的models中建立person類:正則表達式

class person(models.Model):
    first_name = models.CharField(max_length=30)
    last_name = models.CharField(max_length=30)

first_name和last_name是模型的命名字段,每一個字段都被指定爲一個類屬性,而且每一個屬性映射到一個數據表的列上,上面的person模型會建立一個以下的SQL數據庫表語句:數據庫

CREATE TABLE myapp_person (
    "id" serial NOT NULL PRIMARY KEY,
    "first_name" varchar(30) NOT NULL,
    "last_name" varchar(30) NOT NULL
);

其中表的名稱以APP名爲表的前綴命名myapp_person,Django自動從模型類的名稱和包含它的應用程序中派生出數據庫表的名稱,模型的數據庫表格名稱是經過將模型的「應用標籤」(您使用的名稱)與模型的類名稱加在一塊兒並在它們之間加下劃線來構造的。要修改它請使用模型meta元數據選項db_table來指定表名django

模型會自動添加一個自增加的主鍵字段瀏覽器

使用模型:要使用模型,須要在項目的setting.py文件中修改INSTALLED_APPS設置,來添加應用程序名,而後遷移數據。服務器

INSTALLED_APPS = [
    'myapp',
]

#python manage.py makemigrations
#python manage.py migrate

二、字段(字段類型與字段選項)

模型中最重要的部分,字段在python中表現爲一個類屬性,體現了數據庫中的一個列app

在命名時請避免使用python關鍵字,django內置模型API名字,防止命名衝突;字段名中不能有兩個以上下劃線,由於兩個下劃線是Django的查詢語法

(1)字段類型:

模型中的每一個字段都是相應Field類的實例,它們都位於django.db.models中,Django使用字段類型來肯定列類型,呈現表單字段時使用默認的HTML,Django管理員和自動生成的表單中使用的最小驗證要求。

經常使用的Django字段類型:

AutoField()  :一個自動增長的整數類型字段。一般你不須要本身編寫它,Django會自動幫你添加字段:id = models.AutoField(primary_key=True),這是一個自增字段,從1開始計數。若是你非要本身設置主鍵,那麼請務必將字段設置爲primary_key=True。Django在一個模型中只容許有一個自增字段,而且該字段必須爲主鍵

BigAutoField():和AutoField差很少,不一樣之處在於它是64位整數類型自增字段,數字範圍更大,從1到9223372036854775807

BigIntegerField:64位整數字段(看清楚,非自增),相似IntegerField ,-9223372036854775808 到9223372036854775807。在Django的模板表單裏體現爲一個textinput標籤

BinaryField:二進制數據類型。使用受限,少用

BooleanField:布爾值類型。默認值是None。在HTML表單中體現爲CheckboxInput標籤。若是要接收null值,請使用NullBooleanField

CharField:字符串類型。必須接收一個max_length參數,表示字符串長度不能超過該值。默認的表單標籤是input text。最經常使用的filed

CommaSeparatedIntegerField:逗號分隔的整數類型。必須接收一個max_length參數。經常使用於表示較大的金額數目,例如1,000,000元

DateField:class DateField(auto_now=False, auto_now_add=False, **options)日期類型。一個Python中的datetime.date的實例。在HTML中表現爲TextInput標籤。在admin後臺中,Django會幫你自動添加一個JS的日曆表和一個「Today」快捷方式,以及附加的日期合法性驗證。兩個重要參數:(參數互斥,不能共存) auto_now:每當對象被保存時將字段設爲當前日期,經常使用於保存最後修改時間。auto_now_add:每當對象被建立時,設爲當前日期,經常使用於保存建立日期(注意,它是不可修改的)。設置上面兩個參數就至關於給field添加了editable=Falseblank=True屬性。若是想具備修改屬性,請用default參數。例子:pub_time = models.DateField(auto_now_add=True),自動添加發布時間。

DateTimeField:日期時間類型。Python的datetime.datetime的實例。與DateField相比就是多了小時、分和秒的顯示,其它功能、參數、用法、默認值等等都同樣

DecimalField:固定精度的十進制小數。至關於Python的Decimal實例,必須提供兩個指定的參數!參數max_digits:最大的位數,必須大於或等於小數點位數 。decimal_places:小數點位數,精度。 當localize=False時,它在HTML表現爲NumberInput標籤,不然是text類型。例子:儲存最大不超過999,帶有2位小數位精度的數,定義以下:models.DecimalField(..., max_digits=5, decimal_places=2)

DurationField:持續時間類型。存儲必定期間的時間長度。相似Python中的timedelta。在不一樣的數據庫實現中有不一樣的表示方法。經常使用於進行時間之間的加減運算。可是當心了,這裏有坑,PostgreSQL等數據庫之間有兼容性問題

EmailField:郵箱類型,默認max_length最大長度254位。使用這個字段的好處是,可使用DJango內置的EmailValidator進行郵箱地址合法性驗證

FileField:class FileField(upload_to=None, max_length=100, **options)上傳文件類型,它不能設置爲主鍵,默認狀況下,該字段在HTML中表現爲一個ClearableFileInput標籤,在數據庫內,咱們實際保存的是一個字符串類型,默認最大長度100,可用經過max_length參數自定義,真實的文件是保存在服務器的文件系統內的,最重要的參數upload_to用於設置上傳地址的目錄和文件名,以下示例:

class MyModel(models.Model):
    # 文件被傳至`MEDIA_ROOT/uploads`目錄,MEDIA_ROOT由你在settings文件中設置
    upload = models.FileField(upload_to='uploads/')
    # 或者
    # 被傳到`MEDIA_ROOT/uploads/2015/01/30`目錄,增長了一個時間劃分
    upload = models.FileField(upload_to='uploads/%Y/%m/%d/')

FilePathField:文件路徑類型

class FilePathField(path=None, match=None, recursive=False, max_length=100, **options)[source]

一種用來保存文件路徑信息的字段,在數據表內以字符串的形式存在,默認最大長度100,能夠經過max_length參數設置,它包含有如下參數:

path:必須指定的參數,表示一個系統絕對路徑

match:可選參數,一個正則表達式,用於過濾文件名,只匹配基本文件名,不匹配路徑

recursive:可選參數,只能是True或者False,默認爲False,決定是否包含子目錄,也就是是否遞歸的意思

allow_files:可選參數,只能是True或者False,默認爲True,決定是否應該將文件名包括在內,它和allow_folders其中,必須有一個爲True

allow_folders:可選參數,只能是True或者False,默認爲False,決定是否應該將目錄名包括在內

 

FloatField:浮點數類型,參考整數類型

ImageFiedl:圖像類型;用於保存圖像文件的字段。其基本用法和特性與FileField同樣,只不過多了兩個屬性height和width。默認狀況下,該字段在HTML中表現爲一個ClearableFileInput標籤。在數據庫內,咱們實際保存的是一個字符串類型,默認最大長度100,能夠經過max_length參數自定義。真實的圖片是保存在服務器的文件系統內的。

height_field參數:保存有圖片高度信息的模型字段名。 width_field參數:保存有圖片寬度信息的模型字段名。

使用Django的ImageField須要提早安裝pillow模塊,pip install pillow便可

使用FileField或者ImageField字段的步驟:

(1)在settings文件中,配置MEDIA_ROOT做爲上傳文件在服務器中的基礎路徑,爲了性能考慮,這些文件不會被存儲在數據庫中,在配置個MEDIA_URL做爲公用URL,指向上傳文件的基本路徑,請確保Web服務器的用戶帳號對該目錄具備寫入權限

(2)添加FileField或者ImageField字段到模型中,定義好upload_to參數,文件最總會放在MEDIA_ROOT目錄的'upload_to‘子目錄中

(3)全部真正被保存在數據庫中的只是指向上傳文件路徑的字符串而已,可用經過url屬性,在Djang的模塊中方便的訪問這些文件;列如:一個ImageField字段名爲mug_shot,那麼在Django模塊的HTML文件中,可用使用{{ object.mug_shot.url }}來獲取該文件,其中的object用具體的對象名稱代替

(4)能夠經過name和size屬性,獲取文件的名稱和大小信息

 

IntegerField:整數類型,最經常使用的字段之一,取值範圍-2147483648到2147483647。在HTML中表現爲NumberInput標籤。

GenericIPAddressField:class GenericIPAddressField(protocol='both', unpack_ipv4=False, **options)[source],IPV4或者IPV6地址,字符串形式,例如192.0.2.30或者2a02:42fe::4在HTML中表現爲TextInput標籤。參數protocol默認值爲‘both’,可選‘IPv4’或者‘IPv6’,表示你的IP地址類型

NullBooleanField:相似布爾字段,只不過額外容許NULL做爲選項之一

PositiveIntegerField:正整數字段,包含0,最大2147483647

PositiveSmallIntegerField:較小的正整數字段,從0到32767

SlugField:slug是一個新聞行業的術語。一個slug就是一個某種東西的簡短標籤,包含字母、數字、下劃線或者鏈接線,一般用於URLs中。能夠設置max_length參數,默認爲50

SmallIntegerField:小整數,包含-32768到32767

TextField:大量文本內容,在HTML中表現爲Textarea標籤,最經常使用的字段類型之一!若是你爲它設置一個max_length參數,那麼在前端頁面中會受到輸入字符數量限制,然而在模型和數據庫層面卻不受影響。只有CharField才能同時做用於二者

TimeField:時間字段,Python中datetime.time的實例。接收同DateField同樣的參數,只做用於小時、分和秒

URLField:一個用於保存URL地址的字符串類型,默認最大長度200

UUIDField:用於保存通用惟一識別碼(Universally Unique Identifier)的字段。使用Python的UUID類。在PostgreSQL數據庫中保存爲uuid類型,其它數據庫中爲char(32)。這個字段是自增主鍵的最佳替代品

數據庫沒法本身生成uuid,所以須要以下使用default參數:

import uuid     # Python的內置模塊
from django.db import models

class MyUUIDModel(models.Model):
    id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
    # 其它字段

(2)字段參數

每一個字段都有一組特定於字段的參數,下面列出通用參數爲可選的:

null:若是True,Django將像NULL數據庫中那樣存儲空值默認是False

blank:若是True,該字段被容許爲空;默認是False。和Null參數不一樣的是,null是純數據庫層面的,而blank是驗證相關的,它與表單驗證是否容許輸入框內爲空有關,與數據庫無關,因此要當心一個null爲False,blank爲True的字段接收到一個空值可能會出bug或異常

choices:一個二維元組可迭代的對象(例如,一個列表或元組),用做該字段的選擇,用於頁面上的選擇框標籤,第一個元素表示存在數據庫內真實的值,第二個元素表示頁面上顯示的具體內容,在瀏覽器頁面上將顯示第二個元素的值:

YEAR_IN_SCHOOL_CHOICES = (
    ('FR', 'Freshman'),
    ('SO', 'Sophomore'),
    ('JR', 'Junior'),
    ('SR', 'Senior'),
)

db_column:該參數用於定義當前字段在數據表內的列名,若是未指定,Django將使用字段名做爲列名

db_index:該參數接收布爾值,若是爲True,數據庫將爲該字段建立索引

db_tablespace:用於字段索引的數據庫表空間的名字,前提是當前字段設置了索引,默認值爲工程的DEFAULT_INDEX_TABLESPACE設置,若是使用的數據庫不支持表空間,該參數會被忽略

default:字段的默認值。這能夠是一個值或一個可調用的對象。若是可調用,則每次建立新對象時都會調用它。設置的默認值不能是一個可變對象,好比列表,集合等,lambda匿名函數也不可用於default的調用對象,由於匿名函數不能被migrations序列化,注意:在某種緣由不明的狀況下將default設置爲None,可能引起intergyerror:not null constraint failed,即非空約束失敗異常,致使python manage.py migrate失敗,此時可將None改成Fasle或其餘值,只要不是None就行。

editable:若是設爲false那麼當前字段將不會在admin後臺或者其餘的ModelForm表單中顯示,同時還會被模型驗證功能跳過,參數默認值爲True

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

help_text:用窗體小部件顯示額外的「幫助」文本。即便您的字段未用於表單,對於文檔也頗有用。

primary_key:若是True,這個字段是模型的主鍵。若是您沒有primary_key=True爲模型中的任何字段指定,Django會自動添加一個 AutoField自增字段,名爲'id',並設置爲主鍵,也就是id = models.AutoField(primary_key=True),若是你爲某個字段設置了primary_key=True,則當前字段變爲主鍵,並關閉Django自動生成id主鍵的功能;primary_key=True隱含null=False和unique=True的意思,一個模型中只能由一個主鍵字段,另外主鍵字段不可修改,若是給某個對象的主鍵賦個新值其實是建立一個新對象,並不會修改原來的對象

unique:若是爲True,該字段在整個表格中必須是惟一的,注意:對於ManyToManyField和OneToOneField關係類型,該參數無效;當unique=True時,db_index參數無需設置,由於unqiue隱含了索引

unique_for_date:日期惟一,若是由一個title字段,並設置了參數unique_for_date="pub_date",那麼django將不容許由兩個模型對象具有一樣的title和pub_date,有點相似聯合約束。

unique_for_month:月份惟一

unique_for_year:年份惟一

verbose_name:爲字段設置一我的類可讀的,更加直觀的別名,對於每一個字段類型,除了ForeignKey、ManyToManyField和OneToOneField這三個特殊的關係類型,其第一可選位置參數都是verbose_name,若是沒指定這個參數,Django會利用字段的屬性名自動建立它,並將下劃線轉換爲空格

#下面列子的verbose_naem是「person'sfirst name"
first_name = models.CharField("person's first name", max_length=30)
#下面例子的verbose_name是」first name"
first_name = models.CharField(max_length=30)
#因爲外鍵、多對多和一對一字段,第一個參數須要用來指定關聯的模型,所以必須用關鍵參數verbose_name來明確指定
poll = models.ForeignKey(
    Poll,
    on_delete=models.CASCADE,
    verbose_name="the related poll",
    )
#另外,你無須大寫verbose_name的首字母,Djang自動爲你完成這項工做

validators:運行在該字段上的驗證器的列表

三、自動主鍵字段

默認狀況下,Django爲每一個模型提供如下字段:

id = models.AutoField(primary_key=True)

這是一個自動遞增的主鍵;若是你想指定一個自定義主鍵,只需primary_key=True在其中一個字段上指定 。若是Django看到你已經明確設置Field.primary_key,它不會添加自動 id列。

每一個模型只須要一個字段primary_key=True(顯式聲明或自動添加)

四、詳細的字段名

每一個字段類型除了ForeignKey, ManyToManyField和 OneToOneField都有一個可選的第一個位置參數 - 一個詳細名稱。若是沒有給出詳細名稱,Django將使用該字段的屬性名稱自動建立它,並將下劃線轉換爲空格。

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

上面的例子中詳細名稱爲:「person's first name」

first_name = models.CharField(max_length=30)

若是第一個位置參數不制定詳細名則使用字段屬性名來建立它,上面的例子詳細名爲「first name"

還可用在字段中使用verbose_name選項來指定字段名

 

五、關係型數據庫

關係數據庫的強大之處在於相互關聯表。Django提供了定義三種最多見類型的數據庫關係的方法:多對一,多對多和一對一。

(1)多對一的關係

要定義多對一關係,請使用django.db.models.ForeignKey您能夠像使用其餘Field類型同樣使用它,多對一的關係一般被稱爲外鍵,外鍵字段類的定義以下:

class ForeignKey(to,no_delete,**options)

多對一的關係,須要兩個位置參數,第一個爲關聯的模型,另外一個是no_delete選項models.ForeignKey('self',no_delete=models.CASCADE) :

當一張表中建立一行數據時,有一個單選的下拉框且可用被重複選擇

ForeignKey(ForeignObject) # ForeignObject(RelatedField)
        to,                         # 要進行關聯的表名
        to_field=None,              # 要關聯的表中的字段名稱
        on_delete=None,             # 當刪除關聯表中的數據時,當前表與其關聯的行的行爲
         related_name=None,          # 反向操做時,使用的字段名,用於代替 【表名_set】 如: obj.表名_set.all()
        related_query_name=None,    # 反向操做時,使用的鏈接前綴,用於替換【表名】     如: models.UserGroup.objects.filter(表名__字段名=1).values('表名__字段名')
        limit_choices_to=None,      # 在Admin或ModelForm中顯示關聯數據時,提供的條件:
                                    # 如:
                                            - limit_choices_to={'nid__gt': 5}
                                            - limit_choices_to=lambda : {'nid__gt': 5}

                                            from django.db.models import Q
                                            - limit_choices_to=Q(nid__gt=10)
                                            - limit_choices_to=Q(nid=8) | Q(nid__gt=10)
                                            - limit_choices_to=lambda : Q(Q(nid=8) | Q(nid__gt=10)) & Q(caption='root')
        db_constraint=True          # 是否在數據庫中建立外鍵約束
        parent_link=False           # 在Admin中是否顯示關聯數據

例如如下實例:在一篇博客文章中引用多個用戶可選擇。

#下面以建立一個對應多用戶的博客文章模型爲例來講明:

from django.db import models
from django.utils import timezone

class User(models.Model):
    username = models.CharField(max_length=150,verbose_name="用戶名")
    password = models.CharField(max_length=300,verbose_name="密碼")
    age = models.IntegerField(verbose_name="年齡")
    def __str__(self):
        return self.username

class articel(models.Model):
    title = models.CharField(max_length=300,verbose_name="博客標題")
    author = models.ForeignKey(User,on_delete=models.CASCADE,verbose_name="做者")   #做者將對應User表中的多個用戶,提供下拉菜單可選擇用戶
    body = models.TextField(verbose_name="文章內容")
    publish = models.DateTimeField(default=timezone.now,verbose_name="發表時間")

    class Meta:
        ordering = ["-publish"]

    def __str__(self):
        return self.title

若是要關聯的模型對象在另一個app中,假設user模型在blog這個app中,要在當前app模型中關聯,以下設置:

class articel(models.Model):
    author = models.ForeignKey(
        'blog.user',    #app之間關聯
        on_delete=models.CASCADE,
)

若是要建立一個遞歸的外鍵,也就是本身關聯本身的外鍵,使用下面的方法:

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

外鍵還有一些重要的參數:on_delete當一個被外鍵關聯的對象被刪除時,Django將模仿on_delete參數定義的SQL約束執行相應的操做,好比有一個可爲空的外鍵,而且你想讓它在關聯的對象被刪除時,自動設爲null,可以下定義:

user = models.ForeignKey(
    User,
    models.SET_NULL,
    blank=True,
    null=True,
)

該參數可選的值都內置在django.db.models中,包括:

CASCADE:模擬SQL語言中的ON DELETE CASCADE約束,將定義有外鍵的模型對象同時刪除,該操做爲當前django版本的默認操做

PROTECT:阻止上面的刪除操做,可是彈出ProtectedError異常

SET_NULL:將外鍵字段設爲Null,只用當字段設置了Null=True時,方可以使用該值

SET_DEFAULT:將外鍵字段設爲默認值。只有當字段設置了default參數時,方可以使用

DO_NOTHING:什麼也不作

SET():設置爲一個傳遞給SET()的值或者一個回調函數的返回值;注意大小寫

(2)多對多關係

要定義多對多關係,請使用 ManyToManyField您能夠像使用其餘Field類型同樣使用它 :將其做爲模型的類屬性包含在內。

ManyToManyField 須要一個位置參數:與模型相關的類。

ManyToManyField(RelatedField)
        to,                         # 要進行關聯的表名
        related_name=None,          # 反向操做時,使用的字段名,用於代替 【表名_set】 如: obj.表名_set.all()
        related_query_name=None,    # 反向操做時,使用的鏈接前綴,用於替換【表名】     如: models.UserGroup.objects.filter(表名__字段名=1).values('表名__字段名')
        limit_choices_to=None,      # 在Admin或ModelForm中顯示關聯數據時,提供的條件:
                                    # 如:
                                            - limit_choices_to={'nid__gt': 5}
                                            - limit_choices_to=lambda : {'nid__gt': 5}

                                            from django.db.models import Q
                                            - limit_choices_to=Q(nid__gt=10)
                                            - limit_choices_to=Q(nid=8) | Q(nid__gt=10)
                                            - limit_choices_to=lambda : Q(Q(nid=8) | Q(nid__gt=10)) & Q(caption='root')
        symmetrical=None,           # 僅用於多對多自關聯時,symmetrical用於指定內部是否建立反向操做的字段
                                    # 作以下操做時,不一樣的symmetrical會有不一樣的可選字段
                                        models.BB.objects.filter(...)

                                        # 可選字段有:code, id, m1
                                            class BB(models.Model):

                                            code = models.CharField(max_length=12)
                                            m1 = models.ManyToManyField('self',symmetrical=True)

                                        # 可選字段有: bb, code, id, m1
                                            class BB(models.Model):

                                            code = models.CharField(max_length=12)
                                            m1 = models.ManyToManyField('self',symmetrical=False)

        through=None,               # 自定義第三張表時,使用字段用於指定關係表
        through_fields=None,        # 自定義第三張表時,使用字段用於指定關係表中那些字段作多對多關係表
                                        from django.db import models

                                        class 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)
        db_constraint=True,         # 是否在數據庫中建立外鍵約束
        db_table=None,              # 默認建立第三張表時,數據庫中表的名稱

 #以上面的例子爲例再增長一個評論的類模型,並關聯到博客表中,它是一個可用多選的下拉框。

class comment(models.Model):
    user = models.ForeignKey(User,on_delete=models.CASCADE)
    date = models.DateTimeField(default=timezone.now)
    body = models.TextField()

class articel(models.Model):
    title = models.CharField(max_length=300,verbose_name="博客標題")
    author = models.ForeignKey(User,on_delete=models.CASCADE,verbose_name="做者")
    body = models.TextField(verbose_name="文章內容")
    publish = models.DateTimeField(default=timezone.now,verbose_name="發表時間")
    comment = models.ManyToManyField(comment,verbose_name="評論")  #在每一篇文章中針對多個評論,即爲多對多的關係
    class Meta:
        ordering = ["-publish"]

    def __str__(self):
        return self.title

對於ManyToManyField字段,Django採用的是第三張中間表的方式,經過這第三張表,來關聯ManyToMany的雙方,下面經過具體的列子來詳細解析:

首先創建一個簡單的多對多關係模型:

from django.db import models

class Person(models.Model):
    name = models.CharField(max_length=128)
    def __str__(self):
        return self.name

class Group(models.Model):
    name = models.CharField(max_length=128)
    members = models.ManyToManyField(Person)
    def __str__(self):
        return self.name

在Group模型中,經過members字段,以ManyToMany方式與Person模型創建多對多關係,咱們在數據庫中能夠看到三張表,以app名爲前綴,如app01則三張表名爲:app01_group、app01_person、app01_group_members

其中app01_group_memebers是對應關係表,它會生成自身id列,group的id列和person相對應的id列,此中間表是經過id的關聯進行映射的。

自定義中間表:

通常狀況,普通的多對多已經夠用,無需本身建立第三張關係表,可是某些狀況可能更復雜一點,好比若是你想保存某我的加入某個分組的時間呢?想保存進組的緣由呢?

Django提供了一個through參數,用於指定中間模型,你能夠將相似進組時間,邀請緣由等其餘字段都放在這個中間模型內:

from django.db import models

class Person(models.Model):
    name = models.CharField(max_length=128)
    def __str__(self):
        return self.name

class Group(models.Model):
    name = models.CharField(max_length=128)
    members = models.ManyToManyField(Person,through='Membership')  #指定中間表
    def __str__(self):
        return self.name
#自定中間表    
class Membership(models.Model):
    person = models.ForeignKey(Person,on_delete=models.CASCADE)  #經過外鍵關聯模型
    group = models.ForeignKey(Group,on_delete=models.CASCADE)
    date_joined = models.DateField()   #添加自定義字段
    invite_reason = models.CharField(max_length=100)

(3)一對一關係

要定義一對一的關係,請使用 OneToOneField您能夠像使用其餘Field類型同樣使用它 :將其做爲模型的類屬性包含在內。

當對象以某種方式「擴展」另外一個對象時,這對於對象的主鍵很是有用。

OneToOneField 須要一個位置參數:與模型相關的類。

OneToOneField(ForeignKey)
        to,                         # 要進行關聯的表名
        to_field=None               # 要關聯的表中的字段名稱
        on_delete=None,             # 當刪除關聯表中的數據時,當前表與其關聯的行的行爲

                                    ###### 對於一對一 ######
                                    # 1. 一對一其實就是 一對多 + 惟一索引
                                    # 2.當兩個類之間有繼承關係時,默認會建立一個一對一字段
                                    # 以下會在A表中額外增長一個c_ptr_id列且惟一:
                                            class C(models.Model):
                                                nid = models.AutoField(primary_key=True)
                                                part = models.CharField(max_length=12)

                                            class A(C):
                                                id = models.AutoField(primary_key=True)
                                                code = models.CharField(max_length=1)

一對一:在建立表中一行數據時,有一個單選的下拉框,下拉框中的內容被用過一次就消失了。

class User(models.Model):
    username = models.CharField(max_length=150,verbose_name="用戶名")
    password = models.CharField(max_length=300,verbose_name="密碼")
    age = models.IntegerField(verbose_name="年齡")

    def __str__(self):
        return self.username

class User_extend(models.Model):
    User = models.OneToOneField(User, on_delete=models.CASCADE, primary_key=True)  #將用戶信息擴展到此表
    address = models.CharField(max_length=300,null=True,blank=True,verbose_name="住址")
    education = models.CharField(max_length=30,null=True,blank=True,verbose_name="學歷")

六、跨文件的模型

將模型與另外一個應用程序中的模型相關聯徹底能夠。爲此,請在定義模型的文件頂部導入相關模型。而後,只需在須要的地方引用其餘模型類。

from django.db import models
from geography.models import ZipCode

class Restaurant(models.Model):
    # ...
    zip_code = models.ForeignKey(
        ZipCode,
        on_delete=models.SET_NULL,
        blank=True,
        null=True,
    )

七、字段名稱限制

Django對模型字段名稱只有兩個限制:

(1)字段名稱不能是Python保留字,由於這會致使Python語法錯誤

(2)因爲Django查詢查找語法的工做方式,字段名稱不能在一行中包含多個下劃線

八、Meta選項

模型源數據Meta是數據庫類可選的附加屬性,如排序(ordering),數據庫表名(db_table),可讀的數據類名稱(verbose_name)

下面列出可用的Meta選項:

abstract = True   :定義模型爲抽象基類,抽象模型自己不實際生成數據表,而是做爲其餘模型的父類,被繼承使用

app_label = 'myapp'  :聲明模型屬於哪一個應用,如定義了模型的app沒有在INSTALLED_APPS中註冊,則必須經過此元選項聲明它屬於哪一個app

base_manager_name   :用於模型的管理器名稱

db_table = ‘db_name'  :指定模型使用的數據庫名稱

db_tablespace:自定義數據庫表空間的名稱,默認值是工程DEFAULT_TABLESPACE設置

default_manager_name:自定義模型的_default_manager管理器的名字

ordering = ['order_date']  :指定對象的默認排序,可對指定排序規則

verbose_name = 「blog」   :指定對象的可讀名稱

verbose_name_plural:指定模型對象的複數名,在使用中文時,若是不指定該參數,那麼默認的複數名是verbose_name加上‘s'

label:前面介紹的元數據都是可修改和設置的,但還有兩個只讀的元數據,label就是其中之一,app_label.object_name,例如'polls.Question'

class blog(models.Model):
    pass

    class Meta:
        ordering = ['-publish']
        verbose_name = "博客"

九、模型屬性

模型的最重要的屬性是 Manager它是經過它向Django模型提供數據庫查詢操做的接口,用於 從數據庫中檢索實例若是Manager未定義定義,則默認名稱爲 objects管理者只能經過模型​​類訪問,而不能訪問模型實例。

from blog.models import User_extend
date = User_extend.objects.all()

十、模型繼承

Django中的模型繼承以與Python中的普通類繼承徹底不一樣的方式完成,但基本思想在一開始就很常見。那就是它的基類django.db.models.Model必須是它的子類。

 django中有三種可能的繼承方法:

1.定義一個抽象基類,它不單獨使用;用來給子類繼承使用

2.若是要建立現有模型的子類,而且但願在數據庫中爲每一個模型定義一個表,那麼最好使用多個表的繼承

3.若是要在有python級別修改模型的行爲而不以任何方式修改模型的字段,則可用使用代理模型

(1)抽象基類

當想要將一些公共信息放入許多其餘模型時,抽象基類會派上用場,在數據模型的Meta類中定義abstract=True,則此模型不會建立任何數據庫表,當它用做其餘模型的基類時,其字段將添加到子類的字段中。

class CommonInfo(models.Model):
    name = models.CharField(max_length=100)
    age = models.PositiveIntegerField()
    class Meta:
        abstract = True

class Student(CommonInfo):
    home_group = models.CharField(max_length=30)

#該Student模型將會繼承name和age字段和自身的home_group組成,該CommonInfo模型不能用做普通的django模型,它是一個抽象類,它不生成數據庫表,而且沒法直接實例化或保存,從抽象類繼承的字段可用使用其餘字段或值覆蓋,也可用使用刪除None

Meta繼承:

當建立抽象基類時,Django使您在基類中聲明的任何Meta內部類可用做屬性,若是子類沒有聲明它本身的Meta類,它將繼承父類的Meta,若是子類想要擴展父類的Meta類,它能夠將其子類化。

from django.db import models

class CommonInfo(models.Model):
    # ...
    class Meta:
        abstract = True
        ordering = ['name']

class Student(CommonInfo):
    # ...
    class Meta(CommonInfo.Meta):
        db_table = 'student_info'

#Student子類會繼承父類中的Meta內部的屬性

 十一、多表繼承

多表繼承中父類和子類都是獨立自主功能完整,可正常使用的模型,都由本身的數據庫表,內部隱含了一個一對一的關係,以下:

from django.db import models

class Place(models.Model):
    name = models.CharField(max_length=50)
    address = models.CharField(max_length=80)
    def __str__(self):
        return "{}-{}".format(self.name,self.address)

class Restaurant(Place):
    serves_hot_dogs = models.BooleanField(default=False)
    serves_pizza = models.BooleanField(default=False)
    def __str__(self):
        return "{}-{}-{}-{}".format(self.name,self.address,self.serves_hot_dogs,self.serves_pizza)
#Restaurant繼承Place後會有name和address字段,它會在內部字段中建立一個一對一的主鍵關係來將父類中的字段數據映射到自身數據表上
  operations = [
        migrations.CreateModel(
            name='Place',
            fields=[
                ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
                ('name', models.CharField(max_length=50)),
                ('address', models.CharField(max_length=80)),
            ],
        ),
        migrations.CreateModel(
            name='Restaurant',
            fields=[
                ('place_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='app01.Place')),
                ('serves_hot_dogs', models.BooleanField(default=False)),
                ('serves_pizza', models.BooleanField(default=False)),
            ],
            bases=('app01.place',),
        ),
    ]

如在Restaurant數據表中寫入數據,而繼承字段數據實際是寫入父類數據表中的,它的內部機制實際隱含一個OneToOne字段,並設置parent_link=True來映射表字段,咱們也能夠經過這種方法來自定義

Meta和多表繼承:

在多表繼承的狀況下,因爲父類和子類都在數據庫內有物理存在的表,父類的Meta類會對子類形成不肯定的影響,所以,Django在這種狀況下關閉了子類繼承父類的Meta功能,這點和抽象類的繼承有所不一樣

可是,還有兩個Meta元數據庫特殊點,那就是ordering和get_latest_by,這兩個參數是會被繼承的,所以若是在多變繼承中,你不想讓你的子類繼承父類的撒謊給你嗎兩個參數,就必須在子類中重寫

class ChildModel(ParentModel):
  ...
  class Meta:
    ordering = []  #刪除父類的排序影響
相關文章
相關標籤/搜索