zoukankan      html  css  js  c++  java
  • 通过view实现rest api接口

    Django rest framwork之view

    基于Django的View实现Json数据的返回:

    # _*_ encoding:utf-8 _*_
    __author__ = 'LYQ'
    __data__ = '2018/8/13 15:21'
    import json
    
    from django.views.generic.base import View
    from django.http import HttpResponse,JsonResponse
    from .models import *
    
    
    class GoodsView(View):
        def get(self,request):
           good_list=Goods.objects.all()[:10]
           datas=[]
           # for good in good_list:
           #     json_dict = {}
           #     json_dict['name']=good.name
           #     json_dict['goods_desc']=good.goods_desc
           #     json_dict['category']=good.category.name
           #     json_dict['shop_price']=good.shop_price
           #     #时间不是json序列化的对象
           #     json_dict['time']=good.add_time
           #     datas.append(json_dict)
           #直接序列化
           from django.forms.models import model_to_dict
           #用来做序列化
           from django.core import serializers
           datas=[]
           for good in good_list:
               #image和datetime不能序列化
              data=model_to_dict(good)
              datas.append(data)
           datas=serializers.serialize('json',good_list)
           datas=json.loads(datas)
           # return HttpResponse(datas,content_type='application/json')
           return JsonResponse(datas,safe=False)

     Django rest framwork的简单介绍及安装(可参考官方网站):

    Django REST框架是用于构建Web API的强大而灵活的工具包。

    您可能希望使用REST框架的一些原因:

    要求

    REST框架需要以下内容:

    • Python(2.7,3.4,3.5,3.6,3.7)
    • Django(1.11,2.0,2.1)

    以下包是可选的:

    安装

    使用安装pip,包括您想要的任何可选包...

    pip install djangorestframework
    pip install markdown       # Markdown support for the browsable API.
    pip install django-filter  # Filtering support
    

    ...或者从github克隆项目。

    git clone git@github.com:encode/django-rest-framework.git

    添加'rest_framework'到您的INSTALLED_APPS设置。

    INSTALLED_APPS = (
        ...
        'rest_framework',
    )
    

    如果您打算使用可浏览的API,您可能还需要添加REST框架的登录和注销视图。将以下内容添加到根urls.py文件中。

    urlpatterns = [
        ...
        url(r'^api-auth/', include('rest_framework.urls'))
    ]
    

    请注意,URL路径可以是您想要的任何内容。

    让我们看一个使用REST框架构建一个简单的模型支持的API的快速示例。

    我们将创建一个读写API,用于访问有关项目用户的信息。

    REST框架API的任何全局设置都保存在名为的单个配置字典中REST_FRAMEWORK首先将以下内容添加到settings.py模块中:

    REST_FRAMEWORK = {
        # Use Django's standard `django.contrib.auth` permissions,
        # or allow read-only access for unauthenticated users.
        'DEFAULT_PERMISSION_CLASSES': [
            'rest_framework.permissions.DjangoModelPermissionsOrAnonReadOnly'
        ]
    }
    

    别忘了确保你也加入rest_frameworkINSTALLED_APPS我们现在准备创建我们的API了。

    注:如果出现utf8 decode的错误,把虚拟环境中的Libsite-packagespipcompat中的_init_.py的75行中的utf8改成gbk从新安装即可。

    一.ApiView方式实现api

        1.serializers:

    #form对应:Serializer,modelform:ModelSerializer
    from rest_framework import serializers
    from .models import *
    
    class GoodsSerializer(serializers.Serializer):
        name = serializers.CharField(required=True,max_length=100)
        click_num = serializers.IntegerField(default=0)
        goods_front_image=serializers.ImageField()
        add_time=serializers.DateTimeField()
    
        def create(self, validated_data):
            return Goods.objects.create(**validated_data)

        2.views:    

    from rest_framework.views import APIView
    #状态码
    from rest_framework import status
    from .models import * from .serializers import GoodsSerializer
    from rest_dramework.response import Reaponse
    class GoodsListView(APIView): """ List all snippets, or create a new snippet. """ def get(self, request, format=None): goods = Goods.objects.all()
    #many=True,goods是一个列表 goods_serializer
    = GoodsSerializer(goods, many=True) return Response(goods_serializer.data) def post(self,request,format=None): serializer=GoodsSerializer(data=request.data)
    #验证字段是否合法
    if serializer.is_valid(): serializer.save() return Response(request.data,status=status.HTTP_201_CREATED) return Response(request.data,status=status.HTTP_400_BAD_REQUEST)

        3.ModelSerializer:

    class GoodsSerializer(serializers.ModelSerializer):
        # 替换默认的category
        category = GoodsCategorySerializer()
        # 可能有多条many=True
        images = GoodsImageSerializer(many=True)
    
        class Meta:
            model = Goods
            # fields=('name','click_num','market_price','add_time','goods_front_image')
            # 外键为id,想要完整信息,嵌套Serializer
            fields = ('__all__')

    二.GenericView方式实现api接口

    from rest_framework import mixins
    from rest_framework import generics
    #基于mixins,必须重载get函数
     class GoodsListView(mixins.ListModelMixin,generics.GenericAPIView):
         """
         商品详情页
         """
         queryset = Goods.objects.all()[:10]
         serializer_class = GoodsSerializer
         #必须重写,不然默认无法接受get请求
         def get(self, request, *args, **kwargs):
             return self.list(request, *args, **kwargs)

    三.Viewset和router实现api接口和配置

        1.viewset中的view:

        2.GenericViewset:

        继承了ViewSetMixin和GenericAPIView,ViewSetMixin重写了as_view方法,initialize_request方法,initialize_request方法设置了很多action,在动态使用serializer时有很多的好处

    class ViewSetMixin(object):
        """
        This is the magic.
    
        Overrides `.as_view()` so that it takes an `actions` keyword that performs
        the binding of HTTP methods to actions on the Resource.
    
        For example, to create a concrete view binding the 'GET' and 'POST' methods
        to the 'list' and 'create' actions...
    
        view = MyViewSet.as_view({'get': 'list', 'post': 'create'})
        """
    
        @classonlymethod
        def as_view(cls, actions=None, **initkwargs):
            """
            Because of the way class based views create a closure around the
            instantiated view, we need to totally reimplement `.as_view`,
            and slightly modify the view function that is created and returned.
            """
            # The suffix initkwarg is reserved for displaying the viewset type.
            # eg. 'List' or 'Instance'.
            cls.suffix = None
    
            # The detail initkwarg is reserved for introspecting the viewset type.
            cls.detail = None
    
            # Setting a basename allows a view to reverse its action urls. This
            # value is provided by the router through the initkwargs.
            cls.basename = None
    
            # actions must not be empty
            if not actions:
                raise TypeError("The `actions` argument must be provided when "
                                "calling `.as_view()` on a ViewSet. For example "
                                "`.as_view({'get': 'list'})`")
    
            # sanitize keyword arguments
            for key in initkwargs:
                if key in cls.http_method_names:
                    raise TypeError("You tried to pass in the %s method name as a "
                                    "keyword argument to %s(). Don't do that."
                                    % (key, cls.__name__))
                if not hasattr(cls, key):
                    raise TypeError("%s() received an invalid keyword %r" % (
                        cls.__name__, key))
    
            def view(request, *args, **kwargs):
                self = cls(**initkwargs)
                # We also store the mapping of request methods to actions,
                # so that we can later set the action attribute.
                # eg. `self.action = 'list'` on an incoming GET request.
                self.action_map = actions
    
                # Bind methods to actions
                # This is the bit that's different to a standard view
                for method, action in actions.items():
                    handler = getattr(self, action)
                    setattr(self, method, handler)
    
                if hasattr(self, 'get') and not hasattr(self, 'head'):
                    self.head = self.get
    
                self.request = request
                self.args = args
                self.kwargs = kwargs
    
                # And continue as usual
                return self.dispatch(request, *args, **kwargs)
    
            # take name and docstring from class
            update_wrapper(view, cls, updated=())
    
            # and possible attributes set by decorators
            # like csrf_exempt from dispatch
            update_wrapper(view, cls.dispatch, assigned=())
    
            # We need to set these on the view function, so that breadcrumb
            # generation can pick out these bits of information from a
            # resolved URL.
            view.cls = cls
            view.initkwargs = initkwargs
            view.suffix = initkwargs.get('suffix', None)
            view.actions = actions
            return csrf_exempt(view)
    
        def initialize_request(self, request, *args, **kwargs):
            """
            Set the `.action` attribute on the view, depending on the request method.
            """
            request = super(ViewSetMixin, self).initialize_request(request, *args, **kwargs)
            method = request.method.lower()
            if method == 'options':
                # This is a special case as we always provide handling for the
                # options method in the base `View` class.
                # Unlike the other explicitly defined actions, 'metadata' is implicit.
                self.action = 'metadata'
            else:
                self.action = self.action_map.get(method)
            return request
    
        def reverse_action(self, url_name, *args, **kwargs):
            """
            Reverse the action for the given `url_name`.
            """
            url_name = '%s-%s' % (self.basename, url_name)
            kwargs.setdefault('request', self.request)
    
            return reverse(url_name, *args, **kwargs)
    
        @classmethod
        def get_extra_actions(cls):
            """
            Get the methods that are marked as an extra ViewSet `@action`.
            """
            return [method for _, method in getmembers(cls, _is_extra_action)]

        3.继承genericviewset的view写法:

          GenericViewSet继承于GnericAPIView,没有重写get,post等方法,因此还需要继承mixin

    class GoodsListViewSet(mixins.ListModelMixin,mixins.RetrieveModelMixin,viewsets.GenericViewSet):
        """
        商品详情页,分页,搜索,过滤,排序
        """
        #配置ip限制访问次数
        throttle_classes = (UserRateThrottle,AnonRateThrottle)
        queryset = Goods.objects.all()
        serializer_class = GoodsSerializer
        #分页
        pagination_class = GoodsPagination
        #配置认证类,防止公开网页(未登录可查看)不能访问
        # authentication_classes = (TokenAuthentication,)
        filter_backends=(DjangoFilterBackend,filters.SearchFilter,filters.OrderingFilter)
        #字段过滤(DjangoFilterBackend)
        # filter_fields = ('name', 'shop_price')
        filter_class=GoodsFilter
        #搜索过滤(rest_framework.filters.SearchFilter)
        search_fields = ('name','goods_brief','goods_desc')
        #排序过滤(rest_frameworkfilters.OrderingFilter)
        ordering_fields = ('sold_num', 'shop_price')
    
        def retrieve(self, request, *args, **kwargs):
            instance = self.get_object()
            instance.click_num+=1
            instance.save()
            serializer = self.get_serializer(instance)
            return Response(serializer.data)

         viewset和router配套使用:

          第一种:配置url:

     1 #在url.py文件中  
     2 #配置GoodsListViewSet
     3  good_list=GoodsListViewSet.as_view({
     4 #把get请求绑定到list方法上
     5          'get':'list',
     6      })
     7 urlpatterns = [
     8 #把good_list放入url中
     9  url('^goods/$',good_list,name='good_list'),
    11 ]  

            第二种:(使用router)

    from rest_framework.routers import DefaultRouter
    
    router = DefaultRouter()
    # 配置goods的url
    router.register(r'goods', GoodsListViewSet, base_name='goods')
    #在调用router.urls时会自动把router中转换为url配置
    urlpatterns = [
    url('^', include(router.urls)),
    ]

    四.View继承关系

        1.View继承关系(差异就是不同的mixin):

            GnericViewSet(drf)【比GnericAPIView继承增加了一个ViewSetMixin,在url中绑定了,router可以使用,还有实现了initialize_request方法设置了很多action方便不同serializer的使用】———>GnericAPIView(drf)【增加了筛选过滤分页,serializer等】———>APIView(drf)———>View(django)

        2.mixin:

      CreateModelMixin

      ListModelMixin

      RetrieveModelMixin

      UpdateModelMixin

      DestroyModelMIxin

      意境定制好了的view组合(继承GericAPIView不同的mixin实现不同的功能):

  • 相关阅读:
    js---选择排序
    js----冒泡排序
    js---快速排序
    js---去重方法(二)
    js---去重方法(一)
    js--进度条
    随机生成6位数验证码
    倒计时
    别踩白块
    贪吃蛇小游戏
  • 原文地址:https://www.cnblogs.com/lyq-biu/p/9625896.html
Copyright © 2011-2022 走看看