用惯了Django的orm,在用原生sql的时候发现要分页并转换为分页对象再格式化成json传给前端还挺麻烦的,这里总结下方法,方便后续的借鉴和参考!
Django的orm能解决几乎所有的单表查询,唯独在连表查询和子查询等复杂的查询上无能为力,特别是连表查询,在工程上的使用还是非常频繁的,而Django仅支持外键(或者伪外键,即在Django的model里仍旧定义外键,但是在数据库却不加外键约束,在某种程度上也能实现双表查询,但是也相对复杂了操作),所以如何处理连表查询并把结果分页转为json返回前段也成为必须要解决的问题!
原生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)
记录笔记到此~
这个错误的原因是因为json.dumps的问题
dumps是将dict数据转化为str数据,但是dict数据中包含byte数据所以会报错
我这个是在django从数据库读取时间的时候没有转换,所以在读取时间对的时候做一下转换就可以了
table.update_time.strftime('%Y-%m-%d %H:%M:%S')
django框架自带分页器:Paginator,但是基于ORM实现的,我们肯定会有直接执行sql的需求,在直接执行sql的时候,进行分页。我模仿自带的分页类实现的,所有方法名都保持一致。
import math
from django.db import connection
from django.utils.functional import cached_property
clas...
使用Django肯定经常使用Paginator分页,很便捷。但是他可接受的分页对象必须是django orm的查询集或者list、tuple。当需要使用原生sql查询数据,分页就无法使用Paginator。
Paginator其实只需要实现两个方法count和__getitem__就可以自定义一个让Paginator分页器支持的对象,然后就可以使用Paginator分页了,不需要单独对原生sql写...
defgetdata(request):2 #使用ORM3 #all()返回的是QuerySet 数据类型;values()返回的是ValuesQuerySet 数据类型4 data = models.VM.objects.values(‘id‘, ‘ip‘, ‘host‘, ‘username‘)5 data = serializers.serialize("json",...
在做分页接口时出现了Object of type Pagination is not JSON serializable,因为JSON的JSONEncoder不认识Pagination对象。对象不能序列化的问题,在这篇文章中有讲过:TypeError: Object of type XXX is not JSON serializable
为了让接口输出的json结果更美观,把页面的信息放在同一个key下,在序列化之前先进行一次处理。用的是装饰器来实现:
from functools import w
row方法:(掺杂着原生sql和orm来执行的操作)
res = CookBook.objects.raw('select id as nid from epos_cookbook where id>%s', params=[1, ])
print(res.columns) # ['nid']
print(type(res)) # <class 'django.db.models.query.RawQuerySet'>
在select里面查询到的数据orm里面的要一一对
使用$.ajax()方法处理json数据格式,后台传过来的json格式,通过jquery中的$.ajax()之后没有结果。传过来的json格式是这样的{"infos":[{"id":402881e9564b22f701564b251aef0001,"title":"火影","publishingTime":"2016-08-0220:05:38.0","isEditable":"true"},{...
这是一篇我在初学习过程中,遇到的动态数据分页显示的问题,前台采用Ajax传给后台,后台在访问数据库取出分页数据再转换为json格式传递给前台,前台再解析显示到表格中。在此写出我在做的过程中遇到的问题,可以让其他人少走弯路。
前台方面会用到分页的插件,这是传送地址,http://www.jq22.com/jquery-info15943,下载下来,这插件是没有数据交互的,我们要做的就是把数据从数据...