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()),
]
原文地址:https://www.cnblogs.com/ldq1996/p/8432776.html