操作系统: windows
IDE: Pycharm
在列出数据的时候,如果不做处理,所有的信息在一个页面中显示,这既不美观,也不符合实际。最好的方法是做分页和过滤
- 分页 :每次只读取一页的信息,返回给前端。
- 过滤 :根据用户的提供的筛选条件,只读取符合条件的部分信息。
分页
实现分页,需要前端发送的请求中需要携带两个信息: 每页包含多少条记录 和 需要获取第几页。
前端定义列出数据请求中添加 2个url 参数: pagesize 和 pagenum 进行对应。
修改后的api接口文档:API接口文档1.2
Django提供了对分页的支持,具体的信息可以查看其官方文档
以列出药品的代码为例, 可以修改 listmedicine 函数:
# 列出药品信息
def listmedicine(request):
try:
# 返回一个 QuerySet 对象 ,包含所有的表记录
qs = Medicine.objects.values().order_by('-id')
# 查看是否有 关键字 搜索 参数
keywords = request.params.get('keywords',None)
if keywords:
conditions = [Q(name__contains=one) for one in keywords.split(' ') if one]
query = Q()
for condition in conditions:
query &= condition
qs = qs.filter(query)
# 要获取的第几页
pagenum = request.params['pagenum']
# 每页要显示多少条记录
pagesize = request.params['pagesize']
# 使用分页对象,设定每页多少条记录
pgnt = Paginator(qs, pagesize)
# 从数据库中读取数据,指定读取其中第几页
page = pgnt.page(pagenum)
# 将 QuerySet 对象 转化为 list 类型
retlist = list(page)
# total指定了 一共有多少数据
return JsonResponse({'ret': 0, 'retlist': retlist,'total': pgnt.count})
except EmptyPage:
return JsonResponse({'ret': 0, 'retlist': [], 'total': 0})
except:
return JsonResponse({'ret': 2, 'msg': f'未知错误\n{traceback.format_exc()}'})
返回的信息,包括一页的数据, 还需要告诉前端, 符合条件的总共有多少条记录 。因为这样,前端可以计算出, 总共有多少页,从而正确的显示出分页界面。
pgnt = Paginator(qs, pagesize)
创建了分页对象,在初始化参数里面设定每页多少条记录。返回的分页对象赋值给变量 pgnt。
这样一页的数据 就可以通过 pgnt.page(pagenum) 获取,而总共有多少页,通过 pgnt.count 得到。
过滤
过滤 :根据用户的提供的筛选条件,只读取符合条件的部分信息。
比如,列出药品,需要根据 药品描述 中包含的关键字来查询。而且用户可能会输入多个关键字, 比如乳酸和注射液 。
这就有一个问题, 多个关键字查询 是 且 的关系 还是 或 的关系。
且的关系 :
首先,在列出药品的请求消息里面 添加一个参数 keywords 保存关键字信息。里面包含的多个关键字之间用 空格 分开。
查询过滤条件,前面我们学过,可以通过 QuerySet 对象的 filter方法, 比如
qs.filter(name__contains='乳酸')
注意: name__contains='乳酸' 表示name字段包含乳酸这个关键字。
Django执行到该代码时,会自动转换为SQL条件从句到数据库进行查询:
WHERE name LIKE '%乳酸%'
如果有多个过滤条件, 可以继续在后面调用filter方法,比如
qs.filter(name__contains='乳酸',name__contains='注射液')
就等价于下面的 SQL条件从句
WHERE name LIKE '%乳酸%' AND name LIKE '%注射液%'
多个过滤条件, 也可以多个filter方法链在一起,比如
qs.filter(name__contains='乳酸').filter(name__contains='注射液')
通常在同一张表中过滤,这两种写法结果一样。
或的关系:
且的关系表示一种 AND 关系, 也就是要同时满足这些条件。
当需要用到 OR 的关系时,可以使用 Django 里面提供的 Q 对象 。
了解Q对象的详细用法
Q对象的初始化参数里面携带和filter 语法一致的 条件,例如:
from django.db.models import Q
qs.filter(Q(name__contains='乳酸'))
如果我们查询的多个过滤条件是 或 的关系,就用 竖线符号| 连接多个Q对象,比如:
qs.filter( Q(name__contains='乳酸') | Q(name__contains='注射液'))
等价于SQL从句:
WHERE name LIKE '%乳酸%' OR name LIKE '%注射液%'
如果我们查询的多个过滤条件是 且 的关系,也可以用 & 符号 连接多个Q对象,比如
qs.filter( Q(name__contains='乳酸') & Q(name__contains='注射液'))
等价于SQL从句:
WHERE name LIKE '%乳酸%' AND name LIKE '%注射液%'
和上面且的写法效果相同。
当过滤条件是运行时动态获取时,没法预先像下面这样写在代码中时,就可以使用Q对象
qs.filter(name__contains='乳酸',name__contains='注射液')
过滤类型
除了等于、包含 这两种过滤类型, 还有大于、小于、值在列表中等等。
参考官方文档
应用到项目中:
def listmedicine(request):
try:
# .order_by('-id') 表示按照 id字段的值 倒序排列
# 这样可以保证最新的记录显示在最前面
qs = Medicine.objects.values().order_by('-id')
# 查看是否有 关键字 搜索 参数
keywords = request.params.get('keywords',None)
if keywords:
conditions = [Q(name__contains=one) for one in keywords.split(' ') if one]
query = Q()
for condition in conditions:
query &= condition
qs = qs.filter(query)
# 要获取的第几页
pagenum = request.params['pagenum']
# 每页要显示多少条记录
pagesize = request.params['pagesize']
# 使用分页对象,设定每页多少条记录
pgnt = Paginator(qs, pagesize)
# 从数据库中读取数据,指定读取其中第几页
page = pgnt.page(pagenum)
# 将 QuerySet 对象 转化为 list 类型
retlist = list(page)
# total指定了 一共有多少数据
return JsonResponse({'ret': 0, 'retlist': retlist,'total': pgnt.count})
except EmptyPage:
return JsonResponse({'ret': 0, 'retlist': [], 'total': 0})
except:
return JsonResponse({'ret': 2, 'msg': f'未知错误\n{traceback.format_exc()}'})
其中:
query = Q()
for condition in conditions:
query &= condition
qs = qs.filter(query)
先构建一个空的Q对象 , 充当过滤条件, 然后循环取出过滤关键字, 使用 & 叠加过滤条件。(这里用的是且关系)
循环结束时, query就是多个过滤条件同时满足的Q对象
如果需要 或 的关系, 就应该这样 :query |= condition
补充上删除订单的代码:
def deleteorder(request):
# 获取订单ID
oid = request.params['id']
try:
one = Order.objects.get(id=oid)
with transaction.atomic():
# 一定要先删除 OrderMedicine 里面的记录
OrderMedicine.objects.filter(order_id=oid).delete()
# 再删除订单记录
one.delete()
return JsonResponse({'ret': 0, 'id': oid})
except Order.DoesNotExist:
return JsonResponse({
'ret': 1,
'msg': f'id 为`{oid}`的订单不存在'
})
except:
err = traceback.format_exc()
return JsonResponse({'ret': 1, 'msg': err})
使用requests库,构建前端http请求进行测试:
import requests, pprint
'''
测试分页和过滤
'''
# 先登陆,获取sessionid
payload = {
'username': 'byhy',
'password': '88888888'
}
response = requests.post("http://127.0.0.1:8080/api/mgr/signin",
data=payload)
retDict = response.json()
sessionid = response.cookies['sessionid']
# 再发送列出请求,注意多了 keywords
payload = {
'action': 'list_medicine',
'pagenum': 1,
'pagesize': 3,
'keywords': '片'
}
response = requests.get('http://127.0.0.1:8080/api/mgr/medicines',
params=payload,
cookies={'sessionid': sessionid})
pprint.pprint(response.json())
2259

被折叠的 条评论
为什么被折叠?



