2019年3月3日 星期日

[Python] Django的ORM與模型建立

  物件關聯對映(Object Relational Mapping,簡稱ORM),幫助我們能以物件導向的方式操作資料庫,如此能更簡潔、直覺地讀取資料,在換資料庫時,也能省去因為資料庫語言的不同而造成的問題,ORM會幫我們處理轉換,這大概是最好的優點。


  先來看一下相關名詞的對應:

  在ORM中,類別相當於資料庫裡的表,物件則是指每列紀錄,屬性則是各字段。

  在Django中,我們建立一個新的app時,產生的資料夾內會有一個model.py檔,這個檔案預設就是要讓我們來建立ORM Class用的。

  在model.py裡要寫的是像底下這樣的程式碼:
from django.db import models

class Greeting(models.Model):
    name = models.CharField(max_length=50)
    message = models.CharField(max_length=200)
    timestamp = models.DateField(auto_now=True)
    ...
    class Meta:
        db_table = ...
        ...

  在上例,就像是建立了一個叫做app_greeting的表 ( [應用名_類別名] ),表裡有name、message、timestamp這三個欄位。



Meta類別:

  每個繼承自 django.db.models.Model類別都有Meta子類別,可定義模型中繼資料,例如資料表名、資料預設排序方式等。

屬性
解釋
db_table
表名
ordering
設定預設排序欄位,可設定多個欄位,預設為升冪,降冪排序在欄位名前面加負號就可
verbose_name
表的別名備註
verbose_name_plural
Verbose name複數
abstract
是否為抽象類別
permissions
設置額外權限用,2-tuples (permission_code, human_readable_permission_name)
managed
定義manage.py命令列工具是否管理本模型 (預設是True)
unique_together
用來設定不重複的欄位組合
app_label
定義本類別所屬的應用
db_tablespace
對應表格空間名稱,表格空間的概念只存在在某些資料庫中,如Oracle




欄位類型:


欄位類型
解釋
AutoField
自動遞增的整數欄位,通常用作資料表的主鍵。
BigAutoField
AutoField,但能容更大的值(64-bit)
BooleanField
布林值(預設值是None)
PositiveSmallIntegerField
0 ~ 32767
SmallIntegerField
-32768 ~ 32767
PositiveIntegerField
0 ~ 2147483647
IntegerField
-2147483648 ~ 2147483647
BigIntegerField
-9223372036854775808 ~ 9223372036854775807
CharField
相當於varchar (使用max_length指定最大長度)
TextField
相當於longtext
DateField
年月日 (auto_now_add:當物件第一次被建立時將該欄位的值設定為目前時間;auto_now:當物件被儲存時將該欄位的值設定為目前時間)
DateTimeField
年月日時分秒
DurationField
一段時間 (int, Pythontimedelta類型建置)
FloatField
浮點數欄位
DecimalField
表示小數用,需導入參數max_digits:總位數(不含小數點和符號)decimal_places:小數位數
EmailField
帶有檢查Email合法性的CharField
ImageField
類似FileField,同時驗證上船物件是否是一個合法圖片。設定height_fieldwidth_field將會按此高度寬度規格來存圖片
FileField
檔案上傳欄位,upload_to可指定上傳路徑
FilePathField
檔案路徑欄位
URLField
儲存URL
UUIDField
儲存UUID
GenericIPAddressField
IPv4IPv6 address


欄位參數:

  - 所有字段都具有的參數:

參數
解釋
db_column
重新為欄位命名
primary_key
是否為主鍵
verbose_name
字段的別名或備註
unique
字段值在表中必須唯一
null
資料庫中可否為空
blank
表單欄位可否為空 (blank=Truenull也一定要為True)
db_index
設定為索引參數
help_text
在表單中顯示幫助訊息
editable
用戶可否編輯 (field不會出現在admin或任何ModelForm)


  - 關係型字段的參數:
    1. related_name:主物件找到副物件的別名。
# Account和Contact是1:N關係
# 在Contact中有 account = models.ForeignKey(Account)
a1 = Account(user="Rose")
c1 = Contact(account = a1, mobile="1234")
print(a1.contact_set)  # 預設會是 xxx_set,若在Contact設定裡加入relate_name="yyy",則可以就用a1.yyy就行

    2. on_delete:表示當關聯模型被刪除時要做什麼動作
        有六種設定:
            (1) models.CASCADE:一起刪除
            (2) models.PROTECT:阻止刪除,並報 ProtectedError
            (3) models.SET_NULL:設置成null (此欄要為null=True, blank=True)
            (4) models.DEFAULT:設置成default值  (此欄要有 default=?)
            (5) models.DO_NOTHING:什麼也不做
            (6) models.SET:自定義一個對應的實體




表格的關係操作:

    1. one-to-one:models.OneToOneField()
    2. foreign key (one-to-many):models.ForeignKey()
    3. many-to-many:models.ManyToManyField()

範例:
1. 老師與助教 (1:1):
class Teacher(models.Model):
    name = models.CharField(max_length=30, db_index=True)
    intro = models.CharField(max_length=300, null=True, blank=True)
    created_at = models.DateTimeField(auto_now_add=True, verbose_name="創建時間")
    updated_at = models.DateTimeField(auto_now=True, verbose_name="更新時間")

class TeacherAssistant(models.Model):
    name = models.CharField(max_length=30, db_index=True)
    teacher = models.OneToOneField(Teacher, null=True, blank=True, on_delete=models.SET_NULL)
    created_at = models.DateTimeField(auto_now_add=True, verbose_name="創建時間")
    updated_at = models.DateTimeField(auto_now=True, verbose_name="更新時間")

2. 老師與課程 (1:N):
class Course(models.Model):
    title = models.CharField(max_length=50, db_index=True)
    teacher = models.ForeignKey(Teacher, on_delete=models.CASCADE)
    created_at = models.DateTimeField(auto_now_add=True, verbose_name="創建時間")
    updated_at = models.DateTimeField(auto_now=True, verbose_name="更新時間")

3. 課程與學生 (M:N):
class Student(models.Model):
    name = models.CharField(max_length=30, db_index=True)
    course = models.ManyToManyField(Course)
    gender= models.CharField(choices=((1,"男"), (2, "女"), (0, "保密")), max_length=1, default=0) 
    created_at = models.DateTimeField(auto_now_add=True, verbose_name="創建時間")
    updated_at = models.DateTimeField(auto_now=True, verbose_name="更新時間")



參考資料:
  1. 一次搞定:所有Python Web框架開發百科全書



沒有留言:

張貼留言