1、ORM的增删改查均需要通过管理器对象进行。
2、可使用python3 manage.py shell 进入脚本页方便操作。
3、可修改输出格式
一、ORM查询操作
1、查询方法
(1)all()方法
- 用法:
MyModel.objects.all()
- 作用:查询所有数据,等同于select * from table
- 返回值:QuerySet容器对象,内部存放MyModel实例
from bookstore.models import book
books = Book.objects.all()
for book in books:
print(book.title)
(2)values(‘列1’,‘列2’)
- 用法:
MyModel.objects.values(...)
- 作用:查询部分列的数据并返回,等同于select 列1,列2 from xxx
- 返回值:查询结果的容器,容器内存字典,每个字典代表一条数据,格式为{‘列1’:值1,…}
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'])
(3)values_list(‘列1’,‘列2’)
- 用法:
MyModel.objects.values_list(...)
- 作用:查询部分列的数据并返回,等同于select 列1,列2 from xxx
- 返回值:查询结果的容器,容器内存元组,每个元组代表一条数据,格式为(‘值1’,值2),…
(4)order_by(‘列’)
- 用法:
MyModel.objects.order_by('-列','列')
- 作用:对查询结果进行根据某个字段选择性排序,与sql中的ORDERBY相同
- 说明:默认是升序,降序需加’-’
Book.objects.order_by('-price')
'''<QuerySet [<Book: Jquery_清华大学出版社_90.00__85.00>, <Book: HTML5_机械工业出版社_90.00__105.00>, <Book: Linux_机械工业出版社_80.00__65.00>, <Book: Django_清华大学出版社_75.00__70.00>, <Book: Python_清华大学出版社_20.00__25.00>]>'''
Book.objects.values('title').order_by('-price')
''' <QuerySet [{'title': 'Jquery'}, {'title': 'HTML5'}, {'title': 'Linux'}, {'title': 'Django'}, {'title': 'Python'}]>'''
# QuerySet会自动根据mysql的语序执行
Book.objects.order_by('-price').values('title')
''' <QuerySet [{'title': 'Jquery'}, {'title': 'HTML5'}, {'title': 'Linux'}, {'title': 'Django'}, {'title': 'Python'}]>'''
# 可查询到根据何sql语句得到的对象
print(a5.query)
# SELECT `book`.`title` FROM `book` ORDER BY `book`.`price` DESC
小练习:在/bookstore/all_book/路由下用表格展示所有图书的内容
- 主路由给应用分发路由
path('bookstore/',include('bookstore.urls'))
- bookstore应用下配置目标路由
path('all_book/',views.allbook_view)
- 编写视图函数
from django.http import HttpResponse
from django.shortcuts import render
from .models import Book
# Create your views here.
def allbook_view(request):
all_book = Book.objects.all().order_by('price')
return render(request,'bookstore/all_book.html',locals())
- bookstore应用下创建templates/bookstore文件夹,并创建all_book的html页面
<table border="1px" width="800px" height="100px">
<tr>
<th>id</th>
<th>title</th>
<th>pub</th>
<th>info</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.info }}</td>
<td>{{ book.price }}</td>
<td>{{ book.market_price }}</td>
<td>
<a href="">更新</a>
<a href="">删除</a>
</td>
</tr>
{% endfor %}
</table>
(5)filter(条件)
- 语法:
MyModel.objects.filter(属性1=值1,属性2=值2)
- 作用:返回包含此条件的全部数据集
- 返回值:QuerySet容器对象,内部存放MyModel实例
- 说明:多个属性的关系为“与”
from bookstore.models import Book
books = Book.objects.filter(pub='清华大学出版社')
for book in books:
print(book.title)
(6)exclude(条件)
- 语法:
MyModel.objects.exclude(属性1=值1,属性2=值2)
- 作用:返回不包含此条件的全部数据集
- 返回值:QuerySet容器对象,内部存放MyModel实例
- 说明:多个属性的关系为“与”
from bookstore.models import Book
books = Book.objects.exclude(pub='清华大学出版社',price=50)
for book in books:
print(book.title)
(7)get(条件)
- 语法:
MyModel.objects.get(属性1=值1,属性2=值2)
- 作用:返回满足条件的唯一一条数据
- 说明:只能返回一条数据,0或多均报错
from bookstore.models import Book
book = Book.objects.get(pub='清华大学出版社',price=50)
print(book.title)
(8)类名_查询谓词
- 定义:更灵活的条件查询
- 说明:每一个查询谓词是一个独立的查询功能
查询谓词 | 解释 |
---|---|
__exact | 等值匹配 |
__contains | 包含指定值 |
__startswith | 以xxx开始 |
__endswith | 以xxx结束 |
__gt | 大于指定值 |
__gte | 大于等于 |
__lt | 小于指定值 |
__lte | 小于等于 |
__in | 是否在指定范围内(列表) |
__range | 是否在指定区间内(元组) |
2、更新操作
(1)更新单个数据
- 查:通过get()得到要修改的实体对象
- 改:通过 对象.属性 的方式修改数据
- 保存:对象.save()保存数据
(2)批量数据更新
- 直接调用QuertSet的update(属性=值)实现批量修改
books = Book.object.filter(id__gt=3)
books.update(price=0)
小练习:在all_book路由基础上增加更改功能
在/bookstore/update_book/1页面修改书籍的价格.
- 编写视图函数
def update_book(request,book_id):
try:
book = Book.objects.get(id = book_id)
except Exception as e:
print('---update book error is',e)
return HttpResponse('alter("The book is not existed")')
if request.method == 'GET':
return render(request,'bookstore/update_book.html',locals())
elif request.method == 'POST':
pass
- 配置路由与a标签
path('update_book/<int:book_id>',views.update_book)
<a href="/bookstore/update_book/{{ book.id }}">更新</a>
- 编写html页面
<form action='/bookstore/update_book/{{ book.id }}' method='post'>
title
<input type='text' value="{{ book.title }}" readonly>
<br>
pub
<input type='text' value="{{ book.pub }}" readonly>
<br>
info
<input type='text' value="{{ book.info }}" readonly>
<br>
price
<input type='text' name="price" value="{{ book.price }}">
<br>
market_price
<input type='text' name="market_price" value="{{ book.market_price }}" >
<br>
<input type="submit" value='确认修改'>
</form>
- 完善视图函数post部分
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')
3、删除操作
(1)单个数据删除
- 查找查询结果对应的数据对象
- 调用delete()方法实现删除
auth = Author.objects.get(id=1)
auth.delete()
(2)批量数据删除
- 查找查询结果满足条件的所有数据对象
- 调用集合对象的delete()方法实现删除
auth = Author.objects.filter(age__gt=65)
auth.delete()
一般都会做“伪删除”,即is_active字段为False
小练习:增加伪删除书籍的功能
路由/bookstore/delete_book?book_id=xxx,相关查询获取数据的地方要过滤出活跃数据。
- 配置路由与a标签
path('delete_book',views.delete_book)
<a href="/bookstore/delete_book?book_id={{book.id}}">删除</a>
- 编写视图函数
def delete_book(request):
# 通过查询字符串获取book_id
book_id = request.GET.get('book_id')
if not book_id:
return HttpResponse("The book is not existed")
try:
book = Book.objects.get(id = book_id,is_active=True)
except Exception as e:
print('---delete book error is',e)
return HttpResponse("The book is not existed")
book.is_active = False
book.save()
return HttpResponseRedirect('/bookstore/all_book')
二、F对象和Q对象
1、F对象
- F对象代表数据库中某条记录的字段信息
- 作用:在不获取的情况下,对数据库中的字段操作。
from django.db.models import F
F('列名')
Book.objects.all().update(market_price=F('market_price')+10)
Book.objects.filter(market_price__gt=F('price'))
注:比起读取再修改,F对象相当于上了一把锁,多人操作也不会造成竞争。
2、Q对象
Q对象可以操作复杂的逻辑(与&或|非~操作)
from django.db.models import Q
# 找出定价低于20元 或 清华大学出版社的全部书
Book.objects.filter(Q(price__lt=20)|Q(pub='清华大学出版社'))
# 查找不是机械工业出版社的书且价格低于50的书
Book.objects.filter(Q(market_price__t=50) &~Q(pub_house='机械工业出版社'))
三、聚合查询和原生数据库操作
1、聚合查询
(1)整表聚合
- 导入方法:
from django.db.models import *
- 聚合函数:Sum,Avg,Count,Max,Min
- 语法:
Mymodel.objects.aggregate(结果变量名=聚合函数('列'))
- 返回结果:{‘结果变量名’:值}
Book.objects.aggregate(sumprice=Sum('price'))
# {'sumprice': Decimal('317.00')}
(2)分组聚合-先分组再聚合
- 通过查询values找到要分组聚合的列
MyModel.objects.values('列1','列2')
- 通过返回结果的QuerySet.annotate方法
QuerySet.annotate(名=聚合函数('列'))
pub_set = Book.objects.values('pub')
pub_count_set = pub_set.annotate(myCount=Count('pub'))
# <QuerySet [{'pub': '清华大学出版社', 'myCount': 3}, {'pub': '机械工业出版社', 'myCount': 2}]>
2、原生数据库操作
- 直接用sql语句的方式进行数据库通信
(1)直接raw方法
- 语法:MyModel.objects.raw(sql语句,拼接参数)
- 返回值:RawQuerySet集合对象(只支持循环等基础操作)
- 不推荐原因:有SQL注入问题(用户通过数据上传,将恶意的sql语句提交给服务器,从而达到攻击效果)
# 案例1,用户在搜索好友的表单框里输入'1 or 1=1',可查询出所有用户数据
books = Book.objects.raw('select * from book where id=%s'%('1 or 1=1'))
# 正确写法
books = Book.objects.raw('select * from book where id=%s',['1 or 1=1'])
(2)游标cursor
- 导入cursor所在的包 from django.db import connection
- 用创建cursor类的构造函数创建cursor对象
from django.db import connection
# with语句可保证在出现异常时释放cursor资源
with connection.cursor() as cur:
cur.execute('sql语句','拼接参数')