使用Django肯定经常使用Paginator分页,很便捷。但是他可接受的分页对象必须是django orm的查询集或者list、tuple。当需要使用原生sql查询数据,分页就无法使用Paginator。
Paginator其实只需要实现两个方法count
和__getitem__
就可以自定义一个让Paginator分页器支持的对象,然后就可以使用Paginator分页了,不需要单独对原生sql写分页逻辑
class QueryWrapper(object):
"""查询集包装器。实现django Paginator需要的必要方法,实现和query一样使用Paginator分页"""
def __init__(self, sql, params=None, db="default"):
"""
:param sql: sql语句
"""
self.sql = sql
self.params = params
self.db = db
def count(self):
"""计算总数据条数"""
sql = """select count(*) as count from (%s) _count""" % self.sql
data = exec_sql(sql)
if data:
return data[0]['count'] # 返回总数据条数
return 0
def __getitem__(self, k):
"""分页只使用到了切片,此处的k为slice对象"""
x, y = k.start, k.stop
sql = self.sql + ' LIMIT {start}, {num}'.format(start=x, num=y - x)
result = exec_sql(sql) # 字典列表形式返回
return result
def all(self):
"""查询所有数据"""
return exec_sql(self.sql) # 字典列表形式返回
关于__getitem__
的说明:
Python 2.0以后不建议使用__getslice__(self, i, j)
,Python 3.0以上已废弃了__getslice__
方法, 可以使用slice对象作为__getitem__()
的参数来实现切片。
__getitem__(self, key)
求表达式self[key]的值,对于序列类型,key应该是整数或slice对象。对于切片,key是一个slice对象。
slice对象: slice(start, stop, step) 用于表示切片参数,未提供的参数将为None
使用:
sql = 'select id, username, first_name from auth_user'
queryset = QueryWrapper(sql)
count = queryset.count()
data = queryset.all()
# 在Django中使用
from django.core.paginator import Paginator
pages = Paginator(queryset, per_page=10)
page = pages.page(page_no) # 获取某页数据
# 在django rest framework中使用
page = self.paginate_queryset(queryset)
results = self.get_paginated_response(page).data
print(results)
>>>
{
"count": 25,
"next": "http://127.0.0.1:8888/test/?page=2",
"previous": null,
"results": [{
"id": 11349230,
"username": "张三",
"phone": "1440182340944",
}, {
"id": 11344204,
"username": "李四",
"phone": "1440182333431",
},..
}
关于pymysql默认游标(pymysql.cursors.Cursor)获取的数据是元组类型,如果想要字典类型的数据,需要指定cursor为pymysql.cursors.DictCursor
import pymysql
#连接数据库
conn = pymysql.connect(host='192.168.1.152',port= 3306,user = 'root',passwd='123123',db='test') #db:库名
#设置游标类型,默认游标类型为元祖形式
#将游标类型设置为字典形式
cur = conn.cursor(cursor=pymysql.cursors.DictCursor)
cur.execute("select * from lcj") #逼表中所有的操作都可以再此进行操作
#将lcj表中所有数据以字典形式输出
ret = cur.fetchall()
print(ret) #[{'age': 18, 'tel': '13520617734', 'name': 'xiaoluo', 'id': 1, 'sex': '?'},
MySQLdb和pymysql类似,默认游标为MySQLdb.cursors.BaseCursor
,获取的数据是元组类型,如果想要字典类型的数据,就要设置cursorclass参数为MySQLdb.cursors.DictCursor
类。
conn = MySQLdb.connect(host='localhost', user='root', passwd='123456',db='test' cursorclass=MySQLdb.cursors.DictCursor)
cur = conn.cursor()
或者
cur = conn.cursor(cursorclass=MySQLdb.cursors.DictCursor)
cur.close()
附django原生sql查询封装常用方法
def fetchone_sql(sql, params=None, db='default', flat=False):
"""
返回一行数据
:param sql: sql语句
:param params: sql语句参数
:param db: Django数据库名
:param flat: 如果为True,只返回第一个字段值,例如:id
:return: 例如:(id, 'username', 'first_name')
"""
cursor = connections[db].cursor()
cursor.execute(sql, params)
fetchone = cursor.fetchone()
cursor.close()
if fetchone:
fetchone = fetchone[0] if flat else fetchone
return fetchone
def fetchone_to_dict(sql, params=None, db='default'):
"""
返回一行数据
:param sql: sql语句
:param params: sql语句参数
:param db: Django数据库名
:return: 例如:{"id": id, "username": 'username', "first_name": 'first_name'}
"""
cursor = connections[db].cursor()
cursor.execute(sql, params)
desc = cursor.description
row = dict(zip([col[0] for col in desc], cursor.fetchone()))
cursor.close()
return row
def fetchall_sql(sql, params=None, db='default', flat=False):
"""
返回全部数据
:param sql: sql语句
:param params: sql语句参数
:param db: Django数据库名
:param flat: 如果为True,只返回每行数据第一个字段值的元组,例如:(id1, id2, id3)
:return: 例如:[(id, 'username', 'first_name')]
"""
cursor = connections[db].cursor()
cursor.execute(sql, params)
fetchall = cursor.fetchall()
cursor.close()
if fetchall:
fetchall = tuple([o[0] for o in fetchall]) if flat else fetchall
return fetchall
def fetchall_to_dict(sql, params=None, db='default'):
"""
返回全部数据
:param sql: sql语句
:param params: sql语句参数
:param db: Django数据库名
:return: 例如:[{"id": id, "username": 'username', "first_name": 'first_name'}]
"""
cursor = connections[db].cursor()
cursor.execute(sql, params)
desc = cursor.description
object_list = [
dict(zip([col[0] for col in desc], row))
for row in cursor.fetchall()
]
cursor.close()
return object_list