Django模型層
目錄
測試腳本
# 如果只想測試django中某一個py文件,則不用書寫全部前后端交互的代碼,而是直接寫一個腳本即可
# 測試環境準備,在test.py中:
import os
if __name__ == '__main__':
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'django模型層.settings') #修改項目名
import django
django.setup()
# 此處寫測試代碼,注意縮進
單表操作
from app01 import models
# 增
# models.User.objects.create(name='jason',age=19,register_time=timezone.now()) #返回被創建的對象
# user_obj = models.User(name='egon',age=20,register_time='2020-11-11')
# user_obj.save()
# 刪
# res = models.User.objects.filter(pk=2).delete() #批量刪除
# del_obj = models.User.objects.filter(pk=3).first()
# del_obj.delete() #單獨刪除
# 改
# models.User.objects.filter(pk=4).update(name='egon') #批量改
# 查
'''
1.all() 查詢所有
2.filter() 帶有過濾條件查詢
3.get() 查詢數據對象,條件有誤直接報錯
4.first() 拿QuerySet第一個元素
5.last() 拿QuerySet第一個元素
6.values()
res = models.User.objects.values('name','age)
返回僅帶有指定字段的QuerySet(列表套字典)
7.values_list()
res = models.User.objects.values_list('name','age)
返回僅帶有指定字段的QuerySet(列表套元組)
print(res.query) QuerySet對象可以使用.query查看內部sql語句
8.distinct()
去重一定要是一模一樣的數據,所以要排除主鍵
9.order_by()
res = models.User.objects.order_by('age')
默認升序
res = models.User.objects.order_by('-age') 降序
10.reverse()
先排序,后翻轉
11.count()
res = models.User.objects.count()
12.exclude()
res = models.User.objects.exclude(name='jason)
排除符合參數條件的記錄
13.exists()
res = models.User.objects.filter(name='jason).exists()
'''
查看內部sql語句的方式
# 一、QuerySet對象可以使用.query查看內部sql語句
res = models.User.objects.values_list('name','age)
print(res.query)
# 二、配置settings.py
LOGGING = {
'version': 1,
'disable_existing_loggers': False,
'handlers': {
'console':{
'level':'DEBUG',
'class':'logging.StreamHandler',
},
},
'loggers': {
'django.db.backends': {
'handlers': ['console'],
'propagate': True,
'level':'DEBUG',
},
}
}
雙下劃線查詢
res = models.User.objects.filter(age__gt=20) # 年齡大于20
res = models.User.objects.filter(age__lt=20) # 年齡小于20
res = models.User.objects.filter(age__gte=20) # 年齡大于等于20
res = models.User.objects.filter(age__in=[10,20,30]) # 年齡等于10或者20或者30
res = models.User.objects.filter(age__range=[18,40]) # 年齡大于等于18小于等于40
res = models.User.objects.filter(name__contains='n') # name字段包含'n'的,默認區分大小寫
# 忽略大小寫:
res = models.User.objects.filter(name__icontains='n')
# ignore
res = models.User.objects.filter(name__startwith='n') # name字段以'n'開頭的
res = models.User.objects.filter(name__endwith='n')
res = models.User.objects.filter(register_time__month='12') # 注冊時間為12月份的
# 好多方法自己點出來看啊
外鍵增刪改
# 一對多外鍵增刪改
# 增
models.Book.objects.create(name='三國',price=123.23,publish_id=1)
pub_obj = models.Publish.objects.filter(pk=3).first()
models.Book.objects.create(name='紅樓', price=123.00, publish=pub_obj)
# 刪
models.Publish.objects.filter(pk=3).delete() #級聯刪除
# 改
models.Book.objects.filter(pk=5).update(publish_id=4)
models.Book.objects.filter(pk=5).update(publish=pub_obj)
# 多對多外鍵增刪改,即對中間表的操作
# 增
book_obj = models.Book.objects.filter(pk=1).first()
book_obj.authors.add(1,6,7)
book_obj = models.Book.objects.filter(pk=2).first()
author_obj1 = models.Author.objects.filter(pk=2).first()
author_obj2 = models.Author.objects.filter(pk=6).first()
book_obj.authors.add(author_obj1,author_obj2)
# 刪
book_obj = models.Book.objects.filter(pk=1).first()
book_obj.authors.remove(7) # 同樣可以傳對象,支持多個
# 改
book_obj = models.Book.objects.filter(pk=1).first()
book_obj.authors.set([1,8])# 參數需要是可迭代對象,參數內同樣可以傳對象,支持多個,set不會改變與參數重復的原紀錄,會刪去不在參數中的紀錄,不回收主鍵值,另新建只在參數中有的紀錄
# 清空,即在中間表中清空某本書籍與作者的綁定關系
book_obj = models.Book.objects.filter(pk=5).first()
book_obj.authors.clear() # 無需傳參
正反向
# 正向 由外鍵所在表向外鍵關聯表查詢即為正向
# 反向 由外鍵關聯表向外鍵所在表查詢即為反向
多表查詢
# 基于對象的跨表查詢,即子查詢,正向查詢用字段,反向查詢用小寫表名
models.Book.objects.filter(pk=1).first().publish.name # 查圖書表主鍵為一的書的出版社
models.Book.objects.filter(pk=1).first().authors.all() # 查符合條件的書籍的所有作者
pub_obj = models.Publish.objects.filter(name='東方出版社').first()
pub_obj.book_set.all() # 查詢東方出版社出版的書籍
# 反向查詢時,當查詢結果有可能有多個時,需要_set.all(),一對一結果不需要
# 基于雙下劃線的跨表查詢,即連表查詢
models.Author.objects.filter(name='吳承恩').values(‘name','author_info__phone') #查詢吳承恩手機號,返回QuerySet
# 可以將返回的QuerySet當做mysql中的結果表,返回的一個不可分對象當做一條記錄。
# filter()中的字段名作為關鍵字不需用'',而values中的字段名需要''
# publish是虛擬字段,publish_id是django自動添加后綴在mysql生成的字段,.publish返回的是此外鍵關聯的publish對象,而.values('publish_id')返回的是該條記錄此字段的值
聚合查詢
from django.db.models import Max,Min,Sum,Count,Avg # 一般情況下與分組查詢一起使用
#單獨使用聚合查詢 aggregate
分組查詢
# annotate
models.Book.objects.annotate(a_num=Count('authors')).values('name','a_num') #查詢每本書的作者數量
print(models.Book.objects.aggregate(Avg('price'))
print(models.Book.objects.annotate(a_num=Count('authors')).values('name','a_num'))
print(models.Publish.objects.annotate(l_price=Min('book__price')).values('name','l_price'))
print(models.Book.objects.annotate(a_num=Count('authors')).filter(a_num__gt=1).values('name','a_num'))
print(models.Author.objects.annotate(amount=Sum('book__price')).values('name','amount'))
# 按照字段分組查詢
models.Author.objects.values('price').annotate()
F與Q查詢
# F('') 直接獲取表中某字段的數據返回到代碼位置
#
from django.db.models.functions import Concat
from django.db.models import Value
models.Book.objects.update(name=Concat(F('name'),Value('文學大師推薦')))
from django.db.models import Q
print(models.Book.objects.filter(Q(sold__gt=2000)|Q(price__lt=100)).values('name','sold','price')) # or=|,and=,,not=~
q = Q()
q.connector = 'or' # 設置條件連接關系
q.children.append(('sold__gt',2000)) # 設置比較條件,注意傳入的是一個元組
q.children.append(('price__lt',100))
print(models.Book.objects.filter(q).values('name','sold','price'))
# 即SELECT `app01_book`.`name`, `app01_book`.`sold`, `app01_book`.`price` FROM `app01_book` WHERE (`app01_book`.`sold` > 2000 or `app01_book`.`price` < 100) LIMIT 21; args=(2000, Decimal('100'))
開啟事務
# 事務的ACID:原子性,一致性,隔離性,持久性
# 事務的回滾rollback、確認commit
from django.db import transaction
with transaction.atomic():
# 內部所有ORM操作同屬于一個事務
ORM常用字段及參數
AutoField #主鍵字段 primary_key=True
CharField #即varchar verbose字段注釋,max_lenth長度
IntegerField #即int
BigIntegerField #即BigInt
DecimalField #max_digits,decimal_places
EmailField #varchar(254)
DateField #即Date auto_now/auto_now_add
DateTimeField #即DateTime
BooleanField #即布爾值,傳False/True,存0/1
TextField #沒有字數限制
FileField #upload_to ''
# 自定義字段
# class MyCharField(models.Field):
# 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):
# '''
# 返回真正的數據類型及約束條件
# :param connection:
# :return:
# '''
# return f'char({self.max_length})'
#null:即是否可以為空
#unique:是否唯一
#db_index:為字段建立索引
#default:設置字段默認值
#外鍵字段
#to_field:默認關聯另一張表的主鍵字段
#on_delete:2.x一對多一對一需要手動設定級聯
數據庫查詢優化
# ORM惰性查詢,如果查詢結果沒有被使用,則不執行查詢語句
# only/defer
models.Book.objects.only('name') # 返回包含name字段信息的對象組成的QuerySet,但仍可以.其他字段,只不過會重新查詢數據庫
models.Book.objects.defer('name') # 返回不包含name字段信息的對象組成的QuerySet,但仍可以.name字段,只不過會重新查詢數據庫
#only與defer一種是返回只包含參數字段對象組成的QuerySet,一種是返回不包含參數字段對象組成的QuerySet,如果要使用.字段訪問信息,則當返回的QuerySet中沒有此字段信息時需要重新查詢數據庫
# select_related(連表查詢)/prefetch_ralated(子查詢)
res = models.Book.objects.all()
for i in res:
print(i.publish.name) # 每循環一次都查詢一次數據庫
res = models.Book.objects.select_related('publish') # 只在這里連表查詢一次數據庫、參數只能是一對多一對一外鍵字段,只支持正向查詢
for i in res:
print(i.publish.name) # 這里使用上面的連表查詢結果,不用每次都查詢數據庫
res = models.Book.objects.prefetch_related('publish')
for i in res:
print(i.publish.name)
# 要結合具體需求,選擇查詢方法,select_related返回的對象結果可能過大,而prefetch_related查詢的次數可能更多。
圖書管理系統
# redirect參數可以直接傳URL別名,但使用帶正則的別名必須使用reverse()
# 見項目代碼
choices參數
# 如果某個字段的值是可以列舉完全的,那么通常會采用choices參數
gender_choices = (
(1,'男'),
(2,'女'),
(3,'其他')
)
gender = models.IntegerField(choices=gender_choices) # 該gender字段仍存數字,但是如果數字值在gender_choices內,那么可以輕松獲取數字對應的真正內容,字段類型由元組內第一個參數類型決定
# gender字段可以存儲不在gender_choices內的值,范圍參考數據類型
# 獲取對應信息 get_字段名_display
user_obj = models.User.objects.filter(pk=1).first()
user_obj.get_gender_display()
# 如果無對應值,則返回原值
MTV與MVC模型
# MTV,即models、templates、views
# MVC,即models、views、controller
多對多三種創建方式
class BooK
class Author
# 全自動:利用ORM自動創建中間表,可以使用ORM封裝好的操作,但無法使用ORM拓展
authors = models.ManyToManyField(to='Author')
# 半自動:可以使用ORM正反向查詢,但無法使用add、set、remove、clear四個方法,為了拓展性,一般半自動
class Book2Author(models.Model):
book = models.ForeignKey(to='Book')
author = models.ForeignKey(to='Author')
class Book
authors = models.ManyToManyField(to='Author',through='Book2Author',through_field=('book','author')) # 元組順序由中間表查詢本表、被連接表的鍵決定,可以判斷為先自后它
# 全手動:手動創建表,無法使用ORM封裝好的操作,容易拓展
class Book_Author(models.Model):
book = models.ForeignKey(to='Book')
author = models.ForeignKey(to='Author')
浙公網安備 33010602011771號