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

一、引子

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)

Django 分页查询并返回jsons数据,中文乱码解决方法的更多相关文章

  1. [转]mysql导入导出数据中文乱码解决方法小结

    本文章总结了mysql导入导出数据中文乱码解决方法,出现中文乱码一般情况是导入导入时编码的设置问题,我们只要把编码调整一致即可解决此方法,下面是搜索到的一些方法总结,方便需要的朋友. linux系统中 ...

  2. mysql导入导出数据中文乱码解决方法小结(1、navicat导入问题已解决,创建连接后修改连接属性,选择高级->将使用Mysql字符集复选框去掉,下拉框选择GBK->导入sql文件OK;2、phpmyadmin显示乱码的问题也解决,两步:1.将sql文件以utf8的字符集编码另存,2.将文件中sql语句中的字段字符集编码改成utf8,导入OK)

    当向 MySQL 数据库插入一条带有中文的数据形如 insert into employee values(null,'张三','female','1995-10-08','2015-11-12',' ...

  3. JMeter学习-041-响应数据中文乱码解决方法

    华夏子孙,中文为母语.因而在接口测试过程中,响应数据含有中文是再也正常不过的事情.同时,初学JMeter的童鞋,经常会遇到响应数据中中文乱码的问题. 本文中提供两种方式的修正方法,仅供大家参考,谢谢. ...

  4. mysql导入数据中文乱码解决方法

    常见的MySQL导入方法有两种 第一种方法,使用MySQL命令导入 mysql -uroot -p123456 --default-character-set=utf8 [db_name] < ...

  5. linux sqlplus查询数据中文乱码解决方法记录

    locale-gen -lang en.US.UTF-8 重启.

  6. mysql导入导出数据中文乱码解决方法小结

    linux系统中 linux默认的是utf8编码,而windows是gbk编码,所以会出现上面的乱码问题. 解决mysql导入导出数据乱码问题 首先要做的是要确定你导出数据的编码格式,使用mysqld ...

  7. Spring MVC3返回JSON数据中文乱码问题解决(转)

    Spring MVC3返回JSON数据中文乱码问题解决 查了下网上的一些资料,感觉比较复杂,这里,我这几使用两种很简单的办法解决了中文乱码问题. Spring版本:3.2.2.RELEASE Jack ...

  8. Java 前台后台数据传递、中文乱码解决方法

    1.向前台传递数据;2.向后台传递数据;3.ajax post 提交数据到服务端时中文乱码解决方法;4.数组类型参数传递; 1.向前台传递数据:1.1 字符串数据传递:  这种方式只是单一的向前台传递 ...

  9. php mysql 中文乱码解决方法

    本文章向码农们介绍php mysql 中文乱码解决方法,对码农们非常实用,需要的码农可以参考一下. 从MySQL 4.1开始引入多语言的支持,但是用PHP插入的中文会出现乱码.无论用什么编码也不行 解 ...

随机推荐

  1. CentOS切换桌面模式和命令行模式

    CentOS系统中命令行模式的快捷键是[Ctrl]+[Alt]+[F1]~[F6],桌面模式的快捷键为[Ctrl]+[Alt]+[F7] 转自: http://blog.sciencenet.cn/b ...

  2. SQL命令优化(积累)

    与数据库交互的基本语言是sql,数据库每次解析和执行sql语句多需要执行很多步骤.以sql server为例,当数据库收到一条查询语句时,语法分析器会扫描sql语句并将其分成逻辑单元(如关键词.表达式 ...

  3. Mongodb默认开启与关闭

    默认启动:   $ ./mongodb   默认数据保存路径:/data/db/ 默认端口:27017   修改默认路径:   --dbpath $ ./mongdb --dbpath /mongod ...

  4. C语言while语句

    在C语言中,共有三大常用的程序结构: 顺序结构:代码从前往后执行,没有任何“拐弯抹角”: 选择结构:也叫分支结构,重点要掌握 if else.switch 以及条件运算符: 循环结构:重复执行同一段代 ...

  5. selenium的常用方法

    1.常用定位方法 find_element_by_id()find_element_by_name()find_element_by_class_name()find_element_by_tag_n ...

  6. 1855: [Scoi2010]股票交易[单调队列优化DP]

    1855: [Scoi2010]股票交易 Time Limit: 5 Sec  Memory Limit: 64 MBSubmit: 1083  Solved: 519[Submit][Status] ...

  7. IE edge是怎么了??

    IE edge 怎么不能通过$.getJSON(url,function(data){ alert(''); });获取数据呢?,其他浏览器和IE的10以下版本都没问题获取到了,这是什么情况!本来是想 ...

  8. 进击的RecyclerView入门三(要是能拖动就好了)

    还是接着上一讲"进击的RecyclerView入门二(来点小装饰?)",在上一讲中我们学到了怎么给不同的Item定制不同的外观,但貌似那个蓝色的框实在太丑了,咱还是把它干了吧. @ ...

  9. 用linux c求最大公约数

    我写了两中函数,一个是辗转相除法一个是更相减损法,主要代码如下: /*辗转相除法*/int gcd(int a, int b) { ) { return b; } else { return gcd( ...

  10. Linux系统CPU核数等信息查看

    版权声明:本文为原创文章,允许转载,转载时请务必以超链接形式标明文章 原始出处 .作者信息和本声明. https://blog.csdn.net/fgf00/article/details/52584 ...