11. 分页和过滤

操作系统: windows
IDE: Pycharm

在列出数据的时候,如果不做处理,所有的信息在一个页面中显示,这既不美观,也不符合实际。最好的方法是做分页过滤

  • 分页 :每次只读取一页的信息,返回给前端。
  • 过滤 :根据用户的提供的筛选条件,只读取符合条件的部分信息。

分页

实现分页,需要前端发送的请求中需要携带两个信息: 每页包含多少条记录需要获取第几页

前端定义列出数据请求中添加 2个url 参数: pagesizepagenum 进行对应。

修改后的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())

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值