Serialization -- serialization
Preface
This tutorial will introduce the creation of a simple web API. Throughout the learning process, the various components of the REST framework will be introduced one by one to give you a comprehensive understanding of all things if combined.
This tutorial will be quite detailed, so before you start, you should go for some biscuits and drink some of your favorite drinks. If you just want a quick overview, you should check it out Quickstart.
Note: The code for this tutorial is available in GitHub tomchristie/rest-framework-tutorial Found in. test This is a test link.
Create a new virtual environment
Use virtualenv Create a virtual environment.
virtualenv env source env/bin/activate
Then we install the required packages in the virtual environment we created.
pip install django pip install djangorestframework pip install pygments #Use it to highlight code
Note: Use deactivate to exit the virtual environment at any time. For more information, please check Virtualenv documentation
Get ready
We're starting to write code here. Let's create a project first.
cd ~ django-admin.py startproject tutorial cd tutorial
Next, we create an app.
python manage.py startapp snippets
We need to add snippets and rest_framework to INSTALLED_APPS in the tutorial/settings.py file:
INSTALLED_APPS = { ... 'rest_framework', 'snippets.apps.SnippetsConfig', }
Note: If you use Django < 1.9, you need to replace snippets. apps. Snippets Config with snippets.
We can go on.
Create model
In this tutorial, we will create a simple model that will be used to store code snippets.
Edit the snippets/models.py file.
Note: It's a good habit to write notes.
from django.db import models from pygments.lexers import get_all_lexers 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) title = models.CharField(max_length=100,blank=True,defalut='') 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')
Execute commands to create data tables:
python manage.py makemigrations snippets python manage.py migrate
Create Serializer
First, we need to provide a serialized and deserialized presentation of our web API, such as json.
We can declare a serializers similar to django's forms. Create a Serializers.py file.
from rest_framework import serializers from snippets.models import Snippet, LANGUAGE_CHOICES, STYLE_CHOICES class SnippetSerializer(serializers.Serializer): id = serializers.IntegerField(read_only=True) title = serializers.CharField(required=False,allow_blank=True,max_length=100) 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): return Snippet.objects.create(**validated_data) def update(self,instance,validated_data): 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() return instance
The first step in serializer is to define the fields that need to be serialized / deserialized. The create() and update() methods define if serializer.save() is created and updated.
The serializer class is very similar to Django's Form class. Includes validation tags for various fields, such as required,max_length,default.
Field tags can also control how serializer s are displayed in certain environments, such as rendering as HTML.
The previous {base_template':'textarea. html'} tag corresponds to widget=widgets.Textarea` in django Form.
In fact, we can save more time by using the ModelSerializer class, but for now, we still display the fields that define us.
Start-up
Before we go any further, we will familiarize ourselves with serializer through the django shell.
python manage.py shell
We need to import what we need and then create two snippet s.
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()
Let's take a look at one of the examples we created:
serializer = SnippetSerializer(snippet) serializer.data # {'id': 2, 'title': u'', 'code': u'print "hello, world"\n', 'linenos': False, 'language': u'python', 'style': u'friendly'}
Here, we translate the model instance as python's native data type, and in order to complete serialization, we present the data as JSON.
content = JSONRenderer().render(serializer.data) content # '{"id": 2, "title": "", "code": "print \\"hello, world\\"\\n", "linenos": false, "language": "python", "style": "friendly"}'
Deserialization is similar. First, we parse a stream as a Python native data type.
from django.utils.six import BytesIO data = JSONParser().parse(stream)
Then we restore the native data type to a fully populated object instance.
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>
Note: This is similar to forms. When we write views using serializer, it will look more similar.
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')])]
Using Model Serializers
Our SnippetSerializer class copies a lot of snippet stuff. We want our code to be clean and tidy.
Similar to django, which has Form and ModelForm classes, the REST framework also contains Serializer and ModelSerializer classes.
Let's use ModelSerializer to refactor our serializer class. Open snippets/serializers.py and replace the SinppetSerializer class:
class SnippetSerializer(serializers.ModelSerizer): class Meta: model = Snippet fields = ('id','title','code','linenos','language','style')
Serializer has a nice property that allows you to view all fields of a serializer instance by printing. Open the Django shell (python management. py shell):
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')...
Note: Model Serializer doesn't do anything magical, it just creates serializer faster
- Automatically determine field settings
- Simple default create() and update() methods
Write a regular django views using Serializer
Let's use our new serializer to write some API views. Here, instead of using any other features of the REST framework, we write a regular django views.
Write snippets/views.py file:
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
Our API will support viewing all data and creating a new snippet
@csrf_exempt def snippet_list(request): """ //Display 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)
Note: Because we want post to fail CSRF token validation, we use csrf_exempt. In fact, this is not something you often do, and REST framework views will do it more wisely. But now, he can use it.
We also need this view to be retrievable, updated, and deleted.
@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)
Finally, we need to create URLs in the snippets/url s.py file
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 introduce our urls.py(tutorial/urls.py) to urls.py.
from django.conf.urls import url, include urlpatterns = [ url(r'^', include('snippets.urls')), ]
Note: There are some problems with our view that have not been properly handled, such as the incorrect json format sent or the method invoked that the view does not have, then we will return a 500 "server error" message.