zoukankan      html  css  js  c++  java
  • Restful framework【第三篇】序列化组件

    基本使用

    -序列化
    	-对象,转成json格式
    用drf的序列化组件
      -定义一个类继承class BookSerializer(serializers.Serializer):
      -写字段,如果不指定source,字段名必须跟数据库字段名对应(source指定的值跟字段名不能重复)
      -source还可以指定方法
      -publish=serializers.SerializerMethodField()
    	def get_publish(self,obj):
    		obj.publish
    		#obj.authors.all()
    				
    -Serializer
    -ModelSerializer
    	class Meta:
    		# 指定表模型
    		model = models.Book
    		# 序列化所有字段
    		fields = '__all__'
    		# 只想序列化title和id这俩字段
    		# fields = ['title', 'id']
    		# exclude 和fields 不要连用
    		# exclude = ['title']
    		depth=1
             
              -反序列化:
                -保存
                  ser=BookSer(data=传过来的字典)
                  if ser.is_valid()
                    ser.save()
                -取校验通过的数据:
                  ser.data
                -修改
                  ser=BookSer(data=传过来的字典,instance=要修改的对象)
                  if ser.is_valid()
                    ser.save()
                  else:
                    errors=ser.errors
    
              # 如果想让publish字段显示出版社的名字
                # publish = serializers.CharField(source='publish.name')
                # authors = serializers.SerializerMethodField()
                # def get_authors(self, obj):
                #     author_list = obj.authors.all()
                #     author_ser = AuthorSer(instance=author_list, many=True)
                #     return author_ser.data

    Django自带序列化组件

    serializers(把对象序列化成json字符串)

    from django.core import serializers
    from django.core import serializers
    def test(request):
        book_list = Book.objects.all()    
        ret = serializers.serialize("json", book_list)
        return HttpResponse(ret)

    rest-framework序列化之Serializer

    models部分

    from django.db import models
    
    # Create your models here.
    
    
    class Book(models.Model):
        title=models.CharField(max_length=32)
        price=models.IntegerField()
        pub_date=models.DateField()
        publish=models.ForeignKey("Publish")
        authors=models.ManyToManyField("Author")
        def __str__(self):
            return self.title
    
    class Publish(models.Model):
        name=models.CharField(max_length=32)
        email=models.EmailField()
        def __str__(self):
            return self.name
    
    class Author(models.Model):
        name=models.CharField(max_length=32)
        age=models.IntegerField()
        def __str__(self):
            return self.name

    view部分

    from rest_framework.views import APIView
    from rest_framework.response import Response
    from .models import *
    from django.shortcuts import HttpResponse
    from django.core import serializers
    
    
    from rest_framework import serializers
    
    <... 这一块代码最好新建一个 .py文件放在里面,这样的话看起来就不是那么乱了 class BookSerializers(serializers.Serializer): title=serializers.CharField(max_length=32) price=serializers.IntegerField() pub_date=serializers.DateField() publish=serializers.CharField(source="publish.name") #authors=serializers.CharField(source="authors.all") authors=serializers.SerializerMethodField() def get_authors(self,obj): temp=[] for author in obj.authors.all(): temp.append(author.name) return temp   #此处可以继续用author的Serializers,   # def get_authors(self,obj):     # ret=obj.authors.all()     # ss=AuthorSerializer(ret,many=True)     # return ss.data ...>
    class BookViewSet(APIView): def get(self,request,*args,**kwargs): book_list=Book.objects.all() # 序列化方式1: # from django.forms.models import model_to_dict # import json # data=[] # for obj in book_list: # data.append(model_to_dict(obj)) # print(data) # return HttpResponse("ok") # 序列化方式2: # data=serializers.Serialize("json",book_list) # return HttpResponse(data) # 序列化方式3: bs=BookSerializers(book_list,many=True) #many=True代表有多条数据,如果只有一条数据,many=False return Response(bs.data)      # 序列化方式4:    # ret=models.Book.objects.all().values('nid','title')      # dd=list(ret) # return HttpResponse(json.dumps(dd))

    注意:

    source 如果是字段,会显示字段,如果是方法,会执行方法,不用加括号(authors=serializers.CharField(source='authors.all'))

    如在模型中定义一个方法,直接可以在在source指定执行

    class UserInfo(models.Model):
        user_type_choices = (
            (1,'普通用户'),
            (2,'VIP'),
            (3,'SVIP'),
        )
        user_type = models.IntegerField(choices=user_type_choices)
    
        username = models.CharField(max_length=32,unique=True)
        password = models.CharField(max_length=64)
    
    
    #视图
    ret=models.UserInfo.objects.filter(pk=1).first()
    aa=ret.get_user_type_display()
    
    #serializer
    xx=serializers.CharField(source='get_user_type_display')

    小结

    # 1 变量名和source指定的值不能一样
    # 2 source='publish.name'还支持继续 .
    # 3 source 还支持方法(没用)
    # 4 支持写方法,如下
    	#方法一定传一个参数,是当前book对象
    	publish_dic=serializers.SerializerMethodField()
    	def get_publish_dic(self,obj):
    	# 猜,这个obj应该是谁,当前book对象
    	  return {'id':obj.publish.pk,'name':obj.publish.name}
    			
    在线格式化json
    -https://www.json.cn/

    rest-framework序列化之ModelSerializer

    class BookSerializers(serializers.ModelSerializer):
        class Meta:
            model = models.Book
            # fields = "__all__"
            fields=['nid','title','authors','publish']
            # exclude=('nid',)   #不能跟fields同时用
            # depth = 1    #深度控制,写 几 往里拿几层,层数越多,响应越慢,官方建议0--10之间,个人建议最多3层
        publish=serializers.SerializerMethodField()
        def get_publish(self,obj):
            return obj.publish.name
        authors=serializers.SerializerMethodField()
        def get_authors(self,obj):
            ret=obj.authors.all()
            ss=AuthorSerializer(ret,many=True)
            return ss.data

    生成hypermedialink(极少数)

    class BookSerializers(serializers.ModelSerializer):
        class Meta:
            model = models.Book
            fields = "__all__"
        # 生成连接,直接查看出版社详情
        publish = serializers.HyperlinkedIdentityField(view_name='ttt', lookup_field='publish_id', lookup_url_kwarg='pkk')
        authors=serializers.SerializerMethodField()
        def get_authors(self,obj):
            ret=obj.authors.all()
            ss=AuthorSerializer(ret,many=True)
            return ss.data
    #--------------
    
    res=BookSerializers(ret,many=True,context={'request': request})
    #--------------
    
    class Publish(APIView):
        def get(self,request,pkk):
            print(pkk)
            return HttpResponse('ok')
    #----路由---
    url(r'^publish/(?P<pkk>d+)$', views.Publish.as_view(),name='ttt'),

    序列化组件之请求数据校验和保存功能

    class BookSerializers(serializers.ModelSerializer):
        class Meta:
            model=Book
            fields="__all__"
    
    #————————
    class BookView(APIView):
    
        def post(self, request):
    
            # 添加一条数据
            print(request.data)
    
            bs=BookSerializers(data=request.data)
            if bs.is_valid():
                bs.save()  # 生成记录
                return Response(bs.data)
            else:
    
                return Response(bs.errors)
    class BookSerializer1(serializers.Serializer):
        title=serializers.CharField(error_messages={'required': '标题不能为空'})
    
    #这种方式要保存,必须重写create方法

     通过源码查看留的校验字段的钩子函数

    #is_valid---->self.run_validation-(执行Serializer的run_validation)-->self.to_internal_value(data)---(执行Serializer的run_validation:485行)
    def validate_title(self, value):
            from rest_framework import exceptions
            raise exceptions.ValidationError('看你不顺眼')
            return value
    
    #全局
    def validate(self, attrs):
        from rest_framework import exceptions
        if attrs.get('title')== attrs.get('title2'):
            return attrs
        else:
            raise exceptions.ValidationError('不想等啊')

    序列化组件源码分析

    序列化组件,先调用__new__方法,如果many=True,生成ListSerializer对象,如果为False,生成Serializer对象
    序列化对象.data方法--调用父类data方法---调用对象自己的to_representation(自定义的序列化类无此方法,去父类找)
    Aerializer类里有to_representation方法,for循环执行attribute = field.get_attribute(instance)
    再去Field类里去找get_attribute方法,self.source_attrs就是被切分的source,然后执行get_attribute方法,source_attrs
    当参数传过去,判断是方法就加括号执行,是属性就把值取出来

    图书的增删查改resful接口与上面知识点的实例

    视图层

    from django.shortcuts import render, HttpResponse
    from django.http import JsonResponse
    # Create your views here.
    from django.views import View
    
    
    class Test(View):
        def dispatch(self, request, *args, **kwargs):
            # 写代码
            obj = super().dispatch(request, *args, **kwargs)
            # 写代码
            return obj
    
        def get(self, request, *args, **kwargs):
            return HttpResponse('cbv_get')
    
        def post(self, request, *args, **kwargs):
            return HttpResponse('cbv_post')
    
    
    user_list = [{'id': 1, 'name': 'lqz', 'age': 18}, {'id': 2, 'name': 'egon', 'age': 17},
                 {'id': 3, 'name': 'xiaohou', 'age': 16}]
    
    
    def users(request):
        response = {'status': 100, 'errors': None}
        if request.method == 'GET':
            response['users'] = user_list
            return JsonResponse(response, safe=False)
        if request.method == 'POST':
            name = request.POST.get('name')
            age = request.POST.get('age')
            user_list.append({'id': len(user_list) + 1, 'name': name, 'age': age})
            # response['user'] = {'id':len(user_list),'name': name, 'age': age}
            response['msg'] = '新增成功'
            return JsonResponse(response)
    
    
    def user(request, id):
        response = {'status': 100, 'errors': None}
        if request.method == 'GET':
            id = int(id)
            response['user'] = user_list[id]
            return JsonResponse(response)
    
    
    from rest_framework.views import APIView
    from rest_framework.response import Response
    from rest_framework.request import Request
    
    
    # 基于drf写接口,写cbv
    class DrfTest(APIView):
    
        def get(self, request, *args, **kwargs):
            # request是封装之后的request了,原来的request是request._request
            print(type(request._request))
            print(type(request))
            # 问:当前request对象并没有这些属性,但是能打印出来,为什么?
            # 修改了getattr
            print(request.method)
            print(request.POST)
            print(request.GET)
            # 就相当于:
            print(request.query_params)
            print(request._request.GET)
            response = {'status': 100, 'errors': None}
            response['users'] = user_list
            # 用drf的Response,可以通过请求客户端来判断返回数据格式是什么样的
            return Response(response)
            # return JsonResponse(response)
    
        def post(self, request, *args, **kwargs):
            # post 提交的数据,urlencode,formdate,json格式,都能从data中取出来
            name = request.data.get('name')
            # request.FILES
            print(name)
            return HttpResponse('ok')
    
    
    from app01 import models
    from app01.MySer import BookSerializer
    
    class Auth():
        def authenticate(self,request):
            pass
    
    
    # 写一个获取所有图书的接口
    class Books(APIView):
        authentication_classes=[Auth,]
        def get(self, request, *args, **kwargs):
    
            response = {'status': 100, 'msg': '成功'}
            book_list = models.Book.objects.all()
            # 第一个参数是要序列化的queryset对象,如果序列化多条,必须指定many=True
            # 问?什么情况下many=False,instance=单个对象的时候
            book_ser = BookSerializer(book_list, many=True)
            print(book_ser.data)
            response['books'] = book_ser.data
            return Response(response)
    
        def post(self, request):
            response = {'status': 100, 'msg': '成功'}
            # 提交的字典
            # book = request.data
            # 传统方法,创建对象保存
            # 新方法,通过序列化组件保存,必须用继承自ModelSerializer
            # data注意是data
            book_ser = BookSerializer(data=request.data)
            # is_valid提交的字段校验通过
            if book_ser.is_valid():
                book_ser.save()
                response['book'] = book_ser.data
            else:
                response['msg'] = book_ser.errors
            # return Response(book_ser.data)
            return Response(response)
    
    
    class Book(APIView):
    
        def get(self, request, id):
            response = {'status': 100, 'msg': '成功'}
            book = models.Book.objects.filter(pk=id).first()
            book_ser = BookSerializer(book, many=False)
            response['book'] = book_ser.data
            return Response(response)
    
        def put(self, request, id):
            response = {'status': 100, 'msg': '成功'}
            book = models.Book.objects.filter(pk=id).first()
            # 修改的话,要把book对象传过来
            book_ser = BookSerializer(data=request.data, instance=book)
            # is_valid提交的字段校验通过
            if book_ser.is_valid():
                # save既可以修改,又可以更新
                book_ser.save()
                response['book'] = book_ser.data
            else:
                response['msg'] = book_ser.errors
            # return Response(book_ser.data)
            return Response(response)
    
        def delete(self,request,id):
            response = {'status': 100, 'msg': '删除成功'}
            book = models.Book.objects.filter(pk=id).delete()
            return Response(response)

    模板层

    from django.db import models
    
    # Create your models here.
    from django.db import models
    
    
    # Create your models here.
    
    class Book(models.Model):
        title = models.CharField(max_length=32)
        price = models.IntegerField()
        pub_date = models.DateField()
        publish = models.ForeignKey("Publish")
        authors = models.ManyToManyField("Author")
    
        def test(self):
            return self.title + str(self.price)
    
        def __str__(self):
            return self.title
    
    
    class Publish(models.Model):
        name = models.CharField(max_length=32)
        email = models.EmailField()
    
        # def __str__(self):
        #     return self.name
        # return str(self.pk)
    
    
    class Author(models.Model):
        name = models.CharField(max_length=32)
        age = models.IntegerField()
        #
        # def __str__(self):
        #     return self.name

    自己手动创建的序列化组件层

    from rest_framework import serializers
    
    
    # from rest_framework.request import Request
    
    class AuthorSer(serializers.Serializer):
        id = serializers.CharField()
        name = serializers.CharField()
        age = serializers.CharField()
    
    
    # class BookSerializer(serializers.Serializer):
    #     id = serializers.CharField()
    #     # 通过source可以改名
    #     name = serializers.CharField(source='title')
    #     price = serializers.CharField()
    #
    #     xxx = serializers.CharField(source='test')
    #     # 1 变量名和source指定的值不能一样
    #     # 2 source='publish.name'还支持继续 .
    #     # 3 source 还支持方法(没用)
    #     # publish_name = serializers.CharField(source='publish.name')
    #     # publish_id = serializers.CharField(source='publish.pk')
    #     # 4 支持写方法,如下
    #         #方法一定传一个参数,是当前book对象
    #     publish_dic=serializers.SerializerMethodField()
    #     def get_publish_dic(self,obj):
    #         # 猜,这个obj应该是谁,当前book对象
    #         return {'id':obj.publish.pk,'name':obj.publish.name}
    #     authors=serializers.SerializerMethodField()
    #     # def get_authors(self,obj):
    #     #     # 所有作者queryset对象
    #     #     author_list=obj.authors.all()
    #     #     ll=[ {'name':author.name,'id':author.pk} for author in author_list]
    #     #     return ll
    #     def get_authors(self,obj):
    #         # 所有作者queryset对象
    #         author_list=obj.authors.all()
    #         author_ser=AuthorSer(instance=author_list,many=True)
    #         return author_ser.data
    # ModelSerializer跟表模型绑定的序列化
    from app01 import models
    
    
    class BookSerializer(serializers.ModelSerializer):
        class Meta:
            # 指定表模型
            model = models.Book
            # 序列化所有字段
            fields = '__all__'
            # 只想序列化title和id这俩字段
            # fields = ['title', 'id']
            # exclude 和fields 不要连用
            # exclude = ['title']
            # 深度,表示连表的深度
            # 不建议使用:下几层要取得参数不能控制,官方建议不要超过10,我给你的建议不要超过3
            # depth=1
            # 全取出来之后,可以在后面覆盖之前的值
            # 如果想让publish字段显示出版社的名字
            # publish = serializers.CharField(source='publish.name')
            # authors = serializers.SerializerMethodField()
            # def get_authors(self, obj):
            #     author_list = obj.authors.all()
            #     author_ser = AuthorSer(instance=author_list, many=True)
            #     return author_ser.data
    
        title = serializers.CharField(max_length=6, min_length=3, error_messages={'max_length': '太长了'})
    
        # 也有局部钩子和全局钩子
        def validate_title(self, value):
            from rest_framework import exceptions
            print(value)
            if value.startswith('sb'):
                raise exceptions.ValidationError('不能以sb开头')
            return value
        # def validate_title(self, value):
        #     from rest_framework import exceptions
        #     raise exceptions.ValidationError('看你不顺眼')
        #     return value

    路由

    from django.conf.urls import url
    from django.contrib import admin
    from app01 import views
    urlpatterns = [
        url(r'^admin/', admin.site.urls),
        url(r'^users/', views.DrfTest.as_view()),
        # 在这写的实际上就是as_view()内view的内存地址
        url(r'^books/', views.Books.as_view()),
        url(r'^book/(?P<id>d+)', views.Book.as_view()),
    ]
    

      

  • 相关阅读:
    css 移动端像素,rem适配详解
    css,图片和文字在父元素垂直居中,且图片和文字在中线对齐排列的几种方式
    css弹性盒子桃园三兄弟之:flexgrow、flexshrink、flexbasis详解
    less的基本使用
    css 利用flex居中对齐
    css 高度塌陷和外边距折叠问题详解,(BFC)
    HTML行内元素、块状元素、行内块状元素的区别
    css flex弹性布局学习总结
    shell学习笔记
    Ant入门教程
  • 原文地址:https://www.cnblogs.com/596014054-yangdongsheng/p/10228812.html
Copyright © 2011-2022 走看看