Django原生sql语句分页转为json返回前端(Object of type 'Page' is not JSON serializable解决方法)

前文

  用惯了Django的orm,在用原生sql的时候发现要分页并转换为分页对象再格式化成json传给前端还挺麻烦的,这里总结下方法,方便后续的借鉴和参考!
  Django的orm能解决几乎所有的单表查询,唯独在连表查询和子查询等复杂的查询上无能为力,特别是连表查询,在工程上的使用还是非常频繁的,而Django仅支持外键(或者伪外键,即在Django的model里仍旧定义外键,但是在数据库却不加外键约束,在某种程度上也能实现双表查询,但是也相对复杂了操作),所以如何处理连表查询并把结果分页转为json返回前段也成为必须要解决的问题!

调用原生SQL

  原生sql在DJango的python的调用里我们可以用pymysql这个库来实现,也可以通过官方推介的mysql库(mysql.connector),不过相对官方的更推介pymysql这个库,因为这个库集成了更多的功能和问题解决方法,调试起来也非常方便!所以可以基于这两个库封装一个python类对象,在类对象下定义相应的DDL、DML实例方法,当实例调用时直接调用对应的实例方法即可。
  那除了上述封装成类对象的形式,如果仅仅是想简单地调用sql原生方法一次,并不需要封装这么复杂的操作还可以使用如下两种方式!方式1,调用model的原生语句,比如model—>Person,可以这么写:

Person.models.raw("select * from person where id = 3")

  然后你会发现上述的原生sql基本等同于orm的单表查询,所以存在的意义不大,好处是不用去和mysql建立连接、指定对应的库而已。那方式二也可以不建立连接和指定对应的库,但能实现pymysql的功能,那就是调用django.db这个库来实现,比如我要实现Person和Class两个库的链表查询,而db库已经在setting里定义好了,那么可以这么写:

from django.db import connection

cursor = connection.cursor()
cursor.execute("select * from Person a,Class b where a.id=b.id")
result = cursor.fetchall()
cursor.close()

  通过上述就能轻而易举地实现sql语句的调用,不过得到的结果result是个元祖对象,那再web后端里我们一般是返回list里嵌套dict这样的数据格式,有什么方法实现吗?可以基于fetchall再封装一个方法:

# 服务于转换fetchall结果为列表嵌套字典
def dictfetchall(cursor):
    columns = [col[0] for col in cursor.description] #拿到对应的字段列表
    return [
        dict(zip(columns, row))
        for row in cursor.fetchall()
    ]

  然后将result=cursor.fetchal()替换成result = dictfetchall(cursor)即可。不过前端的返回是要分页对象,如何分页呢?这里可以调用paginator来封装,具体如下:

def get_result(self,request):
	page = request.GET.get("page")  # 第几页
	limit = request.GET.get("limit")  # 每页多少
	if page is None or limit is None:  # 默认返回
	    page = 1
	    limit = 10
	    
	cursor = connection.cursor()
	cursor.execute("select * from Person a,Class b where a.id=b.id")
	result = dictfetchall(cursor)
	cursor.close()
	
	paginator = Paginator(result, limit)  #转为限制行数的paginator对象
	total = paginator.count  #计算总行数
	queryset = paginator.page(page) #根据前端的页数选择对应的返回结果
	
	items = json.loads(json.dumps(queryset))
	return JsonResponse(items)

  而如果是上述方法,会看到报错如下:

Object of type 'Page' is not JSON serializable解决方法

  即page对象无法转换为json格式,在用orm的时候可以通过serializers.serialize(‘json’, queryset)来转换为对应的json,不过原生的就不行,因为page对象json无法识别。一开始我的想法是自定义一个json对象,然后作为cls参数传入来识别,后面发现应该是想麻烦了,直接将page对象转为list对象即可,代码修改如下即可:

items = json.dumps(list(queryset))
return JsonResponse(items)

总结

  记录笔记到此~

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值