Django paging query and return jsons data of Chinese scrambling code solution

  • 2020-12-05 17:17:14
  • OfStack

1. The introduction

Django paging query and return json, the returned queryset needs to be serialized, demo is as follows:


# 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')

One mistake that is easy to make is Chinese garbled code 于 json_data = serializers.serialize("json", products, ensure_ascii=False) The third parameter in.

Serialize-- Serializes the django object

Official documents: the original https: / / docs djangoproject. com/en / 2.1 / topics/serialization /

django's serialization framework provides a mechanism for converting django objects to other formats, which are usually text-based and used to send django objects through 1 pipe, but a sequencer may handle any 1 format (text-based or not)

The django serialization class is located in the serializers folder under django.core. The base.py file defines the base class of the sequencer and the anti-sequencer, as well as 1 exception. The ES39en.py file defines how to select the corresponding sequencer according to the format, let's have a look

The function prototypes for the init.py and base.py files are shown below


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):

So let's get down to the serialization of django

Serialized data

At the top level of api, serializing data is very easy to do. As seen above, the serialize function takes 1 format and queryset and returns the serialized data:

Simple way:


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

Complex way:


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

Deserialize data

Simple as 1, accept 1 format and 1 data stream, return 1 iterator


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

However, deserialize does not return simple OBJECTS of type django, but instances of DeserializedObject that are not saved. Use the DeserializedObject.save () method to save this data to the database

Serialization format

django has many serialization formats, some of which require you to install third party support modules, xml, json and yaml are supported by default

Matters needing attention

If you are using utf-8 or some other non-ascii to encode the data, then use the json sequencer, be careful to wear one of the ensure_ascii parameters, otherwise the output encoding will be abnormal


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

Serialization parameter

Serialization can accept additional parameters. There are three parameters in total, as follows:


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

stream

Output the serialized data to the stream stream.


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

selected_field

Select the serialized property by specifying the fields parameter, which is a tuple parameter, and the element which selects the property to serialize


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

use_natural_keys

Whether to use a natural keyword or not, the default is false (that is, use the primary key)

The default foreign key and many-to-many serialization strategy uses primary keys, which is fine in 1 case, but not in some cases. For example, when foreign keys come to ContentType, ContentType is generated automatically when the database process of django is synchronized, so their keywords are not so easy to predict.

1 integer id is also not always the most convenient way to index to 1 object, so based on these cases, django provides the parameter use_natural_keys,

natural key is a tuple that can be used to distinguish a combination of attributes of an element without using a primary key

Deserialization of natural keys

So let's think about these two models


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()
0

By default, the serialized data of Book will be indexed by 1 integer to 1 author. For example, with json, the serialized data of 1 Book will look something like this. 42 is the primary key of the foreign key Author


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()
1

But that's not a good way to do it, is it? You need to know which Author the primary key represents, and you need to know that the primary key is stable and predictable. Therefore, we can add 1 natural key processing function, please define 1 get_by_natural_key method in the management model of the corresponding model, for example:


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()
2

After this, the serialization results look something like this:


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

natural keys serialization

If you want to use natural key for serialization, you must add an natural_key method to the serialized model and use the use_natural_keys=True attribute for serialization:


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()
4

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

Note: natural_key() and get_by_natural_key() are not defined at the same time. You do not need to define the natural_key() method if you only want to override the natural keys capability. Similarly, if you only want to output these natural keys when serialized, then you don't have to define the get_by_natural_key() method

Dependencies in the serialization process

Because natural keys relies on database queries to parse references, you must ensure that the data exists before it is referenced. Look at the following example. If 1 Book natural key is a combination of title and author, you can write:


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()
5

So the question is, what if Author hasn't been serialized yet? Obviously, Author should be serialized before Book, so we can add a dependency as follows:


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()
6

This ensures that the Person object is serialized before the Book object, likewise, any 1 object that references Book will be serialized only after both Person and Book objects are serialized

Inherited model

Don't worry about this if you're using abstract inheritance; If you are using multi-table inheritance, note that all base classes must be serialized, such as:


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()
7

If you serialize only the Restaurant model, you will only get one serves_hot_dog attribute. The base class attributes will be ignored, and you must serialize all inherited models at the same time, as follows:


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

Related articles: