經過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的強大而靈活的工具包。git

您可能但願使用REST框架的一些緣由:github

要求

REST框架須要如下內容:django

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

如下包是可選的:json

 

安裝

使用安裝pip,包括您想要的任何可選包...api

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

...或者從github克隆項目。markdown

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

添加'rest_framework'到您的INSTALLED_APPS設置。架構

INSTALLED_APPS = ( ... 'rest_framework', ) 

若是您打算使用可瀏覽的API,您可能還須要添加REST框架的登陸和註銷視圖。將如下內容添加到根urls.py文件中。app

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

請注意,URL路徑能夠是您想要的任何內容。框架

讓咱們看一個使用REST框架構建一個簡單的模型支持的API的快速示例。ide

咱們將建立一個讀寫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的錯誤,把虛擬環境中的\Lib\site-packages\pip\compat中的_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實現不一樣的功能):

相關文章
相關標籤/搜索