模型是MVC架構中訪問資料的模組,Django的模型對各種資料庫提供了很好的支援。這裡以MySQL為例介紹Django的模型。
使用模型
啟用資料庫支援
在專案的 settings.py 檔案中找到 DATABASES 配置項, 根據資料庫配置資訊:
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME': 'test',
'USER': 'testuser',
'PASSWORD': '123456',
'HOST': 'localhost',
'PORT': '3306',
}
}
Django的目錄結構包括Project和App兩層, 同一個Project下的不同App共享Project的資料庫連線。
settins.py中INSTALLED_APPS用來維護Project中的APP包括自定義APP和外掛APP.
必須在INSTALLED_APPS中新增APP的名稱字串,該APP才可以使用模型。
實現模型類
ORM (Object Relational Mapping,物件關係對映)將程式設計師定義的類對映為資料表。Django提供了優秀的ORM實現。
一般在model.py中定義相關模型,模型類需要繼承django.db.models.Model
。
類名代表資料表名,類中的欄位代表資料表中的欄位, 類的一個例項表示一條資料記錄。
將primary_key關鍵字引數置為True,即可新增主鍵約束。
在未指定primary_key的情況下,Django會預設建立一個id
自增欄位作為主鍵。
示例:
from django.db import models
class Account(models.Model):
account_name = models.CharField(max_length=20)
account_id = models.IntegerField(primary_key=True)
balance = models.DecimalField(max_digits=2, decimal_places=2)
同步資料庫
manage.py中提供了同步資料庫的命令,在專案目錄下依次執行命令
python manage.py makemigrations
python manage.py migrate
在修改資料庫結構後只需要重新同步資料庫即可。
終端互動歷史:
E:\workspace\Django\ThirdDjango>python manage.py makemigrations
Migrations for 'ModelDjango':
0001_initial.py:
- Create model Account
E:\workspace\Django\ThirdDjango>python manage.py migrate
Operations to perform:
Apply all migrations: admin, ModelDjango, contenttypes, auth, sessions
Running migrations:
Rendering model states... DONE
Applying ModelDjango.0001_initial... OK
注意在Django1.7及以後版本中python manage.py syncdb
已被移除。
欄位
django.db.models
模組中定義了大量標準欄位,常用的包括:
CharField
SQL中的varchar型別,max_length關鍵字引數指定長度。
account_name = models.CharField(max_length=20)
IntegerField
整數字段
account_id = models.IntegerField(primary_key=True)
DecimalField
decimal型別,max_digits指定總位數, decimal_places指定小數位數
balance = models.DecimalField(max_digits=2, decimal_places=2)
AutoField
從1開始自增的整型欄位
id = models.AutoField()
DateTimeField
SQL中的datetime型別, 使用Python中的datetime.datetime型別表示
使用下面的建構函式構造一個datetime物件
datetime.datetime (year, month, day[ , hour[ , minute[ , second[ , microsecond[ , tzinfo]]]]])
關於Python的datetime模組詳情可以參考這篇部落格.
可以使用auto_now=True
關鍵字引數使例項每次執行save()時該欄位自動儲存save時間,不允許手動賦值。
更多標準欄位請見Django Book:
關係欄位
關係欄位用於儲存資料表之間的關係,包括ForeignKey, ManyToManyField等。
修改資料
在建立模型後Django提供了一系列API進行資料操作,取代原始SQL語句。
新增資料記錄
例項化模型類,用關鍵字引數對各列賦值,並呼叫物件的save()方法將物件寫入資料庫。
示例:
account_john = Account(account_name='john', accouunt_id='123', balance=0);
account_john.save()
save()方法沒有返回值,在顯式呼叫save()之前不會訪問資料庫.Account例項的欄位是可以直接訪問或修改的.
或者呼叫model_class.objects.create()
Account.objects.create(account_name='john', accouunt_id='123', balance=0)
或者使用:
Account.objects.get_or_create(account_name='john', accouunt_id='123', balance=0)
刪除資料記錄
呼叫資料記錄的delete()方法可以刪除資料記錄。
account.delete()
查詢資料
查詢資料使用QuerySet API。 QuerySet是惰性執行的,建立Query Set不會訪問資料庫,只有在訪問具體查詢結果的時候才會訪問資料庫。
獲取資料表的全部資料記錄:
Account.objects.all()
返回值可以進行切片,但不支援負索引。或者使用:
Account.objects.get(field_name=val)
示例:
Account.objects.get(account_name='john')
或者使用過濾器查詢多條記錄:
Account.objects.filter(accounnt_name=val)
嚴格等於Account.objects.filter(account_name__iexact=val)
忽略大小寫Account.objects.filter(account_name__contains=val)
名稱中包含valAccount.objects.filter(account_name__icontains=val)
忽略大小寫,包含Account.objects.filter(account_name__regex=val)
正規表示式Account.objects.filter(account_name__iregex=val)
正規表示式,忽略大小寫
與filter相反exclude用於返回不滿足條件的查詢結果。
Account.objects.exclude(account_name__contains=val)
filter與exclude可以進行鏈式查詢
Account.objects.exclude(account_name__contains='john').exlucde(balance=0)
對於查詢結果可以使用distinct()去重或者使用order_by(field)進行排序。
Account.objects.filter(account_name__regex=val).distinct()
Account.objects.filter(account_name__regex=val).oreder_by('balance')
使用reverse()方法可以反轉結果集中的元素順序,呼叫兩次將會恢復原順序。
從SQL 的角度,QuerySet和SELECT 語句等價,過濾器是像WHERE 和LIMIT 一樣的限制子句。
使用原生SQL
在模型查詢API不夠用的情況下,你可以使用原始的SQL語句。Django提供兩種方法使用原始SQL進行查詢。
一種是使用Model.objects.raw()方法,並進行原始查詢並返回模型例項:
Account.objects.filter('select * from account')
這種方法為延遲執行,如:
for a in Account.objects.filter('select account_name, balance from account'):
print(a.account_name, a.account_id)
上述語句實際上執行了3次查詢,account_name在raw中被查詢, account_id在列印時被查詢。
另一種是完全避開模型層,直接執行自定義的SQL語句。
from django.db import connection
def my_account_sql(self):
cursor = connection.cursor()
cursor.execute("UPDATE account SET account_id = 1 WHERE baz = %s", [self.baz])
cursor.execute("SELECT foo FROM bar WHERE baz = %s", [self.baz])
row = cursor.fetchone()
return row
與其它資料庫connection的用法非常類似。
編寫原始的SQL語句時,應該格外小心。 每次使用的時候,都要確保轉義了引數中任何使用者可以控制的字元,以防受到SQL隱碼攻擊。