zoukankan      html  css  js  c++  java
  • Django REST framework 第一章 Serialization

    此章节将会介绍多种构成REST framework的重要模块,在每个部分如何一起配合上提供一个综合的全方面的了解。

    准备

    同样的创建一个新项目,创建一个新的app,将rest_framework跟新建的app加入到INSTALLED_APPS

    创建工作model

    打开新建的app的models.py文件

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

    同步到数据库:

    >>> python3 manage.py makemigrations
    >>> python3 manage.py migrate

    创建Serializer类

    在开始web API时,首先需要做的就是提供一种序列化和反序列化的实例到表现的方式,例如json.

    我们做这一步在申明serializers的时候跟Django的forms很相似。

    创建一个serializers.py在app内

    from rest_framework import serializers
    from app01.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):
            """
            用传入的验证过的数据validated_data,创建并返回新的Snippet实例
            """
            return Snippet.objects.create(**validated_data)
    
        def update(self, instance, validated_data):
            """
            用传入的验证过的数据validated_data,更新并返回Snippet实例
            """
            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

    第一部分关于serializer类定义了序列化和反序列化字段。create和update方法定义了当调用serializer.save()的时候全面的实例是如何被创建或者更改的。serializer 类跟Django的form类很相似,包含了相似的验证在不同的字段上,比如requeired、max_length、default.

    字段表示也可以控制serializer应该如何显示在某一种场景下,比如render htm. style={'base_template': 'textarea.html'}等同于在form里面使用widget=widgets.Textarea. 这在控制可浏览的API如何显示方面很有用. 后面会再见讲到这些。

    Serializers方面

    在更进一步之前,先来熟悉一下Serializer类。打开Django的模拟环境shell.

    shuais-MBP:TestApp dandyzhang$ python3 manage.py shell
    Python 3.6.5 (v3.6.5:f59c0932b4, Mar 28 2018, 03:03:55) 
    [GCC 4.2.1 (Apple Inc. build 5666) (dot 3)] on darwin
    Type "help", "copyright", "credits" or "license" for more information.
    (InteractiveConsole)
    >>> 

    首先到导入一些模块,创建一些实例

    >>> from app01.models import Snippet
    >>> from app01.serializers import SnippetSerializer
    >>> from rest_framework.renderers import JSONRenderer
    >>> from rest_framework.parsers import JSONParser
    >>> snippet = Snippet(code='foo="bar"
    ')
    >>> snippet.save()
    >>> snippet = Snippet(code='print("hello, world")
    ')
    >>> snippet.save()

    现在就有一些snippet实例测试了。

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

    此时,转化这个model实例到python本身的数据类型。在结束序列化之前转换成json.

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

    反序列化很类似。首先将流解析为Python本地数据类型。

    >>> from django.utils.six import BytesIO
    >>> stream = BytesIO(content)
    >>> data = JSONParser().parse(stream)
    >>> data
    {'id': 2, 'title': '', 'code': 'print("hello, world")
    ', 'linenos': False, 'language': 'python', 'style': 'friendly'}

    然后,将这些原生数据类型还原为完全填充的对象实例。

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

    注意API跟forms的使用非常的相似。它们之间的相似度在使用serializer来写views时会更加突出。

    我们也可以序列化querysets来提到model的实例,如果想要这么做的话,添加一个many=True的标记在serializer.

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

    使用ModelSerializers

    SnippetSerializer类正在复制包含在Snippet模型中的大量信息。我们可以让代码更简洁一点。而同样地,Django提供了Form和ModelForm类,REST framework包含SerializerModelSerializer类。

    ModelSerializer来重构一下serializer. 打开serializers.py文件,用下面的类代替SnippetSerializer.

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

    serializers包含的一个很好的方面是,你可以检查所有的包含在serializer实例内的字段,通过打印它的表现。

    打开Django的shell

    >>> from app01.serializers import SnippetSerializer
    >>> serializer = SnippetSerializer()
    >>> print(repr(serializer))

    值得记住的重要点是ModelSerializer类不做任何特别神奇的事情,它们只是创建序列化类的快捷方式:

    a、一个自动确定的字段

    b、create()update()方法简单的默认实现

    使用Serializer撰写常规Django视图

    一起看一下如何通过用新的Serializer类写一些API视图,从现在开始,不会用任何REST framework的其他的属性,只是像写普通的Django视图一样写这些视图。

    编辑app01的视图views.py

    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 app01.models import Snippet
    from app01.serializers import SnippetSerializer

    根目录API是一个视图,支持列出所有现存的snippets或者创建新的snippet.

    @csrf_exempt
    def snippet_list(request):
        """
        List all code snippets, or create a new snippet.
        """
        if request.method == 'GET':
            snippets = Snippet.objects.all()
            serializer = SnippetSerializer(snippets, many=True)  # queryset
            return JsonResponse(serializer.data, safe=False)  # safe为True的时候只能传入字典的数据,不然会报错,而False可以传入任何可以被转换成JSON的对象
    
        elif request.method == 'POST':
            data = JSONParser().parse(request)  # request对象的反序列化成字典
            serializer = SnippetSerializer(data=data)  # 字典传入
            if serializer.is_valid():
                serializer.save()
                return JsonResponse(serializer.data, status=201)
            return JsonResponse(serializer.errors, status=400)

    我们还需要一个视图对应一个独立的snippet,可以用来获取、更新或者删除snippet

    @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)  # 单条数据对象直接丢进去,多条则是queryset类型,需要many=True
            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)  # 单个对象的data是一个字典  
            return JsonResponse(serializer.errors, status=400)
    
        elif request.method == 'DELETE':
            snippet.delete()
            return HttpResponse(status=204)

    最后修改urls

    from app01 import views
    from django.urls import path, include
    
    urlpatterns = [
        path('snippets/', views.snippet_list),
        path('snippets/<int:pk>/', views.snippet_detail),
    ]

    安装httpie:

    pip3 install httpie

    输入:

    http http://127.0.0.1:8000/app01/snippets/

    同样的也可以使用浏览器输入url得到同样的json数据

    简单整理下,此篇blog的介绍流程

    1、基础-创建model,同步数据库

    2、创建serializers.py文件,创建serializers类,类似form验证表单的创建,继承form或者modelform,这里则继承Serializer

    或者ModelSerializer,两者具有极高的相似度

    3、通过shell模拟django环境,尝试一下serializer的用法。

    4、FBV的方式实现了API的展示,返回Json序列化数据

  • 相关阅读:
    head命令
    less命令
    解决get方法传递URL参数中文乱码问题
    The method convert(String) of type DateConverter must override a superclass method
    Tomcat Can't load AMD 64-bit .dll on a IA 32
    聚合函数查询 group by having
    string[] 清理重复+反转显示
    C# GetValueList 获得字符串中开始和结束字符串中间得值列表
    C# GetValue 正则获取开始结束代码
    string [] 去除重复字符两个方法
  • 原文地址:https://www.cnblogs.com/wuzdandz/p/9455575.html
Copyright © 2011-2022 走看看