zoukankan      html  css  js  c++  java
  • django

    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

  • 相关阅读:
    Qt使用QCustomplot绘制曲线--修改纵坐标显示宽度
    为WPF项目添加Program.cs
    error: C1083: 无法打开包括文件: “QApplication”: No such file or directory
    clangbackend已停止工作
    无法处理文件 MinimalSimpleBrowserForm.resx,因为它位于 Internet 或受限区域中,或者文件上具有 Web 标记。要想处理这些文件,请删除 Web 标记。
    QByteArray转QString打印
    zend studio中ctrl+鼠标左键无法转到类或函数定义文件的解决方法
    HTML无刷新提交表单
    这个是我得标题:1548241388
    这个是我得标题:1548241357
  • 原文地址:https://www.cnblogs.com/xujunkai/p/12340850.html
Copyright © 2011-2022 走看看