開源web框架django知識總結(四)
一、ORM查詢操作
查詢簡介:
資料庫的查詢需要使用管理器物件進行
通過MyModel.objects管理器方法呼叫查詢方法

all()方法
用法:MyModel.objects.all() 作用:查詢MyModel物體中所有資料,等同于 select * from table 回傳值:QuerySet容器物件,內部存放MyModel實體
#在shell中執行
python manage.py shell
>>> from bookstore.models import Book
>>> books = Book.objects.all()
>>> books
<QuerySet [<Book: Book object (1)>, <Book: Book object (2)>, <Book: Book object (3)>, <Book: Book object (4)>, <Book: Book object (5)>]>
>>> for book in books:
... print("書名",book.title,"出版社",book.pub) # 注意格式tab鍵
...
書名 Python 出版社 清華大學出版社
書名 Django 出版社 清華大學出版社
書名 Jquery 出版社 機械工業出版社
書名 Linux 出版社 機械工業出版社
書名 HTML5 出版社 清華大學出版社
>>>
##################################################
#可以在模型類中定義“__str__"方法,自定義QuerySet中的輸出格式,例如 注意縮進
def __str__(self):
return '%s_%s_%s_%s'%(self.title, self.pub, self.price, self.market_price)

value(‘列1’,‘列2’,…) 方法
? 用法:MyModel.objects.value(…) 作用:查詢部分列的資料并回傳,等同于select 列1,列2 from xxx 回傳值:QuerySet 回傳查詢結果容器,容器記憶體字典,每個字典代表一條資料,格式為:{‘列1’:值1,‘列2’:值2}
>>> from bookstore.models import Book
>>> books = Book.objects.all()
>>> books
<QuerySet [<Book: Python_清華大學出版社_20.00_25.00>, <Book: Django_清華大學出版社_70.00_75.00>, <Book: Jquery_機械工業出版社_90.00_85.00>, <Book: Linux_機械工業出版社_80.00_60.00>, <Book: HTML5_清華大學出版社_90.00_105.00>]>
>>> a2 = Book.objects.values('title','pub')
>>> a2
<QuerySet [{'title': 'Python', 'pub': '清華大學出版社'}, {'title': 'Django', 'pub': '清華大學出版社'}, {'title': 'Jquery', 'pub': '機械工業出版社'}, {'title': 'Linux', 'pub': '機械工業出版社'}, {'title': 'HTML5', 'pub': '清華大學出版社'}]>
>>> for book in a2:
... print(book)
...
{'title': 'Python', 'pub': '清華大學出版社'}
{'title': 'Django', 'pub': '清華大學出版社'}
{'title': 'Jquery', 'pub': '機械工業出版社'}
{'title': 'Linux', 'pub': '機械工業出版社'}
{'title': 'HTML5', 'pub': '清華大學出版社'}
>>> for book in a2:
... print(book['title'])
...
Python
Django
Jquery
Linux
HTML5
>>>

value_list(‘列1’,‘列2’,…) 方法
用法:MyModel.objects.value_list(…) 作用:回傳元組形式的查詢結果,等同于select 列1,列2 from xxx 回傳值:QuerySet 容器物件,內部存放”元組“,會將查詢出來的資料封裝到元組中,再封裝到查詢集合QuerySet 中
>>> a3 = Book.objects.values_list('title','pub')
>>> a3
<QuerySet [('Python', '清華大學出版社'), ('Django', '清華大學出版社'), ('Jquery', '機械工業出版社'), ('Linux', '機械工業出版社'), ('HTML5', '清華大學出版社')]>
>>> for book in a3:
... print(book)
...
('Python', '清華大學出版社')
('Django', '清華大學出版社')
('Jquery', '機械工業出版社')
('Linux', '機械工業出版社')
('HTML5', '清華大學出版社')
>>> for book in a3:
... print(book[0])
...
Python
Django
Jquery
Linux
HTML5

order_by()方法
? 用法:MyModel.objects.order_by(’-列’,‘列’) 作用:與all()方法不同,它會用SQL陳述句的ORDER BY子句對查詢結果進行,根據某個欄位選擇性的進行排序
? 說明:默認是按照升序排序,降序則需要在”列“前增加,‘-’號,表示
>>> a4 = Book.objects.order_by('-price')
>>> a4
<QuerySet [<Book: Jquery_機械工業出版社_90.00_85.00>, <Book: HTML5_清華大學出版社_90.00_105.00>, <Book: Linux_機械工業出版社_80.00_60.00>, <Book: Django_清華大學出版社_70.00_75.00>, <Book: Python_清華大學出版社_20.00_25.00>]>
>>> a5 = Book.objects.values('title').order_by('-price')
>>> a5
<QuerySet [{'title': 'Jquery'}, {'title': 'HTML5'}, {'title': 'Linux'}, {'title': 'Django'}, {'title': 'Python'}]>
>>> a5 = Book.objects.order_by('-price').values('title')
>>> a5
<QuerySet [{'title': 'Jquery'}, {'title': 'HTML5'}, {'title': 'Linux'}, {'title': 'Django'}, {'title': 'Python'}]>
>>> a5.query
<django.db.models.sql.query.Query object at 0x7fcfe8247be0>
>>> print(a5.query)
SELECT `book`.`title` FROM `book` ORDER BY `book`.`price` DESC
>>>


mysite3\bookstore\views.py
from django.shortcuts import render
from .models import Book
# Create your views here.
def all_book(request):
all_book = Book.objects.all()
return render(request, 'bookstore/all_book.html', locals())
templates\bookstore\all_book.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>查看所有書籍</title>
</head>
<body>
<table border="1">
<tr>
<th>id</th>
<th>title</th>
<th>pub</th>
<th>price</th>
<th>market_price</th>
<th>op</th>
</tr>
{% for book in all_book %}
<tr>
<td>{{ book.id }}</td>
<td>{{ book.title }}</td>
<td>{{ book.pub }}</td>
<td>{{ book.price }}</td>
<td>{{ book.market_price }}</td>
<td>
<a href="">更新</a>
<a href="">洗掉</a>
</td>
</tr>
{% endfor %}
</table>
</body>
</html>
urls.py(主路由)
path('bookstore/',include('bookstore.urls')),
urls.py(子路由)
path('all_book', views.all_book),
條件查詢方法:
filter(條件)
? 語法:MyModel.objects.filter(屬性1=值1,屬性2=值2) 作用:回傳包含此條件的全部資料集
? 回傳值:QuerySet容器物件,內部存放MyModel實體 說明:當多個屬性在一起時,為”與“關系,即當

>>> from bookstore.models import Book
>>> b1 = Book.objects.filter(pub='中信出版社')
>>> b1
<QuerySet []>
>>> b1 = Book.objects.filter(pub='清華大學出版社')
>>> b1
<QuerySet [<Book: Python_清華大學出版社_20.00_25.00>, <Book: Django_清華大學出版社_70.00_75.00>, <Book: HTML5_清華大學出版社_90.00_105.00>]>
>>> b1 = Book.objects.filter(pub='清華大學出版社',title='Python2')
>>> b1
<QuerySet []>
>>> b1 = Book.objects.filter(pub='清華大學出版社',title='Python')
>>> b1
<QuerySet [<Book: Python_清華大學出版社_20.00_25.00>]>
>>>


exclude(條件)
語法:MyModel.objects.exclude(條件) 作用:回傳不包含此條件的全部的資料集
示例:查詢 清華大學出版社,定價不等于50意外的全部圖書
books = Book.objects.exclude(pub = '清華大學出版社',price = 50)
for book in books:
print(book)
get(條件)
語法:MyModel.objects.get(條件) 作用:回傳滿足條件的唯一一條資料
all_books = Book.objects.all()
print(all_books.get(title='Python'))
#print(all_books.get(pub='清華大學出版社')) # 查到多條,會報錯
說明:該方法只能回傳一條資料,查詢結果多余一條資料則拋出Model.MultipleObjectsReturned例外;查詢結果如果沒有資料則拋出Model.DoesNotExist例外
思考:如何做非等值的過濾查詢,即 where id > 1
嘗試:Book.objects.filter(id>1) ?

解決辦法:查詢謂詞
定義:做更靈活的條件查詢時,需要使用查詢謂詞, 說明:每一個查詢謂詞是一個獨立的查詢共嗯
__exact:等值匹配 示例:
from bookstore.models import Author
Author.objects.filter(id__exact=1)
# 等同于select * from author where id = 1
__contains:包含指定值 示例:
Author.objects.filter(name__contains='王')
# 等同于select * from author where name like '%w%'
__startswith:以xxx開始
__endswith:以xxx結束
__gt:大于指定值 樣例:
Author.objects.filter(age__gt = 20)
# 等同于 select * from author where age > 20
__gte:大于等于
__lt:小于
__lte:小于等于
__in:查找資料是否在指定查詢范圍內 樣例:
Author.objects.filter(countyr__in=['中國','日本','韓國'])
# 等同于 select * from author where country in ('中國','日本','韓國')
__range:查找資料是否在指定的區間范圍內 樣例:
# 查找年齡在某一區間內的所有作者
Author.objects.filter(age__range=(30,50))
# 等同于 SELECT ... WHERE Author BETWEEN 30 and 50;
二、更新操作
跟新單個資料
修改單個物體的某些欄位值的步驟:
1、查:通過get()得到要修改的物體物件
2、改:通過物件.屬性 的方式修改資料
3、保存:通過物件.save()保存資料
>>> b1 = Book.objects.get(id=1)
>>> b1
<Book: Python_清華大學出版社_20.00_25.00>
>>> b1.price = 22
>>> b1.save()
>>> b1
<Book: Python_清華大學出版社_22_25.00>
批量更新資料
直接呼叫QuerySet的update(屬性=值),實作批量修改 示例:
>>> books = Book.objects.filter(id__gt=3)
>>> books.update(price=0)
2 #表示修改2條資料
>>> books
<QuerySet [<Book: Linux_機械工業出版社_0.00_60.00>, <Book: HTML5_清華大學出版社_0.00_105.00>]>
>>> books = Book.objects.all()
>>> books.update(market_price=9.9)
5
>>> books
<QuerySet [<Book: Python_清華大學出版社_22.00_9.90>, <Book: Django_清華大學出版社_70.00_9.90>, <Book: Jquery_機械工業出版社_90.00_9.90>, <Book: Linux_機械工業出版社_0.00_9.90>, <Book: HTML5_清華大學出版社_0.00_9.90>]>
>>>
views.py
from django.http import HttpResponse, HttpResponseRedirect
from django.shortcuts import render
from .models import Book
def update_book(request, book_id):
#bookstories/update_book/1
try:
book = Book.objects.get(id=book_id)
except Exception as e:
print('--update book error is %s'%(e))
return HttpResponse('--The book is not existed')
if request.method == 'GET':
return render(request, 'bookstore/update_book.html', locals())
elif request.method == 'POST':
price = request.POST['price']
market_price = request.POST['market_price']
#改
book.price = price
book.market_price = market_price
#保存
book.save()
return HttpResponseRedirect('/bookstore/all_book')
update_book.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>更改書籍</title>
</head>
<body>
<form action="/bookstore/update_book/{{ book.id }}" method="post">
<p>
title <input type="text" value="{{ book.title }}" disabled="disabled">
</p>
<p>
pub <input type="text" value="{{ book.pub }}" disabled="disabled">
</p>
<p>
price <input type="text" name="price" value="{{ book.price }}">
</p>
<p>
market_price <input type="text" name="market_price" value="{{ book.market_price }}">
</p>
<p>
<input type="submit" value="更新">
</p>
</form>
</body>
</html>
補全all_book.html鏈接
<a href="/bookstore/update_book/{{ book.id }}">更新</a>
bookstore\urls.py(子路由)
path('update_book/<int:book_id>', views.update_book),
三、洗掉操作
單個資料洗掉
1、查找查詢結果對應的一個資料物件
2、呼叫這個資料物件的delete()方法實作洗掉
views.py
# 物理洗掉
def delete_book(request):
#通過獲取查詢字串 book_id 拿到要洗掉的book的id
book_id = request.GET.get('book_id')
if not book_id:
return HttpResponse('---請求例外')
try:
book = Book.objects.get(id=book_id)
book.delete()
except Exception as e:
print('---delete book get error %s'%(e))
return HttpResponse('---The book id is error')
return HttpResponseRedirect('/bookstore/all_book')
urls.py
path('delete_book', views.delete_book)
all_book.html
<a href="/bookstore/delete_book?book_id={{ book.id }}">洗掉</a>
批量洗掉
1、查找查詢結果集中滿足條件的全部QuerySet查詢集合物件
2、呼叫查詢集合物件的delete()方法實作洗掉
# 洗掉全部書籍中,id大于2的全部資訊
book = Book.objects.filter(id__gt=2)
book.delete()
偽洗掉(邏輯洗掉)
實際需求中,通常不會輕易在業務里把資料真正刪掉,取而代之的是做偽洗掉,即在表中添加一個布爾型欄位(is_active),默認是True;執行洗掉時,將欲洗掉資料的is_active欄位設定為False
注意:用偽洗掉時,確保顯示資料的地方,均加了is_active=True的過濾
新增bookstories/models.py中,欄位
is_active = models.BooleanField('是否活躍',default = True)
執行遷移
views.py
在def all_book(request):查詢中也要加filter(is_active=True)
def delete_book(request):
#通過獲取查詢字串 book_id 拿到要洗掉的book的id
book_id = request.GET.get('book_id')
if not book_id:
return HttpResponse('---請求例外')
try:
book = Book.objects.get(id=book_id,is_active=True)
except Exception as e:
print('---delete book get error %s'%(e))
return HttpResponse('---The book id is error')
#將其is_active 改成False
book.is_active = False
book.save()
#302跳轉至all_book
return HttpResponseRedirect('/bookstore/all_book')
url.py
path('delete_book', views.delete_book)
四、F物件和Q物件
F物件
一個F物件代表資料庫中某條記錄的欄位資訊
作用:通常是對資料庫中的欄位值在不獲取的情況下進行操作,用于類屬性(欄位)之間的比較
語法:
from django.db.models import F
F('列名')
views.py
# 將全部圖書市場價降價50
from django.db.models import F
def all_book_F(request):
Book.objects.all().update(market_price=F('market_price')-50)
return HttpResponseRedirect('/bookstore/all_book')
urls.py
path('all_book_F',views.all_book_F),
#查出市場價大于定價全部圖書
from django.db.models import F
from .models import Book
def all_book_F(request):
all_book=Book.objects.filter(market_price__gt=F('price'))
return render(request, 'bookstore/all_book.html', locals())
Q物件
當在獲取查詢結果集,使用復雜的邏輯或|、邏輯非~等操作時,可以借助于Q物件進行操作
如:想找出定價低于”20元“或”清華大學出版社“的全部書,可以寫成
Book.objects.filter(Q(price__lt=20)|Q(pub="清華大學出版社"))
Q物件在資料包django.db.models中,需要先匯入,再使用
作用:在條件中,用來實作除and(&)以外的or(|)或not(~)操作
運算子:&與操作,|或操作,~非操作 語法:
from django.db.models import Q
Q(條件1)|(條件2) # 條件1成立或條件2成立
Q(條件1)&(條件2) # 條件1成立和條件2同時成立
Q(條件1)&~(條件2) # 條件1成立且條件2不成立
...
示例:
views.py
#想找出定價低于”75“且”清華大學出版社“的全部書
from django.db.models import Q
def all_book_Q(request):
all_book = Book.objects.filter(Q(price__lt=75)&Q(pub='清華大學出版社'))
return render(request, 'bookstore/all_book.html', locals())
urls.py
path('all_book_Q',views.all_book_Q),
五、聚合查詢和原生資料庫操作
聚合查詢:是指對一個資料表中的欄位的資料進行部分或全部進行統計查詢,查bookstore_book資料表中的全部書的平均價格,查詢所有書的總個數等都要使用聚合查詢,
聚合查詢分為:整表聚合,分組聚合
整表聚合,不帶分組的聚合查詢是指將全部資料進行集中統計查詢
聚合函式【需要匯入】
? 匯入方法: from django.db.models import * 聚合函式:Sum,Avg,Count,Max,MIn
? 語法:MyModel.objects.aggregate(結果變數名=聚合函式(‘列’))
? 回傳結果:結果變數名和值,組成的字典 格式為:{“結果變數名”:值}
>>> from django.db.models import Count
>>> from bookstore.models import Book
>>> Book.objects.aggregate(res=Count('id'))
{'res': 4}
>>>
>>> Book.objects.aggregate(res=Count('id')).get('res')
4
分組聚合:是指通過查詢結果中每一個物件所關聯的物件集合,從而得出總結算值(也可以是平均值或總和),即為查詢集的每一項生成聚合,
語法:QuerySet.annotate(結果變數名=聚合函式(‘列’)) 回傳值:QuerySet
1、通過先用查詢結果MyModel.objects.values查找查詢需要分組聚合的列 MyModel.objects.values(‘列1’,‘列2’),如:
>>> pub_set = Book.objects.values('pub')
>>> pub_set
<QuerySet [{'pub': '清華大學出版社'}, {'pub': '清華大學出版社'}, {'pub': '機械工業出版社'}, {'pub': '機械工業出版社'}]>
2、通過回傳結果的QuerySet.annotate方法分組聚合得到分組結果
QuerySet.annotate(名=聚合函式(‘列))
>>> pub_count_set = pub_set.annotate(myCount=Count('pub'))
>>> pub_count_set
<QuerySet [{'pub': '清華大學出版社', 'myCount': 2}, {'pub': '機械工業出版社', 'myCount': 2}]>
原生資料庫操作(自己卡一下就好)
Django也可以支持直接用sql陳述句的方式通信資料庫
查詢:使用MyModel.objects.raw()進行資料庫查詢操作
語法:MyModel.objects.raw(sql陳述句,拼接引數)
回傳值:RawQuerySet集合物件【只支持基本操作,比如回圈】
books = models.Book.objects.raw('select * from bookstore_book')
for book in books:
print(book)
使用原生陳述句時小心SQL注入
定義:用戶通過資料上傳,將惡意的sql陳述句提交給服務器,從而達到攻擊效果
案例1:用戶在搜索好友的表單框輸入 ‘1 or 1=1’
s1 = Book.objects.raw('select * from bookstore_book where id=%s'%('1 or 1=1'))
攻擊結果:可查詢出所有用戶資料

原生資料庫操作–cursor
完全跨過模型類操作資料庫:查詢、更新、洗掉
1、匯入cursor所在包 from django.db import connection
2、用創建cursor類的建構式創建cursor物件,再使用cursor物件,為保證在出現例外時能釋放cursor資源,通常使用with陳述句進行創建操作
from django.db import connection
with connection.cursor() as cur:
cur.execute('執行SQL陳述句','拼接引數')


祝大家學習python順利!
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/305206.html
標籤:python
