django中如何開啓事務
事務處理
提交commit,當所有的操作步驟都被完整執行後,稱該事務被提交。
回滾rollback,由於某一操作步驟執行失敗,導致所有步驟都沒有被提交,則事務必須回滾,即回到事務執行前的狀態。
事務ACID屬性
事務處理的特性,每一個事務都有他們所共有的特性,叫做ACID特性,分別是:原子性atomicity,一致性consistency、隔離性Isolation,持久性Durability。
1、原子性,事務的原子性表示事務執行過程中,把事務作爲一個工作單元處理,一個工作單元可能包括若干個操作步驟,每個操作步驟都必須完成纔算完成,若因任何原因導致其中的一個步驟操作失敗,則所有步驟操作失敗,前面的步驟必須回滾。
2、一致性,事務的一致性保證數據處於一致狀態。如果事務開始時系統處於一致狀態,則事務結束時系統也應處於一致狀態,不管事務成功還是失敗。
3、隔離性,事務的隔離性保證事務訪問的任何數據不會受到其他事務所做的任何改變的影響,直到該事務完成。
4、持久性,事務的持久性保證加入事務執行成功,則它在系統中產生的結果應該是持久的。
django開啓事務
# 暫時只需掌握Django中如何開啓事務 # mysql中通過start transaction開啓事務 # django中通過導入transaction模塊開啓事務 from django.db import transaction try: #可以對事務捕獲異常,當事務出錯時進行另外的處理 with transaction.atomic(): # sql1 # sql2 ... # 在with代碼快內書寫的所有orm操作都是屬於同一個事務 except Exception as e: print(e) print('執行其他操作')
數據庫設計三大範式
參考博客:https://www.cnblogs.com/Tang-Yuan/p/14689514.html 這裏不做詳細介紹
ORM中常用字段及參數
AutoField
int自增列,必須填入參數 primary_key=True。當model中如果沒有自增列,則自動會創建一個列名爲id的列。
IntegerField
一個整數類型,範圍在 -2147483648 to 2147483647。(一般不用它來存手機號(位數也不夠),直接用字符串存,)
CharField
字符類型,必須提供max_length參數, max_length表示字符長度。
這裏需要知道的是Django中的CharField對應的MySQL數據庫中的varchar類型,沒有設置對應char類型的字段,但是Django允許我們自定義新的字段,下面我來自定義對應於數據庫的char類型
自定義字段在實際項目應用中可能會經常用到,這裏需要對他留個印象!
from django.db import models
# Create your models here.
#Django中沒有對應的char類型字段,但是我們可以自己創建
class FixCharField(models.Field):
'''
自定義的char類型的字段類
'''
def __init__(self,max_length,*args,**kwargs):
self.max_length=max_length
super().__init__(max_length=max_length,*args,**kwargs)
def db_type(self, connection):
'''
限定生成的數據庫表字段類型char,長度爲max_length指定的值
:param connection:
:return:
'''
return 'char(%s)'%self.max_length
#應用上面自定義的char類型
class Class(models.Model):
id=models.AutoField(primary_key=True)
title=models.CharField(max_length=32)
class_name=FixCharField(max_length=16)
gender_choice=((1,'男'),(2,'女'),(3,'保密'))
gender=models.SmallIntegerField(choices=gender_choice,default=3)
自定義及使用
DateField
日期字段,日期格式 YYYY-MM-DD,相當於Python中的datetime.date()實例。
DateTimeField
日期時間字段,格式 YYYY-MM-DD HH:MM[:ss[.uuuuuu]][TZ],相當於Python中的datetime.datetime()實例。
auto_now:每次修改數據的時候都會自動更新當前時間
auto_now_add:只在創建數據的時候記錄創建時間後續不會自動修改了
EmailField
字符串類型,Django Admin以及ModelForm中提供驗證機制
DecimalField
10進制小數 - 參數: max_digits,小數總長度 decimal_places,小數位長度
FloatField
浮點型
BooleanField
布爾值類型
該字段傳佈爾值(False/True) 數據庫裏面存0/1
TextField
文本類型
該字段可以用來存大段內容(文章、博客...) 沒有字數限制
FileField
字符類型 upload_to = "/data"上傳文件的保存路徑
給該字段傳一個文件對象,會自動將文件保存到/data目錄下然後將文件路徑保存到數據庫中
/data/a.txt
ImageField
字符串,路徑保存在數據庫,文件上傳到指定目錄 - 參數: upload_to = "" 上傳文件的保存路徑 storage = None 存儲組件,默認django.core.files.storage.FileSystemStorage width_field=None, 上傳圖片的高度保存的數據庫字段名(字符串) height_field=None 上傳圖片的寬度保存的數據庫字段名(字符串)
DurationField
長整數,時間間隔,數據庫中按照bigint存儲,ORM中獲取的值爲datetime.timedelta類型
更多字段參數:https://www.cnblogs.com/Dominic-Ji/p/9203990.html
ORM字段與MySQL字段對應關係
對應關係: 'AutoField': 'integer AUTO_INCREMENT', 'BigAutoField': 'bigint AUTO_INCREMENT', 'BinaryField': 'longblob', 'BooleanField': 'bool', 'CharField': 'varchar(%(max_length)s)', 'CommaSeparatedIntegerField': 'varchar(%(max_length)s)', 'DateField': 'date', 'DateTimeField': 'datetime', 'DecimalField': 'numeric(%(max_digits)s, %(decimal_places)s)', 'DurationField': 'bigint', 'FileField': 'varchar(%(max_length)s)', 'FilePathField': 'varchar(%(max_length)s)', 'FloatField': 'double precision', 'IntegerField': 'integer', 'BigIntegerField': 'bigint', 'IPAddressField': 'char(15)', 'GenericIPAddressField': 'char(39)', 'NullBooleanField': 'bool', 'OneToOneField': 'integer', 'PositiveIntegerField': 'integer UNSIGNED', 'PositiveSmallIntegerField': 'smallint UNSIGNED', 'SlugField': 'varchar(%(max_length)s)', 'SmallIntegerField': 'smallint', 'TextField': 'longtext', 'TimeField': 'time', 'UUIDField': 'char(32)',
# 外鍵字段及參數 unique=True ForeignKey(unique=True) === OneToOneField() # 你在用前面字段創建一對一 orm會有一個提示信息 orm推薦你使用後者但是前者也能用 db_index 如果db_index=True 則代表着爲此字段設置索引 (複習索引是什麼) to_field 設置要關聯的表的字段 默認不寫關聯的就是另外一張的主鍵字段 on_delete 當刪除關聯表中的數據時,當前表與其關聯的行的行爲。 """ django2.X及以上版本 需要你自己指定外鍵字段的級聯更新級聯刪除 """
數據庫查詢優化
only與defer
""" orm語句的特點: 惰性查詢:只有當後面用到了orm語句所查詢出的參數時纔會執行,否則orm就會自動識別不執行 """ # res = models.Book.objects.all() # print(res) # 要用數據了纔會走數據庫查詢 # 想要獲取書籍表中所有書的名字 res = models.Book.objects.values('title') for d in res: print(d.get('title')) # only與defer res = models.Book.objects.only('title') res = models.Book.objects.all() # all已經包含了所有的數據,因此直接點字段就不會走數據庫 res = models.Book.objects.defer('title') # 與only的效果剛好相反 for d in res: print(d.title) # 點only括號內的字段不會走數據庫 # 點defer括號內的字段會重新走數據庫查詢 print(d.price) # 點only括號外的字段,會重新走數據庫查詢 # 點defer括號外的字段,不會走數據庫 ''' 總結: only括號外的字段不在查詢出的對象裏,查詢該字段會重新走數據庫 only括號內的字段就無需走數據庫了 defer與only相反 defer括號內的字段不在查詢出的對象裏,查詢該字段會重新走數據庫 defer括號外的字段無需走數據庫 '''
select_related與prefetch_related
# select_related與prefetch_related 都與跨表操作有關 # select_related res = models.Book.objects.all() # 每循環一次就要走一次數據庫查詢 res = models.Book.objects.select_related('publish') # INNER JOIN 是聯表操作 res = models.Book.objects.prefetch_related('publish') # IN 子查詢 for i in res: print(i.publish.name) ''' 總結: select_related內部就是連表操作,一次性將大表裏的所有數據全部封裝給查詢出來的對象 select_related(外鍵字段1__外鍵字段2__外鍵字段3) 此時無論是點book表的字段還是點publish表的字段都無需再走數據庫查詢了 注意:select_related括號內只能放外鍵字段且只能是一對多、一對一的表間關係, 如果是多對多就會報錯 prefetch_related內部就是子查詢,會將查詢出來的所有結果也給你封裝到對象中 select_related與prefetch_related給用戶的感覺是沒有什麼差距的, 但是這兩個方法各有優缺點,必須結合實際情況來考慮用誰 '''