Django分页查询并返回jsons数据(中文乱码解决方法)


Posted in Python onAugust 02, 2018

一、引子

Django 分页查询并返回 json ,需要将返回的 queryset 序列化, demo 如下:

# coding=UTF-8

import os

from django.core import serializers
from django.core.paginator import Paginator, PageNotAnInteger, EmptyPage
from django.shortcuts import render
from django.http import HttpResponse
from mypage.models import Product


# Create your views here.


def getAllProducts(request):
  products_list = Product.objects.all()
  paginator = Paginator(products_list, 10) # Show 10 products per page
  page = request.GET.get('page', 0)
  try:
    products = paginator.page(page)
  except PageNotAnInteger:
    # If page is not an integer, deliver first page.
    products = paginator.page(10)
  except EmptyPage:
    # If page is out of range (e.g. 9999), deliver last page of results.
    products = paginator.page(paginator.num_pages)

  json_data = serializers.serialize("json", products, ensure_ascii=False)
  return HttpResponse(json_data, content_type='application/json; charset=utf-8')

很容易出现的一个错误是中文乱码,重点在于 json_data = serializers.serialize("json", products, ensure_ascii=False) 中第三个参数。

二、Serialize----序列化django对象

官方文档原文: https://docs.djangoproject.com/en/2.1/topics/serialization/

django的序列化框架提供了一个把django对象转换成其他格式的机制,通常这些其他的格式都是基于文本的并且用于通过一个管道发送django对象,但一个序列器是可能处理任何一个格式的(基于文本或者不是)

django的序列化类位于django.core下面的serializers文件夹里面,base.py文件里面定义了序列器和反序列器的基类以及一些异常, init .py文件定义了如何根据格式来选择对应的序列器等内容,我们一起来看看吧

init.py和base.py文件的函数原型如下图

def serialize(format, queryset, **options):
"""Serialize a queryset (or any iterator that returns database objects) using
a certain serializer."""
s = get_serializer(format)()
s.serialize(queryset, **options)
return s.getvalue()
class Serializer(object):
  """  Abstract serializer base class.  """
  # Indicates if the implemented serializer is only available for
  # internal Django use.
  internal_use_only = False
  def serialize(self, queryset, **options):

那下面我们开始正式讲解django的序列化操作了

序列化数据

在最高层的api,序列化数据是非常容易的操作,看上面的函数可知,serialize函数接受一个格式和queryset,返回序列化后的数据:

简单的写法:

from django.core import serializers
data = serializers.serialize("xml", SomeModel.objects.all())

复杂的写法:

XMLSerializer = serializers.get_serializer("xml")
xml_serializer = XMLSerializer()
xml_serializer.serialize(queryset)
data = xml_serializer.getvalue()

反序列化数据

一样的简单,接受一个格式和一个数据流,返回一个迭代器

for obj in serializers.deserialize("xml", data):
  do_something_with(obj)

然而,deserialize返回的的是不是简单的django类型对象,而是DeserializedObject实例,并且这些实例是没有保存的,请使用DeserializedObject.save()方法把这些数据保存到数据库

序列化格式

django之处很多的序列化格式,有些需要你安装第三方支持的模块,xml,json和yaml是默认支持的

注意事项

如果你是使用utf-8或者其他的非ascii编码数据,然后用json序列器,注意穿一个ensure_ascii参数进去,否则输出的编码将会不正常

json_serializer = serializers.get_serializer("json")()
json_serializer.serialize(queryset, ensure_ascii=False, stream=response)

序列化参数

序列化的是是可以接受额外的参数的,总共有三个参数,如下:

self.stream = options.pop("stream", StringIO())
    self.selected_fields = options.pop("fields", None)
    self.use_natural_keys = options.pop("use_natural_keys", False)

stream

将序列化后的数据输出到该stream流中,接上面的复杂的写法:

out = open("file.xml", "w")
xml_serializer.serialize(SomeModel.objects.all(), stream=out)

selected_field

选择序列化的属性,通过制定fields参数,fields是一个元组参数,元素是选择要序列化的属性

from django.core import serializers
data = serializers.serialize('xml', SomeModel.objects.all(), fields=('name','size'))

use_natural_keys

是否使用自然的关键字,默认是false(即是使用主键)

默认的外键和多对多关系序列化策略是使用主键,一般情况下是很好地,但有些情况下就不是这样了。比如外键到ContentType的时候,由于ContentType是django的数据库进程同步的时候自动产生的,它们的关键字不是那么容易去预测的。

一个整数id也不总是最方便的索引到一个对象的方法,所以基于这些情况,django提供了use_natural_keys这个参数,

一个natural key是一个可以不使用主键就可以用来区分一个元素的属性组合的元组

natural keys的反序列化

考虑这两个模型

from django.db import models
class Person(models.Model):
  first_name = models.CharField(max_length=100)
  last_name = models.CharField(max_length=100)
  birthdate = models.DateField()
  class Meta:
    unique_together = (('first_name', 'last_name'),)
class Book(models.Model):
  name = models.CharField(max_length=100)
  author = models.ForeignKey(Person)

默认Book 的序列化数据将会使用一个整数索引到一个作者,例如,用json的是,一个Book的序列化数据大概是这样的,42是外键Author的主键

{
  "pk": 1,
  "model": "store.book",
  "fields": {
    "name": "Mostly Harmless",
    "author": 42
  }
}

但这不是一个很好的方法,不是吗?你需要知道这个主键代表到底是哪个Author,并且要求这个主键是稳定和可预测的。所以,我们可以增加一个natural key的处理函数,请在对应模型的管理模型里面定义一个get_by_natural_key方法,例如:

from django.db import models
class PersonManager(models.Manager):
  def get_by_natural_key(self, first_name, last_name):
    return self.get(first_name=first_name, last_name=last_name)
class Person(models.Model):
  objects = PersonManager()
  first_name = models.CharField(max_length=100)
  last_name = models.CharField(max_length=100)
  birthdate = models.DateField()
  class Meta:
    unique_together = (('first_name', 'last_name'),)

这样之后,序列化的结果大概是这样的:

{
  "pk": 1,
  "model": "store.book",
  "fields": {
    "name": "Mostly Harmless",
    "author": ["Douglas", "Adams"]
  }
}

natural keys的序列化

如果你想在序列化的时候使用natural key,那你必须在被序列化的模型里面顶一个natural_key方法,并在序列化的时候使用use_natural_keys=True属性如下:

class Person(models.Model):
  objects = PersonManager()
  first_name = models.CharField(max_length=100)
  last_name = models.CharField(max_length=100)
  birthdate = models.DateField()
  def natural_key(self):
    return (self.first_name, self.last_name)
  class Meta:
    unique_together = (('first_name', 'last_name'),)

serializers.serialize('json', [book1, book2], use_natural_keys=True)

注意:natural_key()和get_by_natural_key()不是同时定义的,如果你只想重载natural keys的能力,那么你不必定义natural_key()方法;同样,如果你只想在序列化的时候输出这些natural keys,那么你不必定义get_by_natural_key()方法

序列化过程中的依赖关系

因为natural keys依赖数据库查询来解析引用,所以在数据被引用之前必须确保数据是存在的。看下面的例子,如果一个Book的natural key是书名和作者的组合,你可以这样写:

class Book(models.Model):
  name = models.CharField(max_length=100)
  author = models.ForeignKey(Person)

  def natural_key(self):
    return (self.name,) + self.author.natural_key()

那么问题来了,如果Author还没有被序列化呢?很明显,Author应该在Book之前被序列化,为此,我们可以添加一个依赖关系如下:

def natural_key(self):
  return (self.name,) + self.author.natural_key()
natural_key.dependencies = ['example_app.person']

这保证了Person对象是在Book对象之前被序列化的,同样,任何一个引用Book的对象只有在Person和Book对象都被序列化之后才会被序列化

继承的模型

如果是使用抽象继承的时候,不必在意这个问题;如果你使用的是多表继承,那么注意了:必须序列化所有的基类,例如:

class Place(models.Model):
  name = models.CharField(max_length=50)
class Restaurant(Place):
  serves_hot_dogs = models.BooleanField()

如果仅仅序列化Restaurant模型,那么只会得到一个serves_hot_dog属性,基类的属性将被忽略,你必须同时序列化所有的继承的模型,如下:

all_objects = list(Restaurant.objects.all()) + list(Place.objects.all())
data = serializers.serialize('xml', all_objects)

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Python 相关文章推荐
在Django的模板中使用认证数据的方法
Jul 23 Python
Python解析最简单的验证码
Jan 07 Python
分享一个简单的python读写文件脚本
Nov 25 Python
Django REST为文件属性输出完整URL的方法
Dec 18 Python
Python使用Selenium+BeautifulSoup爬取淘宝搜索页
Feb 24 Python
python matlibplot绘制多条曲线图
Feb 19 Python
基于python框架Scrapy爬取自己的博客内容过程详解
Aug 05 Python
python 动态调用函数实例解析
Oct 21 Python
python sklearn包——混淆矩阵、分类报告等自动生成方式
Feb 28 Python
Python实现对adb命令封装
Mar 06 Python
python如何查看网页代码
Jun 07 Python
PyInstaller运行原理及常用操作详解
Jun 13 Python
Python实现正整数分解质因数操作示例
Aug 01 #Python
Python列表生成式与生成器操作示例
Aug 01 #Python
Python开发最牛逼的IDE——pycharm
Aug 01 #Python
django从请求到响应的过程深入讲解
Aug 01 #Python
python3.6的venv模块使用详解
Aug 01 #Python
从请求到响应过程中django都做了哪些处理
Aug 01 #Python
Python WSGI的深入理解
Aug 01 #Python
You might like
怎样去阅读一份php源代码
2009/08/21 PHP
ajax实现无刷新分页(php)
2010/07/18 PHP
使用HMAC-SHA1签名方法详解
2013/06/26 PHP
php利用事务处理转账问题
2015/04/22 PHP
php使用ftp远程上传文件类(完美解决主从文件同步问题的方法)
2016/09/23 PHP
thinkPHP5.0框架独立配置与动态配置方法
2017/03/17 PHP
jsTree 基于JQuery的排序节点 Bug
2011/07/26 Javascript
文本框根据输入内容自适应高度的代码
2011/10/24 Javascript
jquery ajax 同步异步的执行 return值不能取得的解决方案
2012/01/08 Javascript
javascript中数组array及string的方法总结
2014/11/28 Javascript
jQuery基础知识小结
2014/12/22 Javascript
noty ? jQuery通知插件全面解析
2016/05/18 Javascript
JS实现iframe编辑器光标位置插入内容的方法(兼容IE和Firefox)
2016/06/24 Javascript
nodejs利用http模块实现银行卡所属银行查询和骚扰电话验证示例
2016/12/30 NodeJs
原生JS实现垂直手风琴效果
2017/02/19 Javascript
JS给按钮添加跳转功能类似a标签
2017/05/30 Javascript
Three.js实现浏览器变动时进行自适应的方法
2017/09/26 Javascript
原生js实现移动端触摸轮播的示例代码
2017/12/22 Javascript
vue.js 实现图片本地预览 裁剪 压缩 上传功能
2018/03/01 Javascript
基于Angular 8和Bootstrap 4实现动态主题切换的示例代码
2020/02/11 Javascript
[05:22]DOTA2 2015国际邀请赛中国区预选赛首日TOP10
2015/05/26 DOTA
浅析AST抽象语法树及Python代码实现
2016/06/06 Python
python实现解数独程序代码
2017/04/12 Python
python八皇后问题的解决方法
2018/09/27 Python
python的time模块和datetime模块实例解析
2019/11/29 Python
Python3的socket使用方法详解
2020/02/18 Python
Pytorch转tflite方式
2020/05/25 Python
Python .py生成.pyd文件并打包.exe 的注意事项说明
2021/03/04 Python
html5使用canvas绘制一张图片
2014/12/15 HTML / CSS
澳大利亚礼品篮网站:Macarthur Baskets
2019/10/14 全球购物
小学生学雷锋演讲稿
2014/04/25 职场文书
离婚协议书怎么写2014
2014/09/30 职场文书
2015年秋季小班开学寄语
2015/05/27 职场文书
css3实现背景图片半透明内容不透明的方法示例
2021/04/13 HTML / CSS
Python基础之元类详解
2021/04/29 Python
Java 异步任务计算FutureTask
2022/04/28 Java/Android