Serialization of django-rest-framework

Posted by wing328 on Sat, 18 May 2019 22:17:46 +0200

Foreword: Yesterday I learned about rest-framework serialization, so I wrote a blog record. Official website: http://www.django-rest-framework.org/tutorial/1-serialization/#working-with-serializers.

 

Front-end and back-end separation: Front-end development and back-end development are separated. The implementation of this scheme is to use API, which simply means that the programmer provides the programming interface to be invoked by other people, after which they will return the data for their use. There are many types of APIs, but now the more mainstream and practical one is the RESTful API.

 

I. start

Okay, we're ready to get coding. To get started, let's create a new project to work with. First, create a Django project.

cd ~
django-admin.py startproject tutorial
cd tutorial

Once that's done we can create an app that we'll use to create a simple Web API. Then create an APP

python manage.py startapp snippets

We'll need to add our new snippets app and the rest_framework app to INSTALLED_APPS. Let's edit the tutorial/settings.py file: Modify the global configuration file.

INSTALLED_APPS = (
    ...
    'rest_framework',
    'snippets.apps.SnippetsConfig',
)

Please note that if you're using Django <1.9, you need to replace snippets.apps.SnippetsConfig with snippets.

If you use Django < 1.9, you need to replace snippets. apps. Snippets Config with snippets.

 

2. Creating Model Classes

For the purposes of this tutorial we're going to start by creating a simple Snippet model that is used to store code snippets (fragments). Go ahead and edit the snippets/models.py file.

We will first create a simple Snippet model for storing code snippets and edit the snippets/models.py file.

from django.db import models

# Create your models here.

# pygments Code highlighting can be achieved Official website:http://pygments.org/
from pygments.lexers import get_all_lexers  # lexers:Lexical analyzer
from pygments.styles import get_all_styles


LEXERS = [item for item in get_all_lexers() if item[1]]
LANGUAGE_CHOICES = sorted([(item[1][0], item[0]) for item in LEXERS])
STYLE_CHOICES = sorted((item, item) for item in get_all_styles())


class Snippet(models.Model):
    created = models.DateTimeField(auto_now_add=True)  # Automatically add creation time
    title = models.CharField(max_length=100, blank=True, default='')
    code = models.TextField()
    linenos = models.BooleanField(default=False)
    language = models.CharField(choices=LANGUAGE_CHOICES, default='python', max_length=100)
    style = models.CharField(choices=STYLE_CHOICES, default='friendly', max_length=100)

    class Meta:
        ordering = ('created',)  # Sort by creation time

Initialize and synchronize to the database:

python manage.py makemigrations snippets
python manage.py migrate

  

Creating serialized classes

The first thing we need to get started on our Web API is to provide a way of serializing and deserializing the snippet instances into representations such a s json. We can do this by declaring (declaration) serializers that work very similar to Django's forms.

First of all, I want to ask you, usually, the front end calls the back-end API, the API must return data to the front end, then what type of data is returned?

At present, JSON is widely used in the mainstream, and maybe a few of them are still using XML.

So when we study django-rest-framework, are there any ways to automatically convert data instance information into JSON? It can also convert JSON data passed from the front end to the back end into python data type (dict/list/set...). Of course, serializers can be implemented. First you have to declare (introduce) serializers. See the following example:

# use Web API The first thing is to provide a way to serialize and deserialize code snippet instances into representations json. 
# We can do this by declaring Django Forms are very similar to serializers to do this. stay snippets Create a file in the named directory.
# serializers.py And add the following

from rest_framework import serializers
from snippets.models import Snippet, LANGUAGE_CHOICES, STYLE_CHOICES


class SnippetSerializer(serializers.Serializer):
    # The first part of the serializer class defines serialization/Deserialized fields.
    id = serializers.IntegerField(read_only=True)
    title = serializers.CharField(required=False, allow_blank=True, max_length=100)
    # Using field flags to control serializer rendering to HTML Display template for page
    code = serializers.CharField(style={'base_template': 'textarea.html'})
    linenos = serializers.BooleanField(required=False)
    language = serializers.ChoiceField(choices=LANGUAGE_CHOICES, default='python')
    style = serializers.ChoiceField(choices=STYLE_CHOICES, default='friendly')

    def create(self, validated_data):
        """
        The create() and update() methods define how fully fledged instances are created
        or modified when calling serializer.save()
        Create and return a new `Snippet` instance, given the validated data.
        //Given validated data, create and return a new Snippet instance
        """
        return Snippet.objects.create(**validated_data)

    def update(self, instance, validated_data):
        """
        Update and return an existing `Snippet` instance, given the validated data.
        //Given the validated data, update and return an existing Snippet instance
        """
        instance.title = validated_data.get('title', instance.title)
        instance.code = validated_data.get('code', instance.code)
        instance.linenos = validated_data.get('linenos', instance.linenos)
        instance.language = validated_data.get('language', instance.language)
        instance.style = validated_data.get('style', instance.style)
        instance.save()  # To update
        return instance

The first part of the serializer class defines the serialized/deserialized fields. The create() and update() methods define how instances are created and updated, respectively.

For the following line of code:

code = serializers.CharField(style={'base_template': 'textarea.html'})

What you need to know is that its function is to control the display template when the serializer renders to HTML pages. As for why, it's particularly useful for controlling how to display browsable API s, as you'll see in later articles.

You can actually save yourself time by using Model Serializer, as we'll see later, and then look at the specific role of serializers.

 

IV. Using serializers

Before we get any further information, we'll be familiar with using our new Serializer class. We enter the Django shell:

python manage.py shell

The next step is to create and save Snippet model instances as you learned about Django's ORM:

from snippets.models import Snippet
from snippets.serializers import SnippetSerializer
from rest_framework.renderers import JSONRenderer
from rest_framework.parsers import JSONParser

snippet = Snippet(code='foo = "bar"\n')
snippet.save()

snippet = Snippet(code='print "hello, world"\n')
snippet.save()

Looking at the database at this time, you will find that there are two more rows of data in the related tables, which is the data we just created:

We now have several fragment instances to play with. Let's look at one of these examples of serialization

serializer = SnippetSerializer(snippet)
serializer.data
# {'id': 2, 'title': u'', 'code': u'print "hello, world"\n', 'linenos': False, 'language': u'python', 'style': u'friendly'}

At this point we've translated the model instance into Python native datatypes. 

As you can see from the above code, we have converted the instance information of the model into python's native data type, the dictionary.

To finalize the serialization process we render the data into json.

To complete the serialization process, we converted the data into json.

content = JSONRenderer().render(serializer.data)
content
# '{"id": 2, "title": "", "code": "print \\"hello, world\\"\\n", "linenos": false, "language": "python", "style": "friendly"}'

json format has emerged here, that is to say, the data in json format is to be displayed on a certain URL. It may be felt that when we visit a certain URL, we will return the above data for you to use. This actually completes a serialization process, and we can also see the function prototype of the client.

Serialization is to return the data in json format to the client to view and use the data. When the client needs to modify, add or delete the data, it is necessary to reverse the process, that is, deserialize the data in json format submitted by the client.

Deserialization is similar. First, we parse a stream into Python native data types...

from django.utils.six import BytesIO

stream = BytesIO(content)
data = JSONParser().parse(stream)

...then we restore those native datatypes into a fully populated object instance.

First check whether the data is incorrect, then save the data:

serializer = SnippetSerializer(data=data)
serializer.is_valid()
# True
serializer.validated_data
# OrderedDict([('title', ''), ('code', 'print "hello, world"\n'), ('linenos', False), ('language', 'python'), ('style', 'friendly')])
serializer.save()
# <Snippet: Snippet object>

At this time, another piece of data is added to the database:

We can also serialize querysets instead of model instances. To do so we simply add a many=True flag to the serializer arguments.

We can also serialize query sets rather than model instances. To do this, we just need to add a flag many=True for the serializer parameter

serializer = SnippetSerializer(Snippet.objects.all(), many=True)
serializer.data
# [OrderedDict([('id', 1), ('title', u''), ('code', u'foo = "bar"\n'), ('linenos', False), ('language', 'python'), ('style', 'friendly')]), OrderedDict([('id', 2), ('title', u''), ('code', u'print "hello, world"\n'), ('linenos', False), ('language', 'python'), ('style', 'friendly')]), OrderedDict([('id', 3), ('title', u''), ('code', u'print "hello, world"'), ('linenos', False), ('language', 'python'), ('style', 'friendly')])]

 

 

5. Using ModelSerializers

In the SnippetSerializer class above, we inherited the serializers.Serializer class. You can see that many of the code in the SnippetSerializer class is actually similar to the Snippet model in models.py, so here we can improve it. Just as Form and ModelForm classes are provided in Django, django-rest-framework provides us with Serializer and ModelSerializer classes. Use it to make our code much simpler, modify serializers.py:

# Our SnippetSerializer class is replicating a lot of information that's also contained in the Snippet model.
# It would be nice if we could keep our code a bit more concise.
class SnippetSerializer(serializers.ModelSerializer):
    class Meta:
        model = Snippet
        fields = ('id', 'title', 'code', 'linenos', 'language', 'style')

One nice property that serializers have is that you can inspect all the fields in a serializer instance, by printing its representation. Open the Django shell with Python management.py shell, then try the following:

A good property of a serializer is that it can print its representation to check all fields in a serializer instance. Open the Django shell, Python management.py shell, and then try the following:

from snippets.serializers import SnippetSerializer
serializer = SnippetSerializer()
print(repr(serializer))
# SnippetSerializer():
#    id = IntegerField(label='ID', read_only=True)
#    title = CharField(allow_blank=True, max_length=100, required=False)
#    code = CharField(style={'base_template': 'textarea.html'})
#    linenos = BooleanField(required=False)
#    language = ChoiceField(choices=[('Clipper', 'FoxPro'), ('Cucumber', 'Gherkin'), ('RobotFramework', 'RobotFramework'), ('abap', 'ABAP'), ('ada', 'Ada')...
#    style = ChoiceField(choices=[('autumn', 'autumn'), ('borland', 'borland'), ('bw', 'bw'), ('colorful', 'colorful')...

Remember, the ModelSerializer classes don't do anything particularly magical, they're just shortcuts to creating serializer classes:

  • A set of automatically determined fields.
  • Simple default implementations of create() and update() methods.

 

6. Write regular Django views

The next step is to write some API views using our new Serializer class. Edit snippets/views.py:

from django.shortcuts import render

# Create your views here.
from django.http import HttpResponse, JsonResponse
from django.views.decorators.csrf import csrf_exempt
from rest_framework.renderers import JSONRenderer
from rest_framework.parsers import JSONParser
from snippets.models import Snippet
from snippets.serializers import SnippetSerializer


@csrf_exempt
def snippet_list(request):
    """
    because we want to be able to POST to this view from clients
    that won't have a CSRF token we need to mark the view as csrf_exempt
    List all code snippets, or create a new snippet.
    """
    if request.method == "GET":
        snippets = Snippet.objects.all()
        serializer = SnippetSerializer(snippets, many=True)
        return JsonResponse(serializer.data, safe=False)

    elif request.method == "POST":
        data = JSONParser().parse(request)
        serializer = SnippetSerializer(data=data)
        if serializer.is_valid():
            serializer.save()
            return JsonResponse(serializer.data, status=201)
        return JsonResponse(serializer.errors, status=400)


@csrf_exempt
def snippet_detail(request, pk):
    """
    Retrieve, update or delete a code snippet.
    """
    try:
        snippet = Snippet.objects.get(pk=pk)
    except Snippet.DoesNotExist:
        return HttpResponse(status=404)

    if request.method == "GET":
        serializer = SnippetSerializer(snippet)
        return JsonResponse(serializer.data)

    elif request.method == "PUT":
        data = JSONParser().parse(request)
        serializer = SnippetSerializer(snippet, data=data)
        if serializer.is_valid():
            serializer.save()
            return JsonResponse(serializer.data)
        return JsonResponse(serializer.errors, status=400)

    elif request.method == 'DELETE':
        snippet.delete()
        return HttpResponse(status=204)

The above code is well understood and defines different backstage operations for different http actions, which also embodies the concept of restful API.

because we want to be able to POST to this view from clients that won't have a CSRF token we need to mark the view as csrf_exempt.

Because we want to be able to POST this view from clients without CSRF tokens, we need to add a decorator csrf_exempt to the view.

 

In order for the view function to be invoked, of course, you need to design a url, where the processing is the same as when developing Django. First create snippets/urls.py

from django.conf.urls import url
from snippets import views

urlpatterns = [
    url(r'^snippets/$', views.snippet_list),
    url(r'^snippets/(?P<pk>[0-9]+)/$', views.snippet_detail),
]

We also need to wire up the root urlconf, in the tutorial/urls.py file, to include our snippet app's URLs.

from django.conf.urls import url, include

urlpatterns = [
    url(r'^', include('snippets.urls')),
]

  

VII. Testing API

After completing the above tasks, you can start testing, exit shell mode and start the server. According to the url we just designed, you need to install the httpie module first.

pip install httpie

Then access it in the command line window. The effect is as follows:

Data with the specified id can also be accessed:

Of course, you can also view it directly in the browser and enter the URL directly.

Topics: Python Django JSON shell