這篇文章將為大家詳細(xì)講解有關(guān)Django分頁查詢并返回jsons數(shù)據(jù)的解決方法,小編覺得挺實用的,因此分享給大家做個參考,希望大家閱讀完這篇文章后可以有所收獲。
一、引子
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')
很容易出現(xiàn)的一個錯誤是中文亂碼,重點在于 json_data = serializers.serialize("json", products, ensure_ascii=False)
中第三個參數(shù)。
二、Serialize----序列化django對象
官方文檔原文: https://docs.djangoproject.com/en/2.1/topics/serialization/
django的序列化框架提供了一個把django對象轉(zhuǎn)換成其他格式的機(jī)制,通常這些其他的格式都是基于文本的并且用于通過一個管道發(fā)送django對象,但一個序列器是可能處理任何一個格式的(基于文本或者不是)
django的序列化類位于django.core下面的serializers文件夾里面,base.py文件里面定義了序列器和反序列器的基類以及一些異常, init .py文件定義了如何根據(jù)格式來選擇對應(yīng)的序列器等內(nèi)容,我們一起來看看吧
init.py和base.py文件的函數(shù)原型如下圖
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的序列化操作了
序列化數(shù)據(jù)
在最高層的api,序列化數(shù)據(jù)是非常容易的操作,看上面的函數(shù)可知,serialize函數(shù)接受一個格式和queryset,返回序列化后的數(shù)據(jù):
簡單的寫法:
from django.core import serializers data = serializers.serialize("xml", SomeModel.objects.all())
復(fù)雜的寫法:
XMLSerializer = serializers.get_serializer("xml") xml_serializer = XMLSerializer() xml_serializer.serialize(queryset) data = xml_serializer.getvalue()
反序列化數(shù)據(jù)
一樣的簡單,接受一個格式和一個數(shù)據(jù)流,返回一個迭代器
for obj in serializers.deserialize("xml", data): do_something_with(obj)
然而,deserialize返回的的是不是簡單的django類型對象,而是DeserializedObject實例,并且這些實例是沒有保存的,請使用DeserializedObject.save()方法把這些數(shù)據(jù)保存到數(shù)據(jù)庫
序列化格式
django之處很多的序列化格式,有些需要你安裝第三方支持的模塊,xml,json和yaml是默認(rèn)支持的
注意事項
如果你是使用utf-8或者其他的非ascii編碼數(shù)據(jù),然后用json序列器,注意穿一個ensure_ascii參數(shù)進(jìn)去,否則輸出的編碼將會不正常
json_serializer = serializers.get_serializer("json")() json_serializer.serialize(queryset, ensure_ascii=False, stream=response)
序列化參數(shù)
序列化的是是可以接受額外的參數(shù)的,總共有三個參數(shù),如下:
self.stream = options.pop("stream", StringIO()) self.selected_fields = options.pop("fields", None) self.use_natural_keys = options.pop("use_natural_keys", False)
stream
將序列化后的數(shù)據(jù)輸出到該stream流中,接上面的復(fù)雜的寫法:
out = open("file.xml", "w") xml_serializer.serialize(SomeModel.objects.all(), stream=out)
selected_field
選擇序列化的屬性,通過制定fields參數(shù),fields是一個元組參數(shù),元素是選擇要序列化的屬性
from django.core import serializers data = serializers.serialize('xml', SomeModel.objects.all(), fields=('name','size'))
use_natural_keys
是否使用自然的關(guān)鍵字,默認(rèn)是false(即是使用主鍵)
默認(rèn)的外鍵和多對多關(guān)系序列化策略是使用主鍵,一般情況下是很好地,但有些情況下就不是這樣了。比如外鍵到ContentType的時候,由于ContentType是django的數(shù)據(jù)庫進(jìn)程同步的時候自動產(chǎn)生的,它們的關(guān)鍵字不是那么容易去預(yù)測的。
一個整數(shù)id也不總是最方便的索引到一個對象的方法,所以基于這些情況,django提供了use_natural_keys這個參數(shù),
一個natural key是一個可以不使用主鍵就可以用來區(qū)分一個元素的屬性組合的元組
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)
默認(rèn)Book 的序列化數(shù)據(jù)將會使用一個整數(shù)索引到一個作者,例如,用json的是,一個Book的序列化數(shù)據(jù)大概是這樣的,42是外鍵Author的主鍵
{ "pk": 1, "model": "store.book", "fields": { "name": "Mostly Harmless", "author": 42 } }
但這不是一個很好的方法,不是嗎?你需要知道這個主鍵代表到底是哪個Author,并且要求這個主鍵是穩(wěn)定和可預(yù)測的。所以,我們可以增加一個natural key的處理函數(shù),請在對應(yīng)模型的管理模型里面定義一個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'),)
這樣之后,序列化的結(jié)果大概是這樣的:
{ "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()方法
序列化過程中的依賴關(guān)系
因為natural keys依賴數(shù)據(jù)庫查詢來解析引用,所以在數(shù)據(jù)被引用之前必須確保數(shù)據(jù)是存在的??聪旅娴睦樱绻粋€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應(yīng)該在Book之前被序列化,為此,我們可以添加一個依賴關(guān)系如下:
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)
關(guān)于“Django分頁查詢并返回jsons數(shù)據(jù)的解決方法”這篇文章就分享到這里了,希望以上內(nèi)容可以對大家有一定的幫助,使各位可以學(xué)到更多知識,如果覺得文章不錯,請把它分享出去讓更多的人看到。
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。