Serialization and request and return in Python DjangoREST framework

Source: Internet
Author: User
Tags wrappers install django pip install django virtualenv
This article mainly introduces serialization, request and return in Python's DjangoREST framework. It is very convenient and powerful to use DjangoREST to implement RESTfulwebservice. For more information, see Serialization
1. Set a new environment

Before we start, we first use virtualenv to create a new virtual environment, so that our configuration is completely separated from other project configurations.

$mkdir ~/env$virtualenv ~/env/tutorial$source ~/env/tutorial/bin/avtivate

Now we are in a virtual environment and start to install our dependency packages.

$ Pip install django $ pip install djangorestframework $ pip install pygments // use this package for code highlighting

Run deactivate when you need to exit the virtual environment. For more information, irtualenv document

2. Start

The environment is ready. Let's start creating our project.

$ cd ~$ django-admin.py startproject tutorial$ cd tutorial

After the project is created, create a simple app.

$python manage.py startapp snippets

We use sqlite3 to run our project tutorial, edit tutorial/settings. py, change the default engine of the database to sqlite3, and change the NAME of the database to tmp. db.

DATABASES = {  'default': {    'ENGINE': 'django.db.backends.sqlite3',    'NAME': 'tmp.db',    'USER': '',    'PASSWORD': '',    'HOST': '',    'PORT': '',  }}

Change INSTALLD_APPS in the settings. py file and add our APP snippets and rest_framework.

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

In tutorial/urls. py, include the snippets app url

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

3. Create a Model
Here we create a simple nippets model to store code snippets.

from django.db import modelsfrom pygments.lexers import get_all_lexersfrom pygments.styles import get_all_stylesLEXERS = [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, 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',)


When the model is completed, remember to sync the database

python manage.py syncdb

4. Create a serialization class

We need to use our web api. The first thing we need to do is serialization and deserialization, so that the snippets instance can be converted into declarative content, such as json. we declare a serializer that can work effectively. In the snippets directory, the Form of the serializer is similar to that of django. Create a serializers. py and copy the following content to the file.

from django.forms import widgetsfrom rest_framework import serializersfrom snippets.models import Snippetclass SnippetSerializer(serializers.Serializer):  pk = serializers.Field() # Note: `Field` is an untyped read-only field.  title = serializers.CharField(required=False,                 max_length=100)  code = serializers.CharField(widget=widgets.Textarea,                 max_length=100000)  linenos = serializers.BooleanField(required=False)  language = serializers.ChoiceField(choices=models.LANGUAGE_CHOICES,                    default='python')  style = serializers.ChoiceField(choices=models.STYLE_CHOICES,                  default='friendly')  def restore_object(self, attrs, instance=None):    """    Create or update a new snippet instance.    """    if instance:      # Update existing instance      instance.title = attrs['title']      instance.code = attrs['code']      instance.linenos = attrs['linenos']      instance.language = attrs['language']      instance.style = attrs['style']      return instance    # Create new instance    return Snippet(**attrs)

The previous section of the serialization class defines the types to be serialized and deserialized. The restore_object method defines how to generate correct object instances through deserialization of data.

We can also use ModelSerializer to quickly generate the data, and we will save on how to use it later.
5. Use Serializers

Before using our defined SnippetsSerializers, we should familiarize ourselves with Snippets.

 $python manage.py shell

After entering the shell terminal, enter the following code:

from snippets.models import Snippetfrom snippets.serializers import SnippetSerializerfrom rest_framework.renderers import JSONRendererfrom rest_framework.parsers import JSONParsersnippet = Snippet(code='print "hello, world"\n')snippet.save()


We now have an Snippets instance, And now we serialize it as follows:

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

In this case, the instance is converted to the python native data type. Next we will convert the data into json format to complete serialization:

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

Deserialization is also very easy. First, we need to convert an input stream (content) to the native data type of python.

import StringIOstream = StringIO.StringIO(content)data = JSONParser().parse(stream)

Then we convert the native data type into an object instance.

serializer = SnippetSerializer(data=data)serializer.is_valid()# Trueserializer.object# 
 

Note that these APIs are similar to django forms. These similarities will become more obvious when we talk about using serializers in the view.
6. Use ModelSerializers

SnippetSerializer uses the same code as Snippet. If we can remove this part of code, it will look more concise.

Similar to the Form class and ModelForm class provided by django, Rest Framework also contains the Serializer class and ModelSerializer class.

Open snippets/serializers. py and modify the SnippetSerializer class:

class SnippetSerializer(serializers.ModelSerializer):  class Meta:    model = Snippet    fields = ('id', 'title', 'code', 'linenos', 'language', 'style')

7. Compile Django View through Serializer

Let's take a look at how to compile django view through the serializer class we created. Here, we do not use other features of the rest framework, but only write the normal django view.

We create an HttpResponse subclass so that we can convert any data we return to json.

Add the following content to snippet/views. py:

from django.http import HttpResponsefrom django.views.decorators.csrf import csrf_exemptfrom rest_framework.renderers import JSONRendererfrom rest_framework.parsers import JSONParserfrom snippets.models import Snippetfrom snippets.serializers import SnippetSerializerclass JSONResponse(HttpResponse):  """  An HttpResponse that renders it's content into JSON.  """  def __init__(self, data, **kwargs):    content = JSONRenderer().render(data)    kwargs['content_type'] = 'application/json'    super(JSONResponse, self).__init__(content, **kwargs)

The purpose of our API is to list all the content of Snippet through view, or to create a new snippet

@csrf_exemptdef snippet_list(request):  """  List all code snippets, or create a new snippet.  """  if request.method == 'GET':    snippets = Snippet.objects.all()    serializer = SnippetSerializer(snippets)    return JSONResponse(serializer.data)  elif request.method == 'POST':    data = JSONParser().parse(request)    serializer = SnippetSerializer(data=data)    if serializer.is_valid():      serializer.save()      return JSONResponse(serializer.data, status=201)    else:      return JSONResponse(serializer.errors, status=400)

Note: because we need to post a request to the view through the client, we need to mark the view as csrf_exempt to indicate that it is not a CSRF event.
Note that 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. this isn't something that you 'd normally want to do, and REST framework views actually use more sensible behavior than this, but it'll do for our purposes right now.
We also need a view to operate on a separate Snippet so that this object can be updated/deleted.

@csrf_exemptdef 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)    else:      return JSONResponse(serializer.errors, status=400)  elif request.method == 'DELETE':    snippet.delete()    return HttpResponse(status=204)


Save views. py, create urls. py under the Snippets directory, and add the following content:

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

Note that some edge events are not handled, and the server may throw a 500 exception.
8. Test

Now we start the server to test our Snippet.

Run the command in the python mange. py shell terminal (if the previous entry is not exited)

 >>quit()

Run the following command to run our server:

 python manage.py runserverValidating models...0 errors foundDjango version 1.4.3, using settings 'tutorial.settings'Development server is running at http://127.0.0.1:8000/Quit the server with CONTROL-C.

Create a new terminal to test our server

Serialization:

url http://127.0.0.1:8000/snippets/[{"id": 1, "title": "", "code": "print \"hello, world\"\n", "linenos": false, "language": "python", "style": "friendly"}] url http://127.0.0.1:8000/snippets/1/{"id": 1, "title": "", "code": "print \"hello, world\"\n", "linenos": false, "language": "python", "style": "friendly"}



Request and Response
1. Request Object -- Request Object

Rest framework introduces a Request object inherited from HttpRequest, which provides more flexible resolution of requests. The core part of the request object is the request. data Attribute, which is similar to request. post. However, when using WEB APIs, request. data is more effective.

(1) request. POST # Only handles form data. Only works for 'post' method.
(2) request. DATA # Handles arbitrary data. Works any HTTP request with content.
2. Response Object -- Response Object
Rest framework introduces a Response object that inherits from the TemplateResponse object. It obtains the unrendered content and determines whether the correct content type is returned to the client through content negotiation.

Return Response (data) # Renders to content type as requested by the client.
3. Status Codes
Using Digital HTTP status codes in views will make your code unreadable and cannot easily detect errors in the code. The rest framework provides a clearer identifier for each status code. For example, HTTP_400_BAD_REQUEST. It is better to use such identifiers throughout views than to use numbers.
4. encapsulate API views

When writing API views, REST Framework provides two types of wrappers:

1). @ api_viwe modifier -- function level

2). APIView class-class level

The two Wrappers provide many functions, such as ensuring that the Request instance can be received in the view and adding content to the Response so that the content negotiation mechanism can be executed by the content negotiation.

The interceptor also provides some behaviors, such as returning the 405 Methord Not Allowed response when appropriate, and handling any ParseError exceptions when accessing multi-type input request. DATA.
5. Summary

We started to use these new components to write some views.

We do not need the JESONResponse class (created in the previous article) to delete it. After deletion, we start to reconstruct our view slightly.

from rest_framework import statusfrom rest_framework.decorators import api_viewfrom rest_framework.response import Responsefrom snippets.models import Snippetfrom snippets.serializers import SnippetSerializer@api_view(['GET', 'POST'])def snippet_list(request):  """  List all snippets, or create a new snippet.  """  if request.method == 'GET':    snippets = Snippet.objects.all()    serializer = SnippetSerializer(snippets)    return Response(serializer.data)  elif request.method == 'POST':    serializer = SnippetSerializer(data=request.DATA)    if serializer.is_valid():      serializer.save()      return Response(serializer.data, status=status.HTTP_201_CREATED)    else:      return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

The above code is an improvement to our previous code. It looks more concise and similar to django's forms api form. We also use status codes to make the returned values clearer.
The following is a view update for a single snippet operation:

@api_view(['GET', 'PUT', 'DELETE'])def snippet_detail(request, pk):  """  Retrieve, update or delete a snippet instance.  """         try:    snippet = Snippet.objects.get(pk=pk)  except Snippet.DoesNotExist:    return Response(status=status.HTTP_404_NOT_FOUND)  if request.method == 'GET':    serializer = SnippetSerializer(snippet)    return Response(serializer.data)  elif request.method == 'PUT':    serializer = SnippetSerializer(snippet, data=request.DATA)    if serializer.is_valid():      serializer.save()      return Response(serializer.data)    else:      return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)  elif request.method == 'DELETE':    snippet.delete()    return Response(status=status.HTTP_204_NO_CONTENT)

Note that we do not explicitly require either requests or responses to provide the content type. Request. DATA can be used to process input json requests, yaml, and other formats. Similarly, when response Returns data, REST Framework returns the correct content type to the client.

6. Add an optional format suffix to URLs.

With the fact that no content type needs to be specified in response, we add a format suffix on the API side. The format suffix can be used to explicitly indicate that a specific format is used, which means that our API can process urllike http://example.com/api/items/4.json.

Add the format parameter in views, for example:

def snippet_list(request, format=None):anddef snippet_detail(request, pk, format=None):

Now, slightly modify the urls. py file and add a format suffix pattterns (format_suffix_patterns) to the existing URLs file ):

from django.conf.urls import patterns, urlfrom rest_framework.urlpatterns import format_suffix_patternsurlpatterns = patterns('snippets.views',  url(r'^snippets/$', 'snippet_list'),  url(r'^snippets/(?P
 
  [0-9]+)$', 'snippet_detail'),)urlpatterns = format_suffix_patterns(urlpatterns)
 

These additional url patterns are not required.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.