Django Web应用开发实战第七章
一、ORM框架
Django對各種數(shù)據(jù)庫提供了很好的支持,包括PostgreSQL、MySQL、SQLite和Oracle,且為這些數(shù)據(jù)庫提供了統(tǒng)一API方法,這些API統(tǒng)稱為ORM框架。
通過Django內(nèi)置的ORM框架可以實現(xiàn)數(shù)據(jù)庫連接和讀寫操作。
二、模型定義與數(shù)據(jù)遷移
ORM框架是一種程序技術(shù),用于實現(xiàn) 面向?qū)ο缶幊陶Z言中不同類型系統(tǒng)的數(shù)據(jù)之間的轉(zhuǎn)換,從效果上說,它創(chuàng)建了一個可在編程語言中使用的“虛擬對象數(shù)據(jù)庫”,通過對虛擬對象數(shù)據(jù)庫的操作,實現(xiàn)對目標(biāo)數(shù)據(jù)庫的操作,虛擬對象數(shù)據(jù)庫與目標(biāo)數(shù)據(jù)庫是相互對應(yīng)的。在Django中虛擬對象數(shù)據(jù)庫也稱為模型。模型字段如下:
- AutoField: 自增長類型,數(shù)據(jù)表的字段類型為整數(shù),長度為11位
- BigAutoField: 自增長類型,數(shù)據(jù)表的字段類型為bigint,長度為20位
- CharField: 字符類型
- BooleanField: 布爾類型
- CommonSeparateIntegerField: 用逗號分割的整數(shù)類型
- DateField: 日期(Date)類型
- DatetimeField: 日期時間(Datetime)類型
- Decimal: 十進(jìn)制小數(shù)類型
- EmailField: 字符類型,存儲郵箱格式的字符串
- FloatField: 浮點數(shù)類型,數(shù)據(jù)表的字段類型變成Double類型
- IntegerField: 整數(shù)類型,數(shù)據(jù)表的字段類型為11位的整數(shù)
- BigIntegerField: 長整數(shù)類型
- IPAddressField: 字符類型,存儲Ipv4地址的字符串
- GenericIPAddressField: 字符類型,存儲Ipv4和Ipv6地址的字符串
- NullBooleanField: 允許為空的布爾類型
- PositiveIntegerField: 正整數(shù)的整數(shù)類型
- PositiveSmallIntegerField: 小正整數(shù)類型,取值范圍0~32767
- SlugField: 字符類型,包含字母、數(shù)字、下劃線和連字符的字符串
- TextField: 長文本類型
- TimeField: 時間類型,顯示時分秒HH:MM[:ss[.uuuuuuu]]
- URLField: 字符類型,存儲路由格式的字符串
- BinaryField: 二進(jìn)制數(shù)據(jù)類型
- FileField: 字符類型,存儲文件路徑的字符串
- ImageField: 字符類型,存儲圖片路徑的字符串
- FilePathField: 字符類型,從特定的文件目錄選擇某個文件
允許設(shè)置的參數(shù)
源碼Field(django/db/models/fields/init.py)
- verbose_name: 默認(rèn)None,在Admin站點管理設(shè)置字符的顯示名稱
- primary_key: 默認(rèn)為False,若為True,則將字段設(shè)置成主鍵
- max_length: 默認(rèn)為None,設(shè)置字段的最大長度
- unique: 默認(rèn)為False,若為True,則設(shè)置字段的唯一屬性
- blank: 默認(rèn)為False, 若為True,則設(shè)置字段允許為空值,數(shù)據(jù)庫將存儲空字符串
- null: 默認(rèn)為False,若為True,則字段允許為空值,數(shù)據(jù)庫表現(xiàn)為NULL
- db_index: 默認(rèn)為False,若為True,則以此字段來創(chuàng)建數(shù)據(jù)庫索引
- default: 默認(rèn)為NOT_PROVIDEDD對象,設(shè)置字段的默認(rèn)值
- editable: 默認(rèn)為True,允許字段可編輯,用于設(shè)置Admin的新增數(shù)據(jù)的字段
- serialize: 默認(rèn)為True,允許字段序列化,可將數(shù)據(jù)轉(zhuǎn)化為JSON格式
- unique_for_date: 默認(rèn)為None,設(shè)置日期字段的唯一性
- unique_for_month: 默認(rèn)為None,設(shè)置月份字段的唯一性
- unique_for_year: 默認(rèn)為None,設(shè)置年份字段的唯一性
- choices: 默認(rèn)空列表,設(shè)置字段的可選值
- help_text: 默認(rèn)為空字符串,用于設(shè)置表單的提示信息
- db_column: 默認(rèn)為None,設(shè)置數(shù)據(jù)表的列名稱,若不設(shè)置,則字段名作為列名
- db_tablespace: 默認(rèn)為None,如果字段已創(chuàng)建索引,那么數(shù)據(jù)庫的表空間名稱將作為該字段的索引名稱。注意:部分?jǐn)?shù)據(jù)庫不支持表空間
- auto_created: 默認(rèn)為False,若為True,則自動創(chuàng)建字段,用于一對一的關(guān)系模型
- validators: 默認(rèn)為空列表,設(shè)置字段內(nèi)容的驗證函數(shù)
- error_message: 默認(rèn)為None,設(shè)置錯誤提示
- 以上參數(shù)適用于所有字段
- 以下適用于Meta
- abstract: 若設(shè)置為True,則該模型為抽象模型,不會在數(shù)據(jù)庫里創(chuàng)建數(shù)據(jù)表
- app_label:屬性值為字符串,將模型設(shè)置為指定的項目應(yīng)用,比如將index的models.py定義的模型A指定到其他的APP里
- db_table: 屬性值為字符串,設(shè)置模型所使用的數(shù)據(jù)庫的表名
- db_tablespace: 屬性值為字符串,設(shè)置模型所使用的數(shù)據(jù)庫的表名
- get_lastest_by: 屬性值為字符串或列表,設(shè)置模型數(shù)據(jù)的排序方式
- managed: 默認(rèn)為True,支持Django命令執(zhí)行數(shù)據(jù)遷移;若為False,則不支持?jǐn)?shù)據(jù)遷移功能
- order_with_respect_to: 屬性值為字符串,用于多對多的模型關(guān)系,指向某個關(guān)系模型的名稱,并且模型名稱必須為英文小寫。若A模型對B模型一對多,兩個模型關(guān)聯(lián)后,當(dāng)查詢模型A的某條數(shù)據(jù)時,可使用get_b_order()和set_b_order()來獲取B的關(guān)聯(lián)數(shù)據(jù);可使用get_next_in_order()和get_previous_in_order()獲取當(dāng)前數(shù)據(jù)的上一條和下一條數(shù)據(jù)
- ordering: 屬性值為列表,將模型數(shù)據(jù)以某個字段進(jìn)行排序
- permissions: 屬性值為元組,設(shè)置模型的訪問權(quán)限,默認(rèn)設(shè)置添加、修改和刪除的權(quán)限
- proxy:若設(shè)置為True,則為模型創(chuàng)建代理模型,即為模塊A克隆一個相同的模型B
- required_db_features:屬性值為列表,聲明模型依賴的數(shù)據(jù)庫功能,如['gis_enabled'],表示模型依賴GIS功能
- required_db_vendor: 屬性值為列表,聲明模型依賴的數(shù)據(jù)庫,默認(rèn)支持SQLite、PostgreSQL、MySQL和Oracle
- select_on_save: 數(shù)據(jù)新增修改算法,通常無需設(shè)置,默認(rèn)為False
- indexes: 屬性值為列表,定義數(shù)據(jù)庫表的索引列表
- verbos_name: 屬性值為字符串,設(shè)置模型直觀可讀的名稱并以復(fù)數(shù)形式表示
- verbos_name_plural: 與verbos_name相同,以單數(shù)形式表示
- label: 只讀屬性,屬性值為app_label.object_name
- label_lower: 與label相同,但其值為字母小寫
導(dǎo)數(shù)據(jù)
# 導(dǎo)出項目所有數(shù)據(jù)表
python manage.py dumpdata > data.json # 導(dǎo)出某個項目名稱所有模型
python manage.py dumpdata index > data.json # 導(dǎo)出某個項目某個模型名稱
python manage.py dumpdata index.PersonInfo > data.json # 導(dǎo)入數(shù)據(jù)
python manage.py loaddata data.json
三、數(shù)據(jù)表關(guān)系
# OneToOneField、ForeignKey、ManyToManyField
# 參數(shù)
- to: 必選參數(shù),關(guān)聯(lián)的模型名稱
- on_delete: 必選參數(shù),設(shè)置數(shù)據(jù)刪除模式,刪除模型包括:CASCADE/PROTECT/SET_NULL/SET_DEFAULT/SET/DO_NOTHING
- limit_choices_to: 設(shè)置外鍵的下拉選項,用于模型與表單和Admin后臺系統(tǒng)
- related_name: 用于模型之間的關(guān)聯(lián)查詢,如反向查詢
- related_query_name: 設(shè)置模型的查詢名稱,用于filter或get查詢,若設(shè)置參數(shù)related_name則以該參數(shù)為默認(rèn)值,若沒有設(shè)置,則以模型名稱的小寫為默認(rèn)值
- to_field: 設(shè)置外鍵與其他模型字段的關(guān)聯(lián)性,默認(rèn)關(guān)聯(lián)主鍵,若要關(guān)聯(lián)其他字段,則該字段必須具有唯一性
- db_constraint: 在數(shù)據(jù)庫里是否創(chuàng)建外鍵約束,默認(rèn)為true
- swappable: 設(shè)置關(guān)聯(lián)模型的替換功能,默認(rèn)為true,比如模型A關(guān)聯(lián)模型B,想讓模型C繼承并替換B使得A與模型C之間關(guān)聯(lián)
- symmetrical: 僅限于ManyToManyField,設(shè)置多對多字段之間的對稱模式
- through: 僅限于ManyToManyField,設(shè)置自定義模型C,用于管理和創(chuàng)建模型A和B否多對多關(guān)系
- through_fields: 僅限于ManyToManyField,設(shè)置模型C的字段,確認(rèn)模型C的哪些字段用于管理A和B否多對多關(guān)系
- db_table: 僅限于ManyToManyField,為管理和存儲多對多關(guān)系的數(shù)據(jù)表設(shè)置表名稱
四、數(shù)據(jù)查詢
去重distinct
# 去重查詢,distinct無需設(shè)置參數(shù),去重方式根據(jù)values設(shè)置的字段執(zhí)行
# SQL: select * from index_vocation where job='123';
v = Vocation.objects.values('job').filter(job='123').distinct()
聚合查詢annotate、aggregate
# annotate類似sql里面的group by
# 如果不設(shè)置values,默認(rèn)對主鍵進(jìn)行g(shù)roup by分組
# SQL: select job, sum(id) as 'id__sum' from index_vocation group by job;
v = Vocation.objects.annotate(Sum('id')) # aggregate是計算某個字段的值并返回計算結(jié)果
# SQL: select count(id) as 'id__count' from index_vocation
v = Vocation.objects.aggregate(id_count=Count('id'))
結(jié)果集union、intersection、difference
# 每次查詢的字段必須一致
v1 = Vocation.objects.filter(payment__gt=9000)
v2 = Vocation.objects.filter(payment__gt=5000) # 使用SQL UNION來組合兩個或多個查詢結(jié)果的并集
v1.union(v2) # 使用SQL INTERSECT來獲取兩個或多個查詢結(jié)果的交集
v1.intersection(v2) # 使用SQL EXCEPT來獲取兩個或多個查詢結(jié)果的差集
v2.difference(v2)
查詢條件get:查詢字段必須是主鍵或者唯一約束的字段,且查詢的數(shù)據(jù)必須存在,否則程序會拋異常
查詢條件filter:查詢字段沒有限制,只要該字段是數(shù)據(jù)表某一字即可。查詢結(jié)果以列表形式返回,查詢結(jié)果為空就返回空列表
多表查詢select_related、prefetch_related
# select_related參數(shù)為字符串格式(外鍵字段related_name), 使用left outer join方式查詢兩個數(shù)據(jù)表
# 查詢模型PersonInfo的name字段和模型Vocation的payment字段
p = PersonInfo.objects.select_related('personinfo').values('name', 'personinfo__payment') # select_related使用SQL的join實現(xiàn)的,對于多對多會增加數(shù)據(jù)查詢時間和內(nèi)存占用;prefetch_related更有優(yōu)勢
# 查詢模型Program的某行數(shù)據(jù)
p = Program.objects.prefetch_related('performer').filter(name='123').first()
# 根據(jù)外鍵字段proformer獲取當(dāng)前數(shù)據(jù)的多對多或一對多關(guān)系
p.performer.all()
執(zhí)行sql
# extra: 結(jié)果集修改器,一種提供額外查詢參數(shù)的機制
# 查詢job=123的數(shù)據(jù)
v = Vocation.objects.extra(where=['job=%s'], params=['123']) # 新增查詢字段seat, select_params為selec的%s提供參數(shù)
v = Vocation.objects.extra(select={'seat': '%s'}, select_params=['seatInfo']) # raw
v = Vocation.objects.raw('select * from index_vocation')
v[0] # execute很容易受到sql注入攻擊
from django.db import connection
cursor = connection.cursor()
cursor.execute('select * from index_vocation')
# 讀取第一行數(shù)據(jù)
cursor.fetchone()
# 讀取所有數(shù)據(jù)
cursor.fetchall()
遷移到不同數(shù)據(jù)庫
# 在default數(shù)據(jù)庫中創(chuàng)建數(shù)據(jù)表
python manage.py migrate # 在db1中創(chuàng)建數(shù)據(jù)表
python manage.py migrate --database=db1
五、數(shù)據(jù)庫事務(wù)
事物是指作為單個邏輯執(zhí)行的一系列操作,這些操作具有原子性,即這些操作要么完全執(zhí)行,要么完全不執(zhí)行。
事物處理可以確保事務(wù)性單元內(nèi)所有操作都成功完成,否則不會執(zhí)行數(shù)據(jù)操作。
事物四大特性ACID:
- 原子性(Atomicity):一個事物是一個不可分割的工作單位,事物中包括的操作要么都做,要么都不做。
- 一致性(Consistency):事物必須使數(shù)據(jù)庫從某個一致性狀態(tài)到另一個一致性狀態(tài),一致性與原子性是密切相關(guān)的。
- 隔離性:一個事物的執(zhí)行不能被其他事物干擾,即一個事物內(nèi)部的操作及使用的數(shù)據(jù)對其他事物是隔離的,各個事物之間互不干擾。
- 持久性:也稱永久性(Permanence),指一個事物一旦提交,它對數(shù)據(jù)庫中數(shù)據(jù)的改變應(yīng)該是永久性的,其他操作或故障不應(yīng)該對其有任何影響。 # Django事物定義在django/db/transaction.py
- atomic(): 在視圖函數(shù)或視圖類使用事物
- savepoint(): 開啟事物
- savepoint_rollback(): 回滾事物
- savepoint_save(): 提交事物
from django.shortcuts import render
from .models import *
from django.db import transaction
from django.db.models import F @transaction.atomic
def index(request):
# 開啟事物保護
sid = transaction.savepoint()
try:
id = request.GET.get('id', '')
if id:
v = Vocation.objects.filter(id=id)
v.update(payment=F('payment') + 1)
print('Done')
# 提交事物
# 如不設(shè)置,當(dāng)程序執(zhí)行完成后,會自動提交事物
# transaction.savepoint_commit(sid)
else:
# 全表的payment字段自減1
Vocation.objects.update(payment=F('payment') - 1)
# 事物回滾,將全表payment字段自減1的操作撤回
transaction.savepoint_rollback(sid)
except Expection as e:
transaction.savepoint_rollback(sid) return render(request, 'index.html', local()) # 使用with模塊實現(xiàn)
with transaction.atmonic():
pass
六、發(fā)送郵件
# 郵件配置信息
EMAIL_USE_SSL = True # Django與郵件服務(wù)器的連接方式是否設(shè)置ssl模式 # 郵件服務(wù)器,如果是163,就改成smtp.163.com
EMAIL_HOST = 'smtp.qq.com' # 設(shè)置服務(wù)器類型,qq郵箱分為SMTP和POP3服務(wù)器 # 郵件服務(wù)器端口
EMAIL_PORT = 465 # 若使用SMTP服務(wù)器,則端口應(yīng)為465或587 # 發(fā)送郵件的賬號
EMAIL_HOST_USER = '4512125@qq.com' # 賬號必須開啟POP3/SMTP服務(wù) # SMTP服務(wù)密碼
EMAIL_HOST_PASSWORD = 'SFSDDSFSVGSF' # 授權(quán)碼 # 設(shè)置默認(rèn)發(fā)送郵件的賬號
DEFAULT_FROM_EMAIL = EMAIL_HOST_USER
總結(jié)
以上是生活随笔為你收集整理的Django Web应用开发实战第七章的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 9天的小奶猫眼睛一大一小,是否有先天发育
- 下一篇: 学人工智能感觉怎么样