Django分页查询并返回jsons数据(中文乱码解决方法)
作者:SharpCJ 发布时间:2022-12-02 22:44:20
一、引子
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)
来源:http://www.cnblogs.com/joy99/p/9404479.html


猜你喜欢
- 一、基础环境准备windows环境:Pycharmpython3.6Django2.0.1Mysql5.7安装django 在pycharm
- 目的:在百度贴吧输入关键字和要查找的起始结束页,获取帖子里面楼主所发的图片思路:获取分页里面的帖子链接列表获取帖子里面楼主所发的图片链接列表
- 通常的聊天室所采用的程序,也就是Chat程序了,其基本结构原理是不会采用到数据库的。那究竟采用什么技术呢?我们知道ASP变量当中Sessio
- swagger介绍Swagger本质上是一种用于描述使用JSON表示的RESTful API的接口描述语言。Swagger与一组开源软件工具
- 本篇概要1.线程与多线程2.进程与多进程3.多线程并发下载图片4.多进程并发提高数字运算关于并发在计算机编程领域,并发编程是一个很常见的名词
- 使用下面的命令检查是否安装有MySQL Server[root@localhost etc]# rpm -qa | grep mysql /
- Go 编写定时器和定时任务在 项目开发当中,可能会遇到这样的场景:1 A任务需要在多久之后执行一次(定时器)2.B任务需要每隔多长时间执行一
- 之前安装过Anaconda3,但是今天发现我安装的Anaconda Navigator不见了,然后看了网上的各种博客发现是自己安装Anaco
- 很多jsp程序员都遇到过这样的情况,jsp页面传递参数到servlet,只要参数有中文就是乱码,且大多数是??????乱码,尝试了网上比较普
- input() 的用法Python3.x 中input() 函数接受一个标准输入数据,返回为 string 类型。python3将input
- 一、Pyecharts 概述Pyechart 是一个用于生成 Echarts 图表(Echarts 是基于 Javascript 的开源可视
- 目录一、前言二、基础命令三、正常显示中文:四、设置图样或子图五、设置x轴或y轴相关属性:六、设置标题:七、设置图例:八、进行标注:九、保存图
- 在main.js中按需引入import { Toast} from 'vantVue.use(Toast)页面中的methods中使
- Vue 3.0 正式发布了,喜大普奔😁。新的语法又要学习一阵阵,不过需要在生产环境下大面积使用,可能需要等到它的周边工具:vuex,vue-
- 近期安装了python后,发现使用pycharm工具打开代码后发现代码下边会有波浪线的显示;但是该代码语句确实没有错误,通过查询发现了两种方
- python svm实现手写数字识别——直接可用最近在做个围棋识别的项目,需要识别下面的数字,如下图:我发现现在网上很多代码是良莠不齐,…真
- Python关键字 global与nonlocalglobaldef test(): #1函数内如果没定义x,则x默认为全局变量
- 解决办法一(ThinkPHP官方提供的办法,我并没有测试过):升级到ThinkPHP3.1最新的UploadFile.class.php(h
- 当我们提到一门编程语言的效率时:通常有两层意思,第一是开发效率,这是对程序员而言,完成编码所需要的时间;另一个是运行效率,这是对计算机而言,
- 下面和大家分享一下具体的实现过程。HTML标签结构:<ul class="animation_menu">&