restful序列化应用

Posted xujunkai

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了restful序列化应用相关的知识,希望对你有一定的参考价值。

restful之序列化

1.前序

  • 简单表结构:

    class Publisher(models.Model):
        name = models.CharField(max_length=32)
        def __str__(self):
            return self.name
    
    class Author(models.Model):
        author_name = models.CharField(max_length=22)
        def __str__(self):
            return self.author_name
    
    class Book(models.Model):
        title = models.CharField(max_length=32,verbose_name="图书名字")
        CHOICE = ((1,"PYTHON"),(2,"VUE"),(3,"GO"),(4,"JAVA"))
        category = models.IntegerField(choices=CHOICE)
        put_time = models.DateField()
        publisher = models.ForeignKey(to="Publisher")
        authors = models.ManyToManyField(to="Author")
        class Meta:
            # db_table 指定了表名
            db_table= "book_list"
            # verbose_name_plural表示复数形式的显示;中文的单数和复数一般不作区别
            verbose_name_plural = db_table
    
    
  • url

    urlpatterns = [
        url(r'^books/', views.BookView.as_view(),name="book"),
        url(r'^publisher/(?P<pk>d+)',views.PublisherView.as_view(),name='pub')
    ]
  • 视图

    class BookView(APIView):
        def get(self,request,*args,**kwargs):
            all_obj = models.Book.objects.all()
            #添加hypermedialink 生成链接 必须加context,否则报错
            ser_book = BookSerializer(instance=all_obj,many=True,context={"request":request})
            return Response(ser_book.data)
    
    class PublisherView(APIView):
        def get(self,request,pk,*args,**kwargs):
            print(pk)
            return Response({"error":400})

2.get请求

#!/usr/bin/env python
# -*- coding:utf-8 -*-
from rest_framework import serializers
from api import models

class AuthorSerializer(serializers.ModelSerializer):
    class Meta:
        model = models.Author
        fields = '__all__'

class MyField(serializers.CharField):
    """自定义序列化"""
    def to_representation(self, value):
        new_value = '《{}》'.format(value)
        return new_value


CHOICES = ((1, "Python"), (2, "Linux"), (3, "go"))
class BookSerializer(serializers.Serializer):
    id = serializers.IntegerField(read_only=True)
    # 一对多关系,可以用source= 外键名.另一张表字段
    pub_name = serializers.CharField(source="publisher.name")
    title = serializers.CharField(max_length=32)
    #choice字段序列化:读取 通过get_字段_display 可以获取该CHOICE元组第二设置的值
    category = serializers.CharField(max_length=32, source="get_category_display", read_only=True)
    #写入
    post_category = serializers.ChoiceField(choices=CHOICES, write_only=True)
    put_time = serializers.DateField()
    #多对多关系,定义SerializerMethodField,+ 定义get_多对多字段方法
    author = serializers.SerializerMethodField()
    #自定义序列化器,source指向title字段
    new_title = MyField(source="title")
    # 通过hypermedialink 生成publisher的链接:
    # view_name :可以根据它找到路由配置的url
    # 为Book表关联Publisher的id,传入url设置的参数,这里设置的是id.
    pub_url = serializers.HyperlinkedIdentityField(view_name='pub',lookup_field='publisher_id',lookup_url_kwarg="pk")
    #对字段进行处理
    msg = serializers.SerializerMethodField()
    def get_author(self,obj):
        author = obj.authors.all()
        auth = AuthorSerializer(author,many=True)
        return auth.data
    def get_msg(self, instance):
        # self.context为一个字典, a 里面封装如下字段
        """
        {
            '_request': < WSGIRequest: GET '/books/' > ,
            'parsers': [ < rest_framework.parsers.JSONParser object at 0x000002E3B5E5F470 > , < rest_framework.parsers.FormParser object at 0x000002E3B60D3828 > , < rest_framework.parsers.MultiPartParser object at 0x000002E3B60D3860 > ],
            'authenticators': [ < rest_framework.authentication.SessionAuthentication object at 0x000002E3B60D3898 > , < rest_framework.authentication.BasicAuthentication object at 0x000002E3B60D38D0 > ],
            'negotiator': < rest_framework.negotiation.DefaultContentNegotiation object at 0x000002E3B5E5F518 > ,
            'parser_context': {
                'view': < api.views.BookView object at 0x000002E3B59F5AC8 > ,
                'args': (),
                'kwargs': {},
                'request': < rest_framework.request.Request object at 0x000002E3B60D3908 > ,
                'encoding': 'utf-8'
            },
            '_data': < class 'rest_framework.request.Empty' > ,
            '_files': < class 'rest_framework.request.Empty' > ,
            '_full_data': < class 'rest_framework.request.Empty' > ,
            '_content_type': < class 'rest_framework.request.Empty' > ,
            '_stream': < class 'rest_framework.request.Empty' > ,
            'accepted_renderer': < rest_framework.renderers.BrowsableAPIRenderer object at 0x000002E3B60D39E8 > ,
            'accepted_media_type': 'text/html',
            'version': None,
            'versioning_scheme': None,
            '_authenticator': None,
            '_user': < django.contrib.auth.models.AnonymousUser object at 0x000002E3B60D3B00 > ,
            '_auth': None
        }
        """
        a = self.context.get("request")
        print(a.__dict__)
        return "id:%s,title:%s"%(instance.id,instance.title)

3.序列化post请求:

  • 把之前序列化简单一下,因为之前序列化为了多的介绍一下功能:
class BookSerializer(serializers.Serializer):
    id = serializers.IntegerField(read_only=True)
    pub_name = serializers.CharField(source="publisher.name",read_only=True)
    category_name = serializers.CharField(max_length=32, source="get_category_display", read_only=True)
    put_time = serializers.DateField()
    author = serializers.SerializerMethodField(read_only=True)
    title = serializers.CharField(max_length=32)
    #标注write_only表示,写入时候会序列化的字段
    post_category = serializers.ChoiceField(choices=CHOICES, write_only=True,validators=[about_choice,])
    # required=True 表示这个字段不能为空
    post_author = serializers.ListField(write_only=True,required=True)
    post_pub = serializers.IntegerField(write_only=True,required=True)
    def get_author(self,obj):
        author = obj.authors.all()
        auth = AuthorSerializer(author, many=True)
        return auth.data
    # 用于发送post请求 创建数据
    def create(self,validated_date):
        # validated_date为request.data处理后数据
        book_obj = models.Book.objects.create(
            title = validated_date["title"],
            put_time = validated_date['put_time'],
            category = validated_date['post_category'],
            publisher_id = validated_date['post_pub'],
        )
        # 多对多关系 存储
        book_obj.authors.set(validated_date['post_author'])
        return book_obj
  • 当我们发送post请求时候,如下图:

技术图片

  • 那么接下来如下在视图中:
class BookView(APIView):
    def get(self,request,*args,**kwargs):
        ...
    def post(self,request,*args,**kwargs):
        # 首先将请求数据放入序列化器中..
        ser_obj = BookSerializer(data=request.data)
        # 对其进行验证。
        if ser_obj.is_valid():
            #没有错误保存
            ser_obj.save()
            #返回结果
            return Response(ser_obj.data)
        #存在错误,返回错误信息
        return Response(ser_obj.errors)

4.验证:

  • 那么对于提交数据如何验证呢?restframwork提供3种验证方式。

  • 字段内添加validators

def about_choice(value):
    print(type(value))
    if value == 2:
        raise serializers.ValidationError('图书类型不能是2')
    return value
# 字段
post_category = serializers.ChoiceField(choices=CHOICES, write_only=True,validators=[about_choice,])
上面给post_category添加一个验证,验证函数是about_choice,如果该字段的值为2会引发一个错误。
  • 序列化器定义:validate_字段名
def validate_title(self, attrs):
    if 'python' in attrs:
        raise serializers.ValidationError("python存在书名中..")
        return attrs
# 意思是如果python这个字符串在title字段里,就会引发一个错误。
  • 多个字段验证:直接在序列化器里定义validate
def validate(self, attrs):
    title = attrs['title']
    post_pub = attrs['post_pub']
    if title == 'python' and post_pub == 1:
        raise serializers.ValidationError("非法输入")
return attrs
# 意思是如果python这个字段在title里,并且post_pub等于1会引发一个错误

5.序列化get请求单个数据

  • 请求单个数据
  • url定义
url(r'^books/(?P<pk>d+)/', views.BookView.as_view(),name="book"),
  • 视图中定义
class BookView(APIView):
    def get(self,request,pk,*args,**kwargs):
        if pk:
            book_obj = models.Book.objects.filter(pk=pk)
        else:
            book_obj = models.Book.objects.all()
        # 注意如果是单个book_obj对象,需要去除掉many=True
        ser_book = BookSerializer(instance=book_obj,many=True,context={"request":request})
  • 序列化都一样

6.序列化更新单个数据

  • 视图函数定义put方法
def put(self,request,pk,*args,**kwargs):
    book_obj = models.Book.objects.filter(pk=pk).first()
    ser_obj = BookSerializer(instance=book_obj,data=request.data)
    if ser_obj.is_valid():
        ser_obj.save()
        return Response(ser_obj.data)
    return Response(ser_obj.errors)
  • 序列化器定义update
  def update(self,instance,validated_data):
    # instance为Book对象,validated_data为request.data数据
    instance.title = validated_data.get("title",instance.title)
    instance.put_time = validated_data.get("put_time",instance.put_time)
    # 外键对应
    instance.publisher_id = validated_data.get("post_pub", instance.publisher_id)
    instance.save()
    instance.authors.set(validated_data.get("post_author",instance.authors.all()))
    return instance

#对于外键更新:外键字段_id 
#对于多对多更新: 通过set方式更新

技术图片

7.序列化删除单个数据

  • 视图定义delete方法
    def delete(self,request,pk,*args,**kwargs):
        obj = models.Book.objects.filter(pk=pk).first()
        if obj:
            obj.delete()
            return Response({"message":"删除成功"})
        return Response({"message":"数据不存在"})

one

以上是关于restful序列化应用的主要内容,如果未能解决你的问题,请参考以下文章

Django REST framework 基本组件

Django rest_framewok框架的基本组件

预警|Struts2 REST插件存在远程代码执行漏洞(CVE-2017-9805)

Spring Rest 文档。片段生成时 UTF-8 中间字节无效 [重复]

Django Rest_Framework的简单介绍

restful序列化应用