• Django restful


    1.restful api的规范

    • API与用户的通信协议,总是使用HTTPs协议
    • 域名 
      • https://api.example.com                         尽量将API部署在专用域名(会存在跨域问题)
      • https://example.org/api/                        API很简单
    • 版本
      • URL,如:https://api.example.com/v1/
      • 请求头    跨域时,引发发送多次请求
    • 路径,视网络上任何东西都是资源,均使用名词表示(可复数)
      • https://api.example.com/v1/zoos
      • https://api.example.com/v1/animals
      • https://api.example.com/v1/employees
    • method
      • GET      :从服务器取出资源(一项或多项)
      • POST    :在服务器新建一个资源
      • PUT      :在服务器更新资源(客户端提供改变后的完整资源)
      • PATCH  :在服务器更新资源(客户端提供改变的属性)
      • DELETE :从服务器删除资源
    • 过滤,通过在url上传参的形式传递搜索条件
      • https://api.example.com/v1/zoos?limit=10:指定返回记录的数量
      • https://api.example.com/v1/zoos?offset=10:指定返回记录的开始位置
      • https://api.example.com/v1/zoos?page=2&per_page=100:指定第几页,以及每页的记录数
      • https://api.example.com/v1/zoos?sortby=name&order=asc:指定返回结果按照哪个属性排序,以及排序顺序
      • https://api.example.com/v1/zoos?animal_type_id=1:指定筛选条件
    在进行API的设计中要执行restful的规范,比如api尽量使用名词可以是复数如user/users,不要使用形容词如show。
    api中可以添加版本号如:https://api.example.com/v1/
    API的域名中可以添加“api”字符作为标识如:
      https://api.example.com                         尽量将API部署在专用域名(会存在跨域问题)
      https://example.org/api/                        API很简单;
    过滤可以以参数进行传递:
      https://api.example.com/v1/zoos?limit=10:指定返回记录的数量
      https://api.example.com/v1/zoos?offset=10:指定返回记录的开始位置
      https://api.example.com/v1/zoos?page=2&per_page=100:指定第几页,以及每页的记录数
      https://api.example.com/v1/zoos?sortby=name&order=asc:指定返回结果按照哪个属性排序,以及排序顺序
      https://api.example.com/v1/zoos?animal_type_id=1:指定筛选条件
    提交方式可以进行获取,添加,删除,修改等操作
      GET      :从服务器取出资源(一项或多项)
      POST    :在服务器新建一个资源
      PUT      :在服务器更新资源(客户端提供改变后的完整资源)
      PATCH  :在服务器更新资源(客户端提供改变的属性)
      DELETE :从服务器删除资源

    2.用户认证:

    #view.py
                        class MyAuthentication(BaseAuthentication):
    
                            def authenticate(self, request):
                                # return None ,我不管
                                token = request.query_params.get('token')
                                obj = models.UserInfo.objects.filter(token=token).first()
                                if obj:
                                    return (obj.username,obj)
                                raise APIException('用户认证失败')
                                
                                
                        class AuthView(APIView):
                            authentication_classes=[MyAuthentication,]
    
                        class HostView(APIView):
    
                            def get(self,request,*args,**kwargs):
                                # 原来request对象,django.core.handlers.wsgi.WSGIRequest
                                # 现在的request对象,rest_framework.request.Request
                                print(request.user)
                                print(request.auth)
                                return HttpResponse('主机列表')
    
    #settings.py
    
                        REST_FRAMEWORK = {
                            'UNAUTHENTICATED_USER': None,
                            'UNAUTHENTICATED_TOKEN': None,
                            "DEFAULT_AUTHENTICATION_CLASSES": [
                                "app02.utils.MyAuthentication",
                            ],
                        }

    3.授权(+认证)

    class MyAuthentication(BaseAuthentication):
    
        def authenticate(self, request):
            token = request.query_params.get('token')
            obj = models.UserInfo.objects.filter(token=token).first()
            if obj:
                return (obj.username,obj)
            return None
    
        def authenticate_header(self, request):
            """
            Return a string to be used as the value of the `WWW-Authenticate`
            header in a `401 Unauthenticated` response, or `None` if the
            authentication scheme should return `403 Permission Denied` responses.
            """
            # return 'Basic realm="api"'
            pass
    
    class MyPermission(object):
        message = "无权访问"
        def has_permission(self,request,view):
            if request.user:
                return True
            return False
    
    class AdminPermission(object):
        message = "无权访问"
        def has_permission(self,request,view):
            if request.user == 'alex':
                return True
            return False
    
    class HostView(APIView):
        """
        匿名用户和用户都能访问
        """
        authentication_classes = [MyAuthentication,]
        permission_classes = []
        def get(self,request,*args,**kwargs):
            # 原来request对象,django.core.handlers.wsgi.WSGIRequest
            # 现在的request对象,rest_framework.request.Request
            self.dispatch
            print(request.user)
            # print(request.user)
            # print(request.auth)
            return Response('主机列表')

    4.版本

                urlpatterns = [
                    #url(r'^admin/', admin.site.urls),
                    url(r'^api/(?P<version>[v1|v2]+)/', include('api.urls')),
                ]
    
                urlpatterns = [
                    url(r'^users/', views.UsersView.as_view(),name='u'),
                ]
                
                
                class UsersView(APIView):
                    
                    def get(self,request,*args,**kwargs):
                        self.dispatch
                        print(request.version) # QueryParameterVersioning().detemiin_version()
                        print(request.versioning_scheme) # QueryParameterVersioning()
    
                
                REST_FRAMEWORK = {
                    'VERSION_PARAM':'version',
                    'DEFAULT_VERSION':'v1',
                    'ALLOWED_VERSIONS':['v1','v2'],
                    # 'DEFAULT_VERSIONING_CLASS':"rest_framework.versioning.HostNameVersioning"
                    'DEFAULT_VERSIONING_CLASS':"rest_framework.versioning.URLPathVersioning"
                }
    
            HostName
                urlpatterns = [
                    #url(r'^admin/', admin.site.urls),
                    url(r'^api/', include('api.urls')),
                ]
    
                urlpatterns = [
                    url(r'^users/', views.UsersView.as_view(),name='u'),
                ]
                
                
                class UsersView(APIView):
                    
                    def get(self,request,*args,**kwargs):
                        self.dispatch
                        print(request.version) # QueryParameterVersioning().detemiin_version()
                        print(request.versioning_scheme) # QueryParameterVersioning()
    
                
                REST_FRAMEWORK = {
                    'VERSION_PARAM':'version',
                    'DEFAULT_VERSION':'v1',
                    'ALLOWED_VERSIONS':['v1','v2'],
                    'DEFAULT_VERSIONING_CLASS':"rest_framework.versioning.HostNameVersioning"
                }
                
                # C:WindowsSystem32driversetc
                # vim /etc/hosts
                127.0.0.1    v1.luffy.com
                127.0.0.1    v2.luffy.com

    5.解析器

    请求的数据进行解析:请求体进行解析。表示服务端可以解析的数据格式的种类。
            
                Content-Type: application/url-encoding.....
                request.body
                request.POST
                
                Content-Type: application/json.....
                request.body
                request.POST
            
            客户端:
                Content-Type: application/json
                '{"name":"alex","age":123}'
            
            服务端接收:
                读取客户端发送的Content-Type的值 application/json
                
                parser_classes = [JSONParser,]
                media_type_list = ['application/json',]
            
                如果客户端的Content-Type的值和 application/json 匹配:JSONParser处理数据
                如果客户端的Content-Type的值和 application/x-www-form-urlencoded 匹配:FormParser处理数据
            
            
            配置:
                单视图:
                class UsersView(APIView):
                    parser_classes = [JSONParser,]
                    
                全局配置:
                    REST_FRAMEWORK = {
                        'VERSION_PARAM':'version',
                        'DEFAULT_VERSION':'v1',
                        'ALLOWED_VERSIONS':['v1','v2'],
                        # 'DEFAULT_VERSIONING_CLASS':"rest_framework.versioning.HostNameVersioning"
                        'DEFAULT_VERSIONING_CLASS':"rest_framework.versioning.URLPathVersioning",
                        'DEFAULT_PARSER_CLASSES':[
                            'rest_framework.parsers.JSONParser',
                            'rest_framework.parsers.FormParser',
                        ]
                    }

    6.序列化

    a. 基本操作:
                    class UsersSerializer(serializers.Serializer):
                        name = serializers.CharField()
                        pwd = serializers.CharField()
                
                            
                    class UsersView(APIView):
                        def get(self,request,*args,**kwargs):
                            self.dispatch
                            # 方式一:
                            # user_list = models.UserInfo.objects.all().values('name','pwd','group__id',"group__title")
                            # return Response(user_list)
    
                            # 方式二之多对象
                            # user_list = models.UserInfo.objects.all()
                            # ser = UsersSerializer(instance=user_list,many=True)
                            # return Response(ser.data)
    
                            # 方式二之单对象
                            user = models.UserInfo.objects.all().first()
                            ser = UsersSerializer(instance=user, many=False)
                            return Response(ser.data)
    
                b. 跨表
                    class UsersSerializer(serializers.Serializer):
                        name = serializers.CharField()
                        pwd = serializers.CharField()
                        group_id = serializers.CharField()
                        xxxx = serializers.CharField(source="group.title")
                        x1 = serializers.CharField(source="group.mu.name")
    
    
    
                    class UsersView(APIView):
                        def get(self,request,*args,**kwargs):
                            self.dispatch
                            # 方式一:
                            # user_list = models.UserInfo.objects.all().values('name','pwd','group__id',"group__title")
                            # return Response(user_list)
    
                            # 方式二之多对象
                            user_list = models.UserInfo.objects.all()
                            ser = UsersSerializer(instance=user_list,many=True)
                            return Response(ser.data)
    
                c. 复杂序列化
                    解决方案一:
                        class MyCharField(serializers.CharField):
    
                            def to_representation(self, value):
                                data_list = []
                                for row in value:
                                    data_list.append(row.name)
                                return data_list
    
                        class UsersSerializer(serializers.Serializer):
                            name = serializers.CharField() # obj.name
                            pwd = serializers.CharField()  # obj.pwd
                            group_id = serializers.CharField() # obj.group_id
                            xxxx = serializers.CharField(source="group.title") # obj.group.title
                            x1 = serializers.CharField(source="group.mu.name") # obj.mu.name
                            # x2 = serializers.CharField(source="roles.all") # obj.mu.name
                            x2 = MyCharField(source="roles.all") # obj.mu.name
        
                    解决方案二:
                        class MyCharField(serializers.CharField):
                            def to_representation(self, value):
                                return {'id':value.pk, 'name':value.name}
    
                        class UsersSerializer(serializers.Serializer):
                            name = serializers.CharField() # obj.name
                            pwd = serializers.CharField()  # obj.pwd
                            group_id = serializers.CharField() # obj.group_id
                            xxxx = serializers.CharField(source="group.title") # obj.group.title
                            x1 = serializers.CharField(source="group.mu.name") # obj.mu.name
                            # x2 = serializers.CharField(source="roles.all") # obj.mu.name
                            x2 = serializers.ListField(child=MyCharField(),source="roles.all") # obj.mu.name
    
                    解决方案三(*):
                        class UsersSerializer(serializers.Serializer):
                            name = serializers.CharField() # obj.name
                            pwd = serializers.CharField()  # obj.pwd
                            group_id = serializers.CharField() # obj.group_id
                            xxxx = serializers.CharField(source="group.title") # obj.group.title
                            x1 = serializers.CharField(source="group.mu.name") # obj.mu.name
                            # x2 = serializers.CharField(source="roles.all") # obj.mu.name
                            # x2 = serializers.ListField(child=MyCharField(),source="roles.all") # obj.mu.name
                            x2 = serializers.SerializerMethodField()
    
                            def get_x2(self,obj):
                                obj.roles.all()
                                role_list = obj.roles.filter(id__gt=1)
                                data_list = []
                                for row in role_list:
                                    data_list.append({'pk':row.pk,'name':row.name})
                                return data_list
        
                    
                    以上三种都是使用相同的视图:
                        class UsersView(APIView):
                            def get(self,request,*args,**kwargs):
                                self.dispatch
                                # 方式一:
                                # user_list = models.UserInfo.objects.all().values('name','pwd','group__id',"group__title")
                                # return Response(user_list)
    
                                # 方式二之多对象
                                user_list = models.UserInfo.objects.all()
                                # [obj1,obj2,obj3]
                                ser = UsersSerializer(instance=user_list,many=True)
                                return Response(ser.data)
    
    
                d. 基于Model
                
                    class UsersSerializer(serializers.ModelSerializer):
                        class Meta:
                            model = models.UserInfo
                            fields = "__all__"
                            # fields = ['name', 'pwd','group']
                            depth = 1
    
    
                    class UsersView(APIView):
                        def get(self,request,*args,**kwargs):
                            self.dispatch
                            # 方式一:
                            # user_list = models.UserInfo.objects.all().values('name','pwd','group__id',"group__title")
                            # return Response(user_list)
    
                            # 方式二之多对象
                            user_list = models.UserInfo.objects.all()
                            # [obj1,obj2,obj3]
                            ser = UsersSerializer(instance=user_list,many=True)
                            return Response(ser.data)
                
                
                e. 生成URL
                                    
                    class UsersSerializer(serializers.ModelSerializer):
                        group = serializers.HyperlinkedIdentityField(view_name='detail')
                        class Meta:
                            model = models.UserInfo
                            fields = "__all__"
                            fields = ['name', 'pwd','group']
                            depth = 1
    
    
                    class UsersView(APIView):
                        def get(self,request,*args,**kwargs):
                            self.dispatch
                            # 方式一:
                            # user_list = models.UserInfo.objects.all().values('name','pwd','group__id',"group__title")
                            # return Response(user_list)
    
                            # 方式二之多对象
                            user_list = models.UserInfo.objects.all()
                            # [obj1,obj2,obj3]
                            ser = UsersSerializer(instance=user_list,many=True,context={'request':request})
                            return Response(ser.data)
        
        
                f. 全局生成URL
                                    
                    class UsersSerializer(serializers.HyperlinkedModelSerializer):
                        class Meta:
                            model = models.UserInfo
                            fields = "__all__"
    
                            # fields = ['id','name','pwd']
    
                    class UsersView(APIView):
                        def get(self,request,*args,**kwargs):
                            self.dispatch
                            # 方式一:
                            # user_list = models.UserInfo.objects.all().values('name','pwd','group__id',"group__title")
                            # return Response(user_list)
    
                            # 方式二之多对象
                            user_list = models.UserInfo.objects.all()
                            # [obj1,obj2,obj3]
                            ser = UsersSerializer(instance=user_list,many=True,context={'request':request})
                            return Response(ser.data)
        
            
            请求数据验证:
            
                a.         
                    class PasswordValidator(object):
                        def __init__(self, base):
                            self.base = base
    
                        def __call__(self, value):
                            if value != self.base:
                                message = '用户输入的值必须是 %s.' % self.base
                                raise serializers.ValidationError(message)
    
                        def set_context(self, serializer_field):
                            """
                            This hook is called by the serializer instance,
                            prior to the validation call being made.
                            """
                            # 执行验证之前调用,serializer_fields是当前字段对象
                            pass
    
                    class UsersSerializer(serializers.Serializer):
                            name = serializers.CharField(min_length=6)
                            pwd = serializers.CharField(error_messages={'required': '密码不能为空'}, validators=[PasswordValidator('666')])
    
                
                b. 
                    class PasswordValidator(object):
                        def __init__(self, base):
                            self.base = base
    
                        def __call__(self, value):
                            if value != self.base:
                                message = '用户输入的值必须是 %s.' % self.base
                                raise serializers.ValidationError(message)
    
                        def set_context(self, serializer_field):
                            """
                            This hook is called by the serializer instance,
                            prior to the validation call being made.
                            """
                            # 执行验证之前调用,serializer_fields是当前字段对象
                            pass
    
                    class UsersSerializer(serializers.ModelSerializer):
                        class Meta:
                            model = models.UserInfo
                            fields = "__all__"
                            extra_kwargs = {
                                'name': {'min_length': 6},
                                'pwd': {'validators': [PasswordValidator(666), ]}
                            }
    
            
            
                使用:
                    class UsersView(APIView):
                        def get(self,request,*args,**kwargs):
                            self.dispatch
                            # 方式一:
                            # user_list = models.UserInfo.objects.all().values('name','pwd','group__id',"group__title")
                            # return Response(user_list)
    
                            # 方式二之多对象
                            user_list = models.UserInfo.objects.all()
                            # [obj1,obj2,obj3]
                            ser = UsersSerializer(instance=user_list,many=True,context={'request':request})
                            return Response(ser.data)
    
                        def post(self,request,*args,**kwargs):
                            ser = UsersSerializer(data=request.data)
                            if ser.is_valid():
                                print(ser.validated_data)
                            else:
                                print(ser.errors)
                            return Response('...')

    7.分页

            a. 基于limit offset做分页
                class P1(LimitOffsetPagination):
        
                    max_limit = 3
                    default_limit = 2
                    limit_query_param = 'limit'
                    offset_query_param = 'offset'
                            
                
                class IndexView(views.APIView):
                    def get(self,request,*args,**kwargs):
                        user_list = models.UserInfo.objects.all()
                        p1 = P1()
                        page_user_list = p1.paginate_queryset(queryset=user_list, request=request, view=self)
                        ser = IndexSerializer(instance=page_user_list, many=True)
                        return Response(ser.data) # 不含上一页和下一页
                        # return p1.get_paginated_response(ser.data) # 含上一页和下一页
                        
                class IndexView(views.APIView):
                    def get(self,request,*args,**kwargs):
                        ret = BaseResponse()
                        try:
                            user_list = models.UserInfo.objects.all()
                            p1 = P1()
                            page_user_list = p1.paginate_queryset(queryset=user_list,request=request,view=self)
                            ser = IndexSerializer(instance=page_user_list,many=True)
                            ret.data = ser.data
                            ret.next = p1.get_next_link()
                        except Exception as e:
                            ret.code= 1001
                            ret.error = 'xxxx错误'
                        return Response(ret.__dict__)
                        
            b. 基于页码的分页
                class P2(PageNumberPagination):
                    # 每页显示的数据条数
                    max_page_size = 5
                    page_size = 2
                    page_size_query_param = 'size'
    
                    # 页码
                    page_query_param = 'page'
    
            c. 基于Cursor的分页
            
                class P3(CursorPagination):
                    cursor_query_param = 'cursor'
                    page_size = 2
                    ordering = 'id'

    8.视图

    1. APIView
                    class IndexView(views.APIView):
                        def get(self, request, *args, **kwargs):
                            user_list = models.UserInfo.objects.all()
                            ser = IndexSerializer(instance=user_list,many=True)
                            return Response(ser.data)
                
                2. GenericAPIView(APIView)
                
                3. GenericViewSet(ViewSetMixin, generics.GenericAPIView)
                   
                    路由修改:
                        urlpatterns = [
                            url(r'^index/$', views.IndexView.as_view({'get':'list','post':'create'})),
                            url(r'^index/(?P<pk>d+)$', views.IndexView.as_view({'get':'retrieve'})),
                        ]
                    
                    视图修改:
                        
                        class IndexView(viewsets.GenericViewSet):
    
                            def list(self,request,*args,**kwargs):
    
                                 pass # 获取列表信息
    
                            def retrieve(self, request, *args, **kwargs):
                                pass  # 获取单条数据
    
                            def create(self,request, *args, **kwargs):
                                pass
                    
                    
                    自定义:
                        
                            增
                                POST
                                /users/
                            删
                                DELETE
                                /users/1/
                            改
                                PUT
                                /users/1/
                                
                                patch
                                /users/1/
                            查
                                GET
                                /users/ 
                                GET
                                /users/1/
                                
                            urlpatterns = [
    
                                url(r'^index/$', views.IndexView.as_view()),
                                url(r'^index/(?P<pk>d+)$', views.IndexView.as_view()),
                            ]
                                
                            class IndexView(views.APIView):
    
                                def get(self,request,*args,**kwargs):
                                    pk = kwargs.get('pk')
                                    if pk:
                                        pass # 获取单条信息
                                    else:
                                        pass # 获取列表信息
    
                                def post(self,request,*args,**kwargs):
                                    pass
    
                                def put(self,request,*args,**kwargs):
                                    pass
    
                                def patch(self,request,*args,**kwargs):
                                    pass
    
                                def delete(self,request,*args,**kwargs):
                                    pass
                                
                4. ModelViewSet(mixins.CreateModelMixin,mixins.RetrieveModelMixin,mixins.UpdateModelMixin,mixins.DestroyModelMixin,mixins.ListModelMixin,GenericViewSet)                
                    
                    class IndexView(ModelViewSet):

    9.路由

    第一类:
                # http://127.0.0.1:8000/api/v1/auth/
                url(r'^auth/$', views.AuthView.as_view()),
                # http://127.0.0.1:8000/api/v1/auth.json # 想要让页面显示json格式
                url(r'^auth.(?P<format>[a-z0-9]+)$', views.AuthView.as_view()),
                # http://127.0.0.1:8000/api/v1/auth/1/
                url(r'^auth/(?P<pk>d+)/$', views.AuthView.as_view()),
                # http://127.0.0.1:8000/api/v1/auth/1.json
                url(r'^auth/(?P<pk>d+).(?P<format>[a-z0-9]+)$', views.AuthView.as_view()),
                class AuthView(views.APIView):
    
                    def get(self,request,*args,**kwargs):
                        return Response('...')
            
            第二类:
                url(r'^index/$', views.IndexView.as_view({'get':'list','post':'create'})),
                url(r'^index/.(?P<format>[a-z0-9]+)$', views.IndexView.as_view({'get':'list','post':'create'})),
                url(r'^index/(?P<pk>d+)/$', views.IndexView.as_view({'get':'retrieve','delete':'destroy','put':'update','patch':'partial_update'})),
                url(r'^index/(?P<pk>d+).(?P<format>[a-z0-9]+)$', views.IndexView.as_view({'get':'retrieve','delete':'destroy','put':'update','patch':'partial_update'})),
    
                class IndexView(viewsets.ModelViewSet):
                    queryset = models.UserInfo.objects.all()
                    serializer_class = IndexSerializer
                    pagination_class = P2
            第三类:
                router = DefaultRouter()
                router.register('index',views.IndexViewSet)
                urlpatterns = [
                    url(r'^', include(router.urls)),
                ]
                
                
                class IndexViewSet(viewsets.ModelViewSet):
                    queryset = models.UserInfo.objects.all()
                    serializer_class = IndexSerializer
                    pagination_class = P2
                    
                    
                    
                class IndexSerializer(serializers.ModelSerializer):
                    class Meta:
                        model = models.UserInfo
                        fields = "__all__"

    10.渲染器

    class IndexView(views.APIView):
    
        # renderer_classes = [JSONRenderer,BrowsableAPIRenderer]
    
        def get(self,request,*args,**kwargs):
            self.dispatch
            user_list = models.UserInfo.objects.all()
            ser = IndexSerializer(instance=user_list,many=True)
            return Response(ser.data)
    
    urlpatterns = [
        url(r'^index/$', views.IndexView.as_view()),
        url(r'^index.(?P<format>[a-z0-9]+)$', views.IndexView.as_view()),
    ]
  • 相关阅读:
    力扣学习计划图床01
    一篇文章带你初步了解C++重载机制
    解决Github Gist无法访问问题
    VScode解决文件乱码问题,调整文件编码
    六、angular 生成二维码
    五、angularjs在进入界面前加载数据
    四、angularjs 如何在页面没有登录的情况下阻止用户通过更改url进入页面--$stateChangeStart
    三、angularjs上传图片
    二、单页应用如何调用微信接口和手机端的一些方法?
    二、Flex 布局教程:实例篇
  • 原文地址:https://www.cnblogs.com/ldq1996/p/8432776.html
Copyright © 2020-2023  润新知