django模型和欄位
一個模型(model)就是一個單獨的、確定的資料的資訊源,包含了資料的欄位和操作方法。通常,每個模型對映為一張資料庫中的表。
基本的原則如下:
- 每個模型在Django中的存在形式為一個Python類
- 每個模型都是django.db.models.Model的子類
- 模型的每個欄位(屬性)代表資料表的某一列
- Django將自動為你生成資料庫訪問API
簡單示例:
下面的模型定義了一個“人”,它具有first_name
和last_name
欄位:
from django.db import models
class Person(models.Model): first_name = models.CharField(max_length=30) last_name = models.CharField(max_length=30)
每一個欄位都是一個類屬性,每個類屬性表示資料表中的一個列。
上面的程式碼,相當於下面的原生SQL語句:
CREATE TABLE myapp_person (
"id" serial NOT NULL PRIMARY KEY, "first_name" varchar(30) NOT NULL, "last_name" varchar(30) NOT NULL );
注意:
- 表名
myapp_person
由Django自動生成,預設格式為“專案名稱+下劃線+小寫類名”,你可以重寫這個規則。 - Django預設自動建立自增主鍵
id
,當然,你也可以自己指定主鍵。 - 上面的SQL語句基於
PostgreSQL
語法。
通常,我們會將模型編寫在其所屬app下的models.py檔案中,沒有特別需求時,請堅持這個原則,不要自己給自己新增麻煩。
建立了模型之後,在使用它之前,你需要先在settings檔案中的INSTALLED_APPS
處,註冊models.py
檔案所在的myapp
。看清楚了,是註冊app,不是模型,也不是models.py
。如果你以前寫過模型,可能已經做過這一步工作,可跳過。
INSTALLED_APPS = [ #... 'myapp', #... ]
當你每次對模型進行增、刪、修改時,請務必執行命令python manage.py migrate
python manage.py makemigrations
讓修改動作儲存到記錄檔案中,方便github等工具的使用。
模型欄位fields
欄位是模型中最重要的內容之一,也是唯一必須的部分。欄位在Python中表現為一個類屬性,體現了資料表中的一個列。請不要使用clean
、save
、delete
等Django內建的模型API名字,防止命名衝突。下面是一個展示,注意欄位的寫法:
from django.db import models
class Musician(models.Model): first_name = models.CharField(max_length=50) last_name = models.CharField(max_length=50) instrument = models.CharField(max_length=100) class Album(models.Model): artist = models.ForeignKey(Musician, on_delete=models.CASCADE) name = models.CharField(max_length=100) release_date = models.DateField() num_stars = models.IntegerField()
欄位命名約束:
Django不允許下面兩種欄位名:
-
與Python關鍵字衝突。這會導致語法錯誤。例如:
class Example(models.Model): pass = models.IntegerField() # 'pass'是Python保留字!
-
欄位名中不能有兩個以上下劃線在一起,因為兩個下劃線是Django的查詢語法。例如:
class Example(models.Model): foo__bar = models.IntegerField() # 'foo__bar' 有兩個下劃線在一起!
由於你可以自定義表名、列名,上面的規則可能被繞開,但是請養成良好的習慣,一定不要那麼起名。
SQL語言的join、where和select等保留字可以作為欄位名,因為Django對它們都進行了轉義。
常用欄位型別
欄位型別的作用:
- 決定資料庫中對應列的資料型別(例如:INTEGER, VARCHAR, TEXT)
- HTML中對應的表單標籤的型別,例如
<input type=“text” />
- 在admin後臺和自動生成的表單中最小的資料驗證需求
Django內建了許多欄位型別,它們都位於django.db.models
中,例如models.CharField
。這些型別基本滿足需求,如果還不夠,你也可以自定義欄位。
下表列出了所有Django內建的欄位型別,但不包括關係欄位型別(欄位名採用駝峰命名法,初學者請一定要注意):
型別 | 說明 |
---|---|
AutoField | 一個自動增加的整數型別欄位。通常你不需要自己編寫它,Django會自動幫你新增欄位:id = models.AutoField(primary_key=True) ,這是一個自增欄位,從1開始計數。如果你非要自己設定主鍵,那麼請務必將欄位設定為primary_key=True 。Django在一個模型中只允許有一個自增欄位,並且該欄位必須為主鍵! |
BigAutoField | (1.10新增)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=False 和blank=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) 上傳檔案型別,後面單獨介紹。 |
FilePathField | 檔案路徑型別,後面單獨介紹 |
FloatField | 浮點數型別,參考整數型別 |
ImageField | 影象型別,後面單獨介紹。 |
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)。這個欄位是自增主鍵的最佳替代品,後面有例子展示。 |
這裡有如何上傳檔案和圖片的方法:
1.FileField:
class FileField(upload_to=None, max_length=100, **options)[source]
上傳檔案欄位(不能設定為主鍵)。預設情況下,該欄位在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/')
Django很人性化地幫我們實現了根據日期生成目錄的方式!
upload_to
引數也可以接收一個回撥函式,該函式返回具體的路徑字串,如下例:
def user_directory_path(instance, filename): #檔案上傳到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)
例子中,user_directory_path
這種回撥函式,必須接收兩個引數,然後返回一個Unix風格的路徑字串。引數instace
代表一個定義了FileField
的模型的例項,說白了就是當前資料記錄。filename
是原本的檔名。
2. ImageField
class ImageField(upload_to=None, height_field=None, width_field=None, max_length=100, **options)[source]
用於儲存影象檔案的欄位。其基本用法和特性與FileField一樣,只不過多了兩個屬性height和width。預設情況下,該欄位在HTML中表現為一個ClearableFileInput標籤。在資料庫內,我們實際儲存的是一個字串型別,預設最大長度100,可以通過max_length引數自定義。真實的圖片是儲存在伺服器的檔案系統內的。
height_field
引數:儲存有圖片高度資訊的模型欄位名。 width_field
引數:儲存有圖片寬度資訊的模型欄位名。
使用Django的ImageField需要提前安裝pillow模組,pip install pillow即可。
使用FileField或者ImageField欄位的步驟:
- 在settings檔案中,配置
MEDIA_ROOT
,作為你上傳檔案在伺服器中的基本路徑(為了效能考慮,這些檔案不會被儲存在資料庫中)。再配置個MEDIA_URL
,作為公用URL,指向上傳檔案的基本路徑。請確保Web伺服器的使用者賬號對該目錄具有寫的許可權。 - 新增FileField或者ImageField欄位到你的模型中,定義好
upload_to
引數,檔案最終會放在MEDIA_ROOT
目錄的“upload_to”子目錄中。 - 所有真正被儲存在資料庫中的,只是指向你上傳檔案路徑的字串而已。可以通過url屬性,在Django的模板中方便的訪問這些檔案。例如,假設你有一個ImageField欄位,名叫
mug_shot
,那麼在Django模板的HTML檔案中,可以使用{{ object.mug_shot.url }}
來獲取該檔案。其中的object用你具體的物件名稱代替。 - 可以通過
name
和size
屬性,獲取檔案的名稱和大小資訊。
安全建議
無論你如何儲存上傳的檔案,一定要注意他們的內容和格式,避免安全漏洞!務必對所有的上傳檔案進行安全檢查,確保它們不出問題!如果你不加任何檢查就盲目的讓任何人上傳檔案到你的伺服器文件根目錄內,比如上傳了一個CGI或者PHP指令碼,很可能就會被訪問的使用者執行,這具有致命的危害。
3. FilePathField
class FilePathField(path=None, match=None, recursive=False, max_length=100, **options)[source]
一種用來儲存檔案路徑資訊的欄位。在資料表內以字串的形式存在,預設最大長度100,可以通過max_length引數設定。
它包含有下面的一些引數:
path
:必須指定的引數。表示一個系統絕對路徑。
match
:可選引數,一個正則表示式,用於過濾檔名。只匹配基本檔名,不匹配路徑。例如foo.*\.txt$
,只匹配檔名foo23.txt
,不匹配bar.txt
與foo23.png
。
recursive
:可選引數,只能是True或者False。預設為False。決定是否包含子目錄,也就是是否遞迴的意思。
allow_files
:可選引數,只能是True或者False。預設為True。決定是否應該將檔名包括在內。它和allow_folders
其中,必須有一個為True。
allow_folders
: 可選引數,只能是True或者False。預設為False。決定是否應該將目錄名包括在內。
比如:
FilePathField(path="/home/images", match="foo.*", recursive=True)
它只匹配/home/images/foo.png
,但不匹配/home/images/foo/bar.png
,因為預設情況,只匹配檔名,而不管路徑是怎麼樣的。
4. UUIDField:
資料庫無法自己生成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) # 其它欄位