zoukankan      html  css  js  c++  java
  • RESTful规范(一)

    一、学习restframework之前准备

    1、json格式若想展示中文,需要ensure_ascii=False

    import json
    
    dic={'name':'你好'}
    print(json.dumps(dic,ensure_ascii=False))

    2、不基于restframework也可以通过django来做符合restframework的规范接口设计,Jsonresponse,若想在json展示中文,如下

    def books(request):
    
        ll=[{'name':'python全站开发','price':20},{'name':'linux','price':30}]
    
        # return HttpResponse(json.dumps(ll))
        return JsonResponse(ll,safe=False,json_dumps_params={'ensure_ascii':False})

    3、原声cbv执行流程

    url(r'^books/$', views.Book.as_view()),


    原声cbv执行流程---》as_view----》dispatch---》相应到具体的函数 from django.views import View class Book(View): def get(self,reuquest): # reuquest.method return HttpResponse('get') def post(self,request): return HttpResponse('post')

    3、分析restframework

    一 restfu(规范)
        是什么:
            -面向资源编程
            -getBooklist:获取图书列表
            -符合规范的:books
        规范:
            -method:get----》books----》取到所有的书
                    
                     post———》books---》新增图书
                     
                     put/patch--》books/id---》修改图书
                     
                     delete---》books/id---》删除图书
            -https://api.example.com/v1/zoos?limit=10
            -
    
    二 drf
        安装(app):pip3 install djangorestframework
        -基于drf写resful的接口,得写CBV
        -request对象,源码分析
        -APIView源码分析   

    二、restframework使用

    1、POST没法解析json格式,可以在body里取值出来序列化反序列化操作转成字典,目前drf可以在前台提交post后台取值的话用data,

    from rest_framework.views import APIView
    
    class Book(APIView):
        def get(self,request):
            # 拿原来的request对象
            # request._request
            # print(request.method)
            # print(request._request.method)
            # request.POST
            # request.method
            return HttpResponse('get')
        def post(self,request):
            print(request.method)
            print(request._request.method)
            print(request.POST)
    
            # 用apiview之后,再取数据,从request.data
            print(request.data)
            return HttpResponse('post')

    2、用Postman模拟发http请求,网上直接下载,data可以类似于解析器,解析form-data,urlencoded,json格式,而django只能解析form-data,urlencoded两种格式

    三、序列化组件

    1、从数据库取出来的都是qs类型,里面套了一个一个对象,要传到前台去必须要json格式,符合drf规范的第一种方式

    数据库配置
    DATABASES = { 'default': { 'ENGINE': 'django.db.backends.mysql', 'NAME': 'resful', 'USER':'root', 'PASSWORD':'', 'HOST':'127.0.0.1', 'PORT':3306, } }

    models取值为qureryset类型,

    from app01 import models
    序列化组建
    第一种方式
    class Book(APIView):
        def get(self,request):
            response={'status':100,'msg':None}
            books=models.Book.objects.all()
            # ll=[]
            # for book in books:
            #     ll.append({'name':book.name,''})
            ll=[ {'name':book.name,'price':book.price} for book in books]
            response['msg']='查询成功'
            response['data']=ll
            return JsonResponse(response,safe=False)
    
            # return HttpResponse('get')
        def post(self,request):
    
            return HttpResponse('post')

    2、第二种方式,用django子自带序列化组件serializers(Django内置的serializers(把对象序列化成json字符串),但是有个缺点不能定制化

    from django.core import serializers
    
    
    class Book(APIView):
        def get(self,request):
            # response={'status':100,'msg':None}
            books = models.Book.objects.all()
            ret = serializers.serialize("json", books)
            return HttpResponse(ret)
    
            # return HttpResponse('get')
        def post(self,request):
    
            return HttpResponse('post')

    3、用drf自带的组件,建议的话新建个py在APP下,方便解耦,如myserial.py,为符合drf格式,里面新建个response类,见下

        -1 导入:from rest_framework import serializers
        -2 写一个类(名字任意),继承serializers.Serializer
            class BookSer(serializers.Serializer):
                nid=serializers.IntegerField()
                name3=serializers.CharField(source='name')
                price=serializers.CharField()
                # publish_date = serializers.DateField()
                publish_date = serializers.CharField()
                # publish=serializers.CharField(source='publish.email')
                publish=serializers.CharField(source='publish.name')
                xxx=serializers.CharField(source='test')
        -3 如果不指定source,字段名,必须跟数据库列名一致
        -4 source--》既可以指定数据属性,又可以指定方法属性,可以写(publish.name)
        -5 使用:
            -查询出要序列化的数据:books = models.Book.objects.all()
            -ret=myserial.BookSer(books,many=True)-----》多条(queryset对象),必须指定many=True
            -ret=myserial.BookSer(books,many=False)-----》一条(Book对象),必须指定many=False
        -6 aa=serializers.SerializerMethodField()
            -必须配套一个方法(get_aa(self,obj)),方法返回结果,会赋给aa
            -在方法内部,可以继续用序列化组件

    myserial.py

    from rest_framework import serializers
    
    class BookSer(serializers.Serializer):
        nid=serializers.IntegerField()
        name3=serializers.CharField(source='name')
        price=serializers.CharField()
        # publish_date = serializers.DateField()
        publish_date = serializers.CharField()
        # publish=serializers.CharField(source='publish.email')
        publish=serializers.CharField(source='publish.name')
        xxx=serializers.CharField(source='test')
        # authors=serializers.CharField(source='authors.all')
        # SerializerMethodField,可以写一个方法方法名叫:get_字段名字,方法返回值,会赋给authors
        aa=serializers.SerializerMethodField()
        # def get_authors(self,obj):
        #     authors=obj.authors.all()
        #     # ll=[ author.name for author in authors]
        #     ll=[ {'name':author.name,'age':author.age} for author in authors]
        #     return ll
        def get_aa(self, obj):
            authors = obj.authors.all()
            # ll=[ author.name for author in authors]
            ser=AuthorSer(authors,many=True)
            return ser.data

    models.py

    class Book(models.Model):
        nid = models.AutoField(primary_key=True)
        name = models.CharField(max_length=32)
        price = models.DecimalField(max_digits=5, decimal_places=2)
        publish_date = models.DateField(auto_now_add=True)
    
        publish = models.ForeignKey(to='Publish',to_field='nid',on_delete=models.CASCADE)
        authors=models.ManyToManyField(to='Author')
    
        def test(self):
            return 'ttttttt'
        def __str__(self):
            return self.name

    使用,为符合drf格式,里面新建个response类,@property让类方法变属性,不需要(),直接点+属性就ok了

    class MyResponse():
        def __init__(self):
            self.status = 100
            self.msg = None
    
        @property
        def get_dic(self):
            return self.__dict__from app01 import myserial
    class Book(APIView):
        queryset=models.Book.objects.all()
        serializer_class=myserial.BookSer
        def get(self,request):
            response=MyResponse()
            # 多条
            # books = models.Book.objects.all()
            # ret=myserial.BookSer(books,many=True)
            # 一条
            book = self.queryset
            # ret = myserial.BookSer(book, many=False)
            ret = self.serializer_class(instance=book, many=True)
            response.msg='查询成功'
            response.data=ret.data
            return JsonResponse(response.get_dic,safe=False)
    
            # return HttpResponse('get')
        def post(self,request):
       
     # return HttpResponse('post')

    4、若要进行多对多的查询,book和author,可以用SerializerMethodField方法

       -6 aa=serializers.SerializerMethodField()
            -必须配套一个方法(get_aa(self,obj)),方法返回结果,会赋给aa
            -在方法内部,可以继续用序列化组件

    如下

    class BookSer(serializers.Serializer):
        nid=serializers.IntegerField()
        name3=serializers.CharField(source='name')
        price=serializers.CharField()
        # publish_date = serializers.DateField()
        publish_date = serializers.CharField()
        # publish=serializers.CharField(source='publish.email')
        publish=serializers.CharField(source='publish.name')
        xxx=serializers.CharField(source='test')
        # authors=serializers.CharField(source='authors.all')
        # SerializerMethodField,可以写一个方法方法名叫:get_字段名字,方法返回值,会赋给authors
        aa=serializers.SerializerMethodField()
        # def get_authors(self,obj):
        #     authors=obj.authors.all()
        #     # ll=[ author.name for author in authors]
        #     ll=[ {'name':author.name,'age':author.age} for author in authors]
        #     return ll
        def get_aa(self, obj):
            authors = obj.authors.all()
            # ll=[ author.name for author in authors]
            ser=AuthorSer(authors,many=True)
            return ser.data
    
    
    class AuthorSer(serializers.Serializer):
        id=serializers.IntegerField(source='nid')
        age=serializers.CharField()
        name=serializers.CharField()

    四 序列化组件之serializers.ModelSerializer

        -用法同Serializer
        -不同点:
            class BookSer(serializers.ModelSerializer):
                class Meta:
                    # 指定要序列号的表模型是book
                    model=models.Book
                    fields='__all__'
                    exclude=['nid']
                    depth=1

    例子如下

    from app01 import models
    class BookSer(serializers.ModelSerializer):
        class Meta:
            # 指定要序列号的表模型是book
            model=models.Book
            # 把所有字段都序列化
            # fields='__all__'
            # 可以传列表,指定取几个
            # fields=['name','authors','publish']
            # 除了nid都查
            exclude=['authors']
            #fields和exclude不能同时用
            # depth指定深度,个人建议最多用3
            # depth=2

    五 序列化组件的字段校验和反序列化功能

    序列化组件是将对象序列化成字典,但是前台post提交的json数据需要转成字典,再反序列化成对象,最后save()方法才能保存在数据里,需要反序列功能

        -只有:ModelSerializer,能直接保存
        - def post(self,request):
            print(request.data)
            #生成一个序列化对象 
            ser=myserial.BookSer(data=request.data)
            #判断字段是否校验通过
            if ser.is_valid():
            #通过,直接保存
                ser.save()
            else:
                #错误信息        
                print(ser.errors)
    
            return HttpResponse('post')


    from app01 import models
    class BookSer(serializers.ModelSerializer):
    class Meta:
    # 指定要序列号的表模型是book
    model=models.Book
    exclude=['authors']

    如下

     def post(self,request):
            # print(request.data)
            ser=myserial.BookSer(data=request.data)
            if ser.is_valid():
                ser.save()
                return HttpResponse('成功')
            else:
                print(ser.errors)
    
                return JsonResponse(ser.errors)

    六 序列化组件局部校验和全局校验

        -局部校验
         name=serializers.CharField()
         def validate_name(self,value):
            if value.startswith('sb'):
                raise ValidationError('不能以sb开头')
            else:
                return value
        -全局校验
            def validate(self,value):
                print(type(value))
                print(value)
                name=value.get('name')
                price=value.get('price')
                if name!=price:
                    raise ValidationError('书名和价格不相等')
                else:
    
                    return value

    如下

    from rest_framework.exceptions import ValidationError
    from app01 import models
    class BookSer(serializers.ModelSerializer):
        class Meta:
            # 指定要序列号的表模型是book
            model=models.Book
            # 把所有字段都序列化
            # fields='__all__'
            # 可以传列表,指定取几个
            # fields=['name','authors','publish']
            # 除了nid都查
            exclude=['authors']
            #fields和exclude不能同时用
            # depth指定深度,个人建议最多用3
            # depth=2
        局部校验
        name=serializers.CharField(error_messages={'required':'该字段必填'})
        def validate_name(self,value):
            if value.startswith('sb'):
                raise ValidationError('不能以sb开头')
            else:
                return value
        全局校验
        def validate(self,value):
            print(type(value))
            print(value)
            name=value.get('name')
            price=value.get('price')
            if name!=price:
                raise ValidationError('书名和价格不相等')
            else:
    
                return value

    views,主要验证前台post提交数据的局部和全局验证

    from app01 import myserial
    class Book(APIView):
        queryset=models.Book.objects.all()
        serializer_class=myserial.BookSer
        def get(self,request):
            response=MyResponse()
            # 多条
            # books = models.Book.objects.all()
            # ret=myserial.BookSer(books,many=True)
            # 一条
            book = self.queryset
            # ret = myserial.BookSer(book, many=False)
            ret = self.serializer_class(instance=book, many=True)
            response.msg='查询成功'
            response.data=ret.data
            return JsonResponse(response.get_dic,safe=False)
    
            # return HttpResponse('get')
        def post(self,request):
            # print(request.data)
            ser=myserial.BookSer(data=request.data)
            if ser.is_valid():
                ser.save()
                return HttpResponse('成功')
            else:
                print(ser.errors)
    
                return JsonResponse(ser.errors)

    七、符合drf的视图类基本写法

    1、views.py

    
    
    class MyResponse():
    def __init__(self):
    self.status = 100
    self.msg = None

    @property
    def get_dic(self):
    return self.__dict__

    class
    BookDetail(APIView): def get(self,request,id): response=MyResponse() ret=models.Book.objects.filter(pk=id).first() ser=myserial.BookSer(instance=ret,many=False) response.msg='查询成功' response.data=ser.data return JsonResponse(response.get_dic,safe=False) def put(self,request,id): # 修改 response=MyResponse() book=models.Book.objects.filter(pk=id).first() ser=myserial.BookSer(instance=book,data=request.data) if ser.is_valid(): # 可以新增,可以修改 ser.save() print(ser.data) print(type(ser.instance)) response.msg='修改成功' response.data=ser.data else: response.msg = '修改失败' response.status = 101 response.data=ser.errors return JsonResponse(response.get_dic,safe=False) def delete(self,request,id): ret=models.Book.objects.filter(pk=id).delete() return HttpResponse('删除成功')

    2、序列化组件

    url(r'^books/(?P<pk>d+)/', views.BookDetail.as_view()),

    from app01 import models
    class BookSer(serializers.ModelSerializer):
    class Meta:
    # 指定要序列号的表模型是book
    model=models.Book
    exclude=['authors']
  • 相关阅读:
    SSL评测
    EF+SQLSERVER控制并发下抢红包减余额(改进)
    关于游标嵌套时@@FETCH_STATUS的值
    windows下限制Redis端口只能由本机访问
    windows下配置Redis
    Node.js 使用gm处理图像
    Git 与其他系统
    git-svn 简易 操作指南
    git-svn — 让git和svn协同工作
    Git和SVN共存的方法
  • 原文地址:https://www.cnblogs.com/di2wu/p/10129173.html
Copyright © 2011-2022 走看看