python---django中orm的使用(5)数据库的基本操作(性能相关:select_related,和prefetch_related重点)(以及事务操作)...
生活随笔
收集整理的這篇文章主要介紹了
python---django中orm的使用(5)数据库的基本操作(性能相关:select_related,和prefetch_related重点)(以及事务操作)...
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
##################################################################
# PUBLIC METHODS THAT ALTER ATTRIBUTES AND RETURN A NEW QUERYSET # 公共方法:通過操作屬性,來返回一個新的queryset查詢集
##################################################################
def all(self)# 獲取所有的數據對象def filter(self, *args, **kwargs)# 條件查詢# 條件可以是:參數,字典,Qdef exclude(self, *args, **kwargs) #排除# 條件查詢# 條件可以是:參數,字典,Q
persion_list = models.Person.objects.all()for item in persion_list:#是已經從person表中獲取的數據print(item.id,item.ut_id,item.user)#需要再次從usertype中再去查詢一次,又發了一次請求,執行的次數增加了,降低了數據庫性能print(item.ut.title) 使用select_related獲取數據:
persion_list = models.Person.objects.all() #一次性獲取到所有數據(數據量大,占內存,只有需要連表時,才會去使用),
#包含連表(select_related中,可以一次添加多個)的信息 select_related('','',...)persion_list = models.Person.objects.all().select_related('ut')#select * from person left join usertype where person.ut_id = usertype.id
for item in persion_list:#是已經從person表中獲取的數據print(item.id,item.ut_id,item.user)#不會再去數據庫中查詢,因為數據已經取出來放在內存中print(item.ut.title)
#然后再去關聯表中取數據:select * from usertype where id in [persion_list中的id列表],
#Django將兩者數據數據相結合,然后返回給用戶,
#此方法不使用連表,也是一次獲取所有數據,高效
for item in persion_list:#是已經從person表中獲取的數據print(item.id,item.ut_id,item.user)#不會再去數據庫中查詢,因為數據已經取出來放在內存中print(item.ut.title)
persion_list = models.Person.objects.only('id','user') #select id,user from persion 只去獲取這兩個字段值。注意:但是如果在后面獲取數據的時候,獲取其他值(不包含在id,user字段),也可以獲取到,只是會再次去執行SQL語句for item in persion_list:print(item.ut_id,item.id,item.user)#其中item.ut_id不在我們only字段中,所以會再次執行SQL語句去獲取數據
#SELECT "app02_person"."id", "app02_person"."ut_id" FROM "app02_person" WHERE "app02_person"."id" = ?; args=(item.id,)
defer:
persion_list = models.Person.objects.defer('ut_id') #效果一致同上面only
DATABASES = {'default': {'ENGINE': 'django.db.backends.sqlite3','NAME': os.path.join(BASE_DIR, 'db.sqlite3'),}, 'default1': {'ENGINE': 'django.db.backends.sqlite3','NAME': os.path.join(BASE_DIR, 'db.sqlite4'),}, 'default2': {
'ENGINE': 'django.db.backends.mysql', #數據庫引擎設置
'NAME': 'test', #數據庫名稱
'USER': 'root', #數據庫用戶名
'PASSWORD':'root', #數據庫密碼
'HOST':'', #主機地址,默認localhost
'PORT':'3306' #數據庫端口
}
}
#persion_list = models.Person.objects.extra(select={'new_tag':'select title from app02_usertype where id= %s'},select_params=(1,))#無法實現動態#SELECT (select title from app02_usertype where id= 1) AS "new_tag", "app02_person"."id", "app02_person"."user", "app02_person"."ut_id" FROM "app02_person"; args=(1,) 條件查詢:persion_list = models.Person.objects.extra(tables=['app02_usertype'],where=['app02_person.ut_id = app02_usertype.id'])#SELECT "app02_person"."id", "app02_person"."user", "app02_person"."ut_id" FROM "app02_person" , "app02_usertype" WHERE (app02_person.ut_id = app02_usertype.id); args=()
def values(self, *fields):# 獲取每行數據為字典格式def values_list(self, *fields, **kwargs):# 獲取每行數據為元組def dates(self, field_name, kind, order='ASC'):# 根據時間進行某一部分進行去重查找并截取指定內容# kind只能是:"year"(年), "month"(年-月), "day"(年-月-日)# order只能是:"ASC" "DESC"# 并獲取轉換后的時間- year : 年-01-01- month: 年-月-01- day : 年-月-日models.DatePlus.objects.dates('ctime','day','DESC')def datetimes(self, field_name, kind, order='ASC', tzinfo=None):# 根據時間進行某一部分進行去重查找并截取指定內容,將時間轉換為指定時區時間# kind只能是 "year", "month", "day", "hour", "minute", "second"# order只能是:"ASC" "DESC"# tzinfo時區對象models.DDD.objects.datetimes('ctime','hour',tzinfo=pytz.UTC)models.DDD.objects.datetimes('ctime','hour',tzinfo=pytz.timezone('Asia/Shanghai'))""" pip3 install pytzimport pytzpytz.all_timezonespytz.timezone(‘Asia/Shanghai’)""" def none(self):# 空QuerySet對象
指定數據庫 models.Person.objects.raw('select * from app02_person', using="default")
def count(self):# 獲取個數def get(self, *args, **kwargs):# 獲取單個對象def create(self, **kwargs): # 創建對象
def first(self):# 獲取第一個def last(self):# 獲取最后一個
def delete(self):# 刪除def update(self, **kwargs):# 更新
def set(self,**kwargs):
#更新,將原來數據清除,重新設置為現在的數據(一對多,多對多)
def exists(self):# 是否有結果 ? 聚合函數:aggregatepython---django中orm的使用(2) # 聚合函數,獲取字典類型聚合結果from django.db.models import Count, Avg, Max, Min, Sumresult = models.UserInfo.objects.aggregate(k=Count('u_id', distinct=True), n=Count('nid'))===> {'k': 3, 'n': 4} aggregate get_or_create:存在則獲取,不存在則創建并返回該記錄obj, created = models.Person.objects.get_or_create(user='root1',defaults={'ut_id': '1',})
# defaults 指定創建時,其他字段的值
# 創建執行:INSERT INTO "app02_person" ("user", "ut_id") VALUES ('root1', 1); args=[u'root1', 1]
# 查詢執行:SELECT "app02_person"."id", "app02_person"."user", "app02_person"."ut_id" FROM "app02_person" WHERE "app02_person"."user" = 'root1'; args=(u'root1',) print(obj) #對應的記錄(已有,則是原來的記錄,原來沒有,則是剛剛創建的數據記錄)print(created) #若是剛剛創建則為True,否則為False update_or_create:如果存在,則更新,否則創建obj, created = models.Person.objects.update_or_create(user='root1',defaults={'ut_id': '2',})#BEGIN; args=None#SELECT "app02_person"."id", "app02_person"."user", "app02_person"."ut_id" FROM "app02_person" WHERE "app02_person"."user" = 'root1'; args=(u'root1',)#UPDATE "app02_person" SET "user" = 'root1', "ut_id" = 2 WHERE "app02_person"."id" = 5; args=(u'root1', 2, 5)
#obj1.ut.all() #AttributeError at /test2 'UserType' object has no attribute 'all'
print(type(obj1))
#<class 'app02.models.Person'>
obj2 = models.UserType.objects.filter(id=1).first()print(obj2.person_set.all())#正確,usertype是一,對應多,獲取的數據是一個數據集,queryset
# print(type(obj2))
#<QuerySet [<Person: Person object>, <Person: Person object>, <Person: Person object>, <Person: Person object>,<Person: Person object>]>, <class 'app02.models.UserType'>) ?
def all(self)# 獲取所有的數據對象def filter(self, *args, **kwargs)# 條件查詢# 條件可以是:參數,字典,Qdef exclude(self, *args, **kwargs) #排除# 條件查詢# 條件可以是:參數,字典,Q
?
class UserType(models.Model):title = models.CharField(max_length=32)class Person(models.Model):user = models.CharField(max_length=32)ut = models.ForeignKey(to='UserType') 測試用數據庫設計?
性能相關:select_related,和prefetch_related
select_related:表之間進行join連表操作,一次性獲取關聯的數據。
普通方法獲取數據:persion_list = models.Person.objects.all()for item in persion_list:#是已經從person表中獲取的數據print(item.id,item.ut_id,item.user)#需要再次從usertype中再去查詢一次,又發了一次請求,執行的次數增加了,降低了數據庫性能print(item.ut.title) 使用select_related獲取數據:
persion_list = models.Person.objects.all() #一次性獲取到所有數據(數據量大,占內存,只有需要連表時,才會去使用),
#包含連表(select_related中,可以一次添加多個)的信息 select_related('','',...)persion_list = models.Person.objects.all().select_related('ut')#select * from person left join usertype where person.ut_id = usertype.id
for item in persion_list:#是已經從person表中獲取的數據print(item.id,item.ut_id,item.user)#不會再去數據庫中查詢,因為數據已經取出來放在內存中print(item.ut.title)
但是連表查詢也會消耗一部分時間(連表查詢性能低),在某些情況下,使用空間換取時間沒來獲得較小的查詢時間。將連表放在同一張表中.
prefetch_related:多表連表操作時速度會慢,使用其執行多次SQL查詢在Python代碼中實現連表操作。分別在多個表中查詢得到結果,然后重組。
使用prefetch_related獲取數據:persion_list = models.Person.objects.all()#一次性獲取到所有數據(數據量大,占內存,只有需要連表時,才會去使用),#prefetch_related('','',...)persion_list = models.Person.objects.all().prefetch_related('ut')#相當于先去person表中select * from person ...(條件)#然后再去關聯表中取數據:select * from usertype where id in [persion_list中的id列表],
#Django將兩者數據數據相結合,然后返回給用戶,
#此方法不使用連表,也是一次獲取所有數據,高效
for item in persion_list:#是已經從person表中獲取的數據print(item.id,item.ut_id,item.user)#不會再去數據庫中查詢,因為數據已經取出來放在內存中print(item.ut.title)
?
?
聚合查詢:annotate(分組查詢group by)請看:python---django中orm的使用(2)
去重函數:distinct
models.Persion.objects.all().distinct('name') #查詢姓名不重復的人排序函數:order_by,可以設置多個值,排序先到后
persion_list = models.Person.objects.all().order_by('ut_id','-id') #-id代表id降序排序,默認升序排列倒序函數:reverse將獲取的數據集翻轉倒序
persion_list = models.Person.objects.all().order_by('ut_id','-id').reverse()獲取單獨字段:only和排除某些字段defer
only:persion_list = models.Person.objects.only('id','user') #select id,user from persion 只去獲取這兩個字段值。注意:但是如果在后面獲取數據的時候,獲取其他值(不包含在id,user字段),也可以獲取到,只是會再次去執行SQL語句for item in persion_list:print(item.ut_id,item.id,item.user)#其中item.ut_id不在我們only字段中,所以會再次執行SQL語句去獲取數據
#SELECT "app02_person"."id", "app02_person"."ut_id" FROM "app02_person" WHERE "app02_person"."id" = ?; args=(item.id,)
defer:
persion_list = models.Person.objects.defer('ut_id') #效果一致同上面only
切換使用的數據庫using:參數為使用的別名?def using(self, alias):
默認操作下會有models.Person.object.all().using("default') #在setting中設置 settings文件DATABASES = {'default': {'ENGINE': 'django.db.backends.sqlite3','NAME': os.path.join(BASE_DIR, 'db.sqlite3'),}, 'default1': {'ENGINE': 'django.db.backends.sqlite3','NAME': os.path.join(BASE_DIR, 'db.sqlite4'),}, 'default2': {
'ENGINE': 'django.db.backends.mysql', #數據庫引擎設置
'NAME': 'test', #數據庫名稱
'USER': 'root', #數據庫用戶名
'PASSWORD':'root', #數據庫密碼
'HOST':'', #主機地址,默認localhost
'PORT':'3306' #數據庫端口
}
}
使用方式:
models.Person.object.all().using("default1') 使用第2種數據庫去取數據 models.Person.object.all().using("default2') 使用第3種數據庫引擎下數據庫去取數據額外的查詢:extra:構造額外的查詢條件或者映射
子查詢:#persion_list = models.Person.objects.extra(select={'new_tag':'select title from app02_usertype where id= %s'},select_params=(1,))#無法實現動態#SELECT (select title from app02_usertype where id= 1) AS "new_tag", "app02_person"."id", "app02_person"."user", "app02_person"."ut_id" FROM "app02_person"; args=(1,) 條件查詢:persion_list = models.Person.objects.extra(tables=['app02_usertype'],where=['app02_person.ut_id = app02_usertype.id'])#SELECT "app02_person"."id", "app02_person"."user", "app02_person"."ut_id" FROM "app02_person" , "app02_usertype" WHERE (app02_person.ut_id = app02_usertype.id); args=()
?
################################################## # PUBLIC METHODS THAT RETURN A QUERYSET SUBCLASS # 公共方法返回一個查詢子集 ##################################################def values(self, *fields):# 獲取每行數據為字典格式def values_list(self, *fields, **kwargs):# 獲取每行數據為元組def dates(self, field_name, kind, order='ASC'):# 根據時間進行某一部分進行去重查找并截取指定內容# kind只能是:"year"(年), "month"(年-月), "day"(年-月-日)# order只能是:"ASC" "DESC"# 并獲取轉換后的時間- year : 年-01-01- month: 年-月-01- day : 年-月-日models.DatePlus.objects.dates('ctime','day','DESC')def datetimes(self, field_name, kind, order='ASC', tzinfo=None):# 根據時間進行某一部分進行去重查找并截取指定內容,將時間轉換為指定時區時間# kind只能是 "year", "month", "day", "hour", "minute", "second"# order只能是:"ASC" "DESC"# tzinfo時區對象models.DDD.objects.datetimes('ctime','hour',tzinfo=pytz.UTC)models.DDD.objects.datetimes('ctime','hour',tzinfo=pytz.timezone('Asia/Shanghai'))""" pip3 install pytzimport pytzpytz.all_timezonespytz.timezone(‘Asia/Shanghai’)""" def none(self):# 空QuerySet對象
raw:執行原生SQL:
import pymysql#創建連接 conn = pymysql.connect(host='127.0.0.1',port=3306,user='root',password='root',db='test',charset="utf8") #創建游標 cursor = conn.cursor()effect_row = cursor.execute("insert into info (name,age,sex) values ('ls',33,'男')")conn.commit()cursor.close()conn.close() pymysql操作數據庫 import pymysqlconn = pymysql.connect(host="127.0.0.1",port=3306,user="root",password="root",db="prct",charset="utf8")cursor = conn.cursor(pymysql.cursors.DictCursor) #執行存儲過程 cursor.callproc('p1')ret = cursor.fetchall()conn.commit() cursor.close() conn.close()print(ret) pymysql操作數據庫2 ?存儲過程http://www.cnblogs.com/ssyfj/p/8545601.html from django.db import connection,connectionscursor = connections['default'].cursor()cursor.execute("select * from app01_user where id > %s",[1])#select * from app01_user where id > 1; args=[1]row = cursor.fetchall()print(row) #[(2, u'\u674e\u56db'), (3, u'\u738b\u4e94')] Django執行原生SQL 執行原生SQL:res = models.Person.objects.raw('select * from app02_person')for item in res:print(item) #Person objectres = models.Person.objects.raw('select * from app01_user') #注意是可以去獲取其他數據表的結果集,最好不要這樣做,自己對應自己,不要亂用,易混淆#select * from app01_user; args=()#而且需要為這些聯合表中重復字段設置別名,以免重復select id as nid,username from app01_user for item in res:print(item) #Person object 設置參數: models.Person.objects.raw('select id as nid,username from app01_user where nid >%s',params=[4,]) 轉換列名: name_map = {'username': 'un', }res = models.Person.objects.raw('select id as nid,username from app01_user', translations=name_map)指定數據庫 models.Person.objects.raw('select * from app02_person', using="default")
?
?
#################################### # METHODS THAT DO DATABASE QUERIES # 進行數據庫查詢的方法 ####################################def count(self):# 獲取個數def get(self, *args, **kwargs):# 獲取單個對象def create(self, **kwargs): # 創建對象
def first(self):# 獲取第一個def last(self):# 獲取最后一個
def delete(self):# 刪除def update(self, **kwargs):# 更新
def set(self,**kwargs):
#更新,將原來數據清除,重新設置為現在的數據(一對多,多對多)
def exists(self):# 是否有結果 ? 聚合函數:aggregatepython---django中orm的使用(2) # 聚合函數,獲取字典類型聚合結果from django.db.models import Count, Avg, Max, Min, Sumresult = models.UserInfo.objects.aggregate(k=Count('u_id', distinct=True), n=Count('nid'))===> {'k': 3, 'n': 4} aggregate get_or_create:存在則獲取,不存在則創建并返回該記錄obj, created = models.Person.objects.get_or_create(user='root1',defaults={'ut_id': '1',})
# defaults 指定創建時,其他字段的值
# 創建執行:INSERT INTO "app02_person" ("user", "ut_id") VALUES ('root1', 1); args=[u'root1', 1]
# 查詢執行:SELECT "app02_person"."id", "app02_person"."user", "app02_person"."ut_id" FROM "app02_person" WHERE "app02_person"."user" = 'root1'; args=(u'root1',) print(obj) #對應的記錄(已有,則是原來的記錄,原來沒有,則是剛剛創建的數據記錄)print(created) #若是剛剛創建則為True,否則為False update_or_create:如果存在,則更新,否則創建obj, created = models.Person.objects.update_or_create(user='root1',defaults={'ut_id': '2',})#BEGIN; args=None#SELECT "app02_person"."id", "app02_person"."user", "app02_person"."ut_id" FROM "app02_person" WHERE "app02_person"."user" = 'root1'; args=(u'root1',)#UPDATE "app02_person" SET "user" = 'root1', "ut_id" = 2 WHERE "app02_person"."id" = 5; args=(u'root1', 2, 5)
?set補充:上面數據庫是基于外鍵一對多,一個人的類型只能有一個,一個類型可以有多個人
下面進行多對多表修改:
class Tag(models.Model):title = models.CharField(max_length=32)class User(models.Model):user = models.CharField(max_length=32)ut = models.ManyToManyField(to='Tag') User對應Tag(多對多)其中測試set:
obj2 = models.User.objects.filter(id=1).first()obj2.ut.set(2,3)#若是原來是1,2則會被修改為2,3?
?
也可以用外鍵進行測試需要使用外鍵方來進行修改,否則一些方法無法找到:
obj2 = models.Person.objects.filter(id__gt=2)obj1.ut.all()#錯誤,沒有該屬性,person是多,對應只有一,是一個單獨的對象#obj1.ut.all() #AttributeError at /test2 'UserType' object has no attribute 'all'
print(type(obj1))
#<class 'app02.models.Person'>
obj2 = models.UserType.objects.filter(id=1).first()print(obj2.person_set.all())#正確,usertype是一,對應多,獲取的數據是一個數據集,queryset
# print(type(obj2))
#<QuerySet [<Person: Person object>, <Person: Person object>, <Person: Person object>, <Person: Person object>,<Person: Person object>]>, <class 'app02.models.UserType'>) ?
?
ORM的事務操作
一:導入模塊
from django.db import transaction二:簡單使用
try:with transaction.atomic():表的增刪改操作except Exception as e:return HttpResponse("出現錯誤....")return HttpResponse("ok")?
轉載于:https://www.cnblogs.com/ssyfj/p/8698865.html
總結
以上是生活随笔為你收集整理的python---django中orm的使用(5)数据库的基本操作(性能相关:select_related,和prefetch_related重点)(以及事务操作)...的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 文本超出隐藏 综合整理
- 下一篇: linux使用free命令查看内存占用