Django REST framework 基本組件

来源:https://www.cnblogs.com/wangyueping/archive/2019/09/13/11470699.html
-Advertisement-
Play Games

一、序列化組件 簡單使用 開發我們的Web API的第一件事是為我們的Web API提供一種將代碼片段實例序列化和反序列化為諸如 之類的表示形式的方式。我們可以通過聲明與Django forms非常相似的序列化器(serializers)來實現。 models部分: views部分: ModelSe ...


一、序列化組件

簡單使用

開發我們的Web API的第一件事是為我們的Web API提供一種將代碼片段實例序列化和反序列化為諸如json之類的表示形式的方式。我們可以通過聲明與Django forms非常相似的序列化器(serializers)來實現。

models部分:

from django.db import models

# Create your models here.


class Book(models.Model):
    title=models.CharField(max_length=32)
    price=models.IntegerField()
    pub_date=models.DateField()
    publish=models.ForeignKey("Publish")
    authors=models.ManyToManyField("Author")
    def __str__(self):
        return self.title

class Publish(models.Model):
    name=models.CharField(max_length=32)
    email=models.EmailField()
    def __str__(self):
        return self.name

class Author(models.Model):
    name=models.CharField(max_length=32)
    age=models.IntegerField()
    def __str__(self):
        return self.name

views部分:

from rest_framework.views import APIView
from rest_framework.response import Response
from .models import *
from django.shortcuts import HttpResponse
from django.core import serializers


from rest_framework import serializers

class BookSerializers(serializers.Serializer):
    title=serializers.CharField(max_length=32)
    price=serializers.IntegerField()
    pub_date=serializers.DateField()
    publish=serializers.CharField(source="publish.name")
    #authors=serializers.CharField(source="authors.all")
    authors=serializers.SerializerMethodField()
    def get_authors(self,obj):
        temp=[]
        for author in obj.authors.all():
            temp.append(author.name)
        return temp


class BookViewSet(APIView):

    def get(self,request,*args,**kwargs):
        book_list=Book.objects.all()
        # 序列化方式1:
        # from django.forms.models import model_to_dict
        # import json
        # data=[]
        # for obj in book_list:
        #     data.append(model_to_dict(obj))
        # print(data)
        # return HttpResponse("ok")

        # 序列化方式2:
        # data=serializers.serialize("json",book_list)
        # return HttpResponse(data)

        # 序列化方式3:
        bs=BookSerializers(book_list,many=True)
        return Response(bs.data)

ModelSerializer

class BookSerializers(serializers.ModelSerializer):
      class Meta:
          model=Book
          fields="__all__"
          depth=1

提交post請求

  def post(self,request,*args,**kwargs):
       
        bs=BookSerializers(data=request.data,many=False)
        if bs.is_valid():
            # print(bs.validated_data)
            bs.save()
            return Response(bs.data)
        else:
            return HttpResponse(bs.errors)

重寫save中的create方法

class BookSerializers(serializers.ModelSerializer):

      class Meta:
          model=Book
          fields="__all__"
          # exclude = ['authors',]
          # depth=1

      def create(self, validated_data):
        
          authors = validated_data.pop('authors')
          obj = Book.objects.create(**validated_data)
          obj.authors.add(*authors)
          return obj

單條數據的get和put請求

class BookDetailViewSet(APIView):

    def get(self,request,pk):
        book_obj=Book.objects.filter(pk=pk).first()
        bs=BookSerializers(book_obj)
        return Response(bs.data)

    def put(self,request,pk):
        book_obj=Book.objects.filter(pk=pk).first()
        bs=BookSerializers(book_obj,data=request.data)
        if bs.is_valid():
            bs.save()
            return Response(bs.data)
        else:
            return HttpResponse(bs.errors)

超鏈接API:Hyperlinked

class BookSerializers(serializers.ModelSerializer):
      publish= serializers.HyperlinkedIdentityField(
                     view_name='publish_detail',
                     lookup_field="publish_id",
                     lookup_url_kwarg="pk")
      class Meta:
          model=Book
          fields="__all__"
          #depth=1

urls部分:

`urlpatterns ``=` `[``    ``url(r``'^books/$'``, views.BookViewSet.as_view(),name``=``"book_list"``),``    ``url(r``'^books/(?P<pk>\d+)$'``, views.BookDetailViewSet.as_view(),name``=``"book_detail"``),``    ``url(r``'^publishers/$'``, views.PublishViewSet.as_view(),name``=``"publish_list"``),``    ``url(r``'^publishers/(?P<pk>\d+)$'``, views.PublishDetailViewSet.as_view(),name``=``"publish_detail"``),``]`


二、視圖組件之視圖三部曲

使用混合(mixins)

上一節的視圖部分:

from rest_framework.views import APIView
from rest_framework.response import Response
from .models import *
from django.shortcuts import HttpResponse
from django.core import serializers
from rest_framework import serializers


class BookSerializers(serializers.ModelSerializer):
      class Meta:
          model=Book
          fields="__all__"
          #depth=1


class PublshSerializers(serializers.ModelSerializer):

      class Meta:
          model=Publish
          fields="__all__"
          depth=1


class BookViewSet(APIView):

    def get(self,request,*args,**kwargs):
        book_list=Book.objects.all()
        bs=BookSerializers(book_list,many=True,context={'request': request})
        return Response(bs.data)


    def post(self,request,*args,**kwargs):
        print(request.data)
        bs=BookSerializers(data=request.data,many=False)
        if bs.is_valid():
            print(bs.validated_data)
            bs.save()
            return Response(bs.data)
        else:
            return HttpResponse(bs.errors)


class BookDetailViewSet(APIView):

    def get(self,request,pk):
        book_obj=Book.objects.filter(pk=pk).first()
        bs=BookSerializers(book_obj,context={'request': request})
        return Response(bs.data)

    def put(self,request,pk):
        book_obj=Book.objects.filter(pk=pk).first()
        bs=BookSerializers(book_obj,data=request.data,context={'request': request})
        if bs.is_valid():
            bs.save()
            return Response(bs.data)
        else:
            return HttpResponse(bs.errors)


class PublishViewSet(APIView):

    def get(self,request,*args,**kwargs):
        publish_list=Publish.objects.all()
        bs=PublshSerializers(publish_list,many=True,context={'request': request})
        return Response(bs.data)


    def post(self,request,*args,**kwargs):

        bs=PublshSerializers(data=request.data,many=False)
        if bs.is_valid():
            # print(bs.validated_data)
            bs.save()
            return Response(bs.data)
        else:
            return HttpResponse(bs.errors)


class PublishDetailViewSet(APIView):

    def get(self,request,pk):

        publish_obj=Publish.objects.filter(pk=pk).first()
        bs=PublshSerializers(publish_obj,context={'request': request})
        return Response(bs.data)

    def put(self,request,pk):
        publish_obj=Publish.objects.filter(pk=pk).first()
        bs=PublshSerializers(publish_obj,data=request.data,context={'request': request})
        if bs.is_valid():
            bs.save()
            return Response(bs.data)
        else:
            return HttpResponse(bs.errors)

mixin類編寫視圖

from rest_framework import mixins
from rest_framework import generics

class BookViewSet(mixins.ListModelMixin,
                  mixins.CreateModelMixin,
                  generics.GenericAPIView):

    queryset = Book.objects.all()
    serializer_class = BookSerializers

    def get(self, request, *args, **kwargs):
        return self.list(request, *args, **kwargs)

    def post(self, request, *args, **kwargs):
        return self.create(request, *args, **kwargs)



class BookDetailViewSet(mixins.RetrieveModelMixin,
                    mixins.UpdateModelMixin,
                    mixins.DestroyModelMixin,
                    generics.GenericAPIView):
    queryset = Book.objects.all()
    serializer_class = BookSerializers

    def get(self, request, *args, **kwargs):
        return self.retrieve(request, *args, **kwargs)

    def put(self, request, *args, **kwargs):
        return self.update(request, *args, **kwargs)

    def delete(self, request, *args, **kwargs):
        return self.destroy(request, *args, **kwargs)

使用通用的基於類的視圖

通過使用mixin類,我們使用更少的代碼重寫了這些視圖,但我們還可以再進一步。REST框架提供了一組已經混合好(mixed-in)的通用視圖,我們可以使用它來簡化我們的views.py模塊。

from rest_framework import mixins
from rest_framework import generics

class BookViewSet(generics.ListCreateAPIView):

    queryset = Book.objects.all()
    serializer_class = BookSerializers

class BookDetailViewSet(generics.RetrieveUpdateDestroyAPIView):
    queryset = Book.objects.all()
    serializer_class = BookSerializers

class PublishViewSet(generics.ListCreateAPIView):

    queryset = Publish.objects.all()
    serializer_class = PublshSerializers

class PublishDetailViewSet(generics.RetrieveUpdateDestroyAPIView):
    queryset = Publish.objects.all()
    serializer_class = PublshSerializers

viewsets.ModelViewSet

urls.py:

    url(r'^books/$', views.BookViewSet.as_view({"get":"list","post":"create"}),name="book_list"),
    url(r'^books/(?P<pk>\d+)$', views.BookViewSet.as_view({
                'get': 'retrieve',
                'put': 'update',
                'patch': 'partial_update',
                'delete': 'destroy'
            }),name="book_detail"),

views.py:

class BookViewSet(viewsets.ModelViewSet):
    queryset = Book.objects.all()
    serializer_class = BookSerializers


三、認證組件

局部視圖認證

在app01.service.auth.py:

class Authentication(BaseAuthentication):

    def authenticate(self,request):
        token=request._request.GET.get("token")
        token_obj=UserToken.objects.filter(token=token).first()
        if not token_obj:
            raise exceptions.AuthenticationFailed("驗證失敗!")
        return (token_obj.user,token_obj)

在views.py:

def get_random_str(user):
    import hashlib,time
    ctime=str(time.time())

    md5=hashlib.md5(bytes(user,encoding="utf8"))
    md5.update(bytes(ctime,encoding="utf8"))

    return md5.hexdigest()


from app01.service.auth import *

from django.http import JsonResponse
class LoginViewSet(APIView):
    authentication_classes = [Authentication,]
    def post(self,request,*args,**kwargs):
        res={"code":1000,"msg":None}
        try:
            user=request._request.POST.get("user")
            pwd=request._request.POST.get("pwd")
            user_obj=UserInfo.objects.filter(user=user,pwd=pwd).first()
            print(user,pwd,user_obj)
            if not user_obj:
                res["code"]=1001
                res["msg"]="用戶名或者密碼錯誤"
            else:
                token=get_random_str(user)
                UserToken.objects.update_or_create(user=user_obj,defaults={"token":token})
                res["token"]=token

        except Exception as e:
            res["code"]=1002
            res["msg"]=e

        return JsonResponse(res,json_dumps_params={"ensure_ascii":False})

全局視圖認證組件

settings.py配置如下:

`REST_FRAMEWORK``=``{``    ``"DEFAULT_AUTHENTICATION_CLASSES"``:[``"app01.service.auth.Authentication"``,]``}`

四、許可權組件

局部視圖許可權

在app01.service.permissions.py中:

from rest_framework.permissions import BasePermission
class SVIPPermission(BasePermission):
    message="SVIP才能訪問!"
    def has_permission(self, request, view):
        if request.user.user_type==3:
            return True
        return False

在views.py:

from app01.service.permissions import *

class BookViewSet(generics.ListCreateAPIView):
    permission_classes = [SVIPPermission,]
    queryset = Book.objects.all()
    serializer_class = BookSerializers

全局視圖許可權

settings.py配置如下:

`REST_FRAMEWORK``=``{``    ``"DEFAULT_AUTHENTICATION_CLASSES"``:[``"app01.service.auth.Authentication"``,],``    ``"DEFAULT_PERMISSION_CLASSES"``:[``"app01.service.permissions.SVIPPermission"``,]``}`

五、throttle(訪問頻率)組件

局部視圖throttle

在app01.service.throttles.py中:

from rest_framework.throttling import BaseThrottle

VISIT_RECORD={}
class VisitThrottle(BaseThrottle):

    def __init__(self):
        self.history=None

    def allow_request(self,request,view):
        remote_addr = request.META.get('REMOTE_ADDR')
        print(remote_addr)
        import time
        ctime=time.time()

        if remote_addr not in VISIT_RECORD:
            VISIT_RECORD[remote_addr]=[ctime,]
            return True

        history=VISIT_RECORD.get(remote_addr)
        self.history=history

        while history and history[-1]<ctime-60:
            history.pop()

        if len(history)<3:
            history.insert(0,ctime)
            return True
        else:
            return False

    def wait(self):
        import time
        ctime=time.time()
        return 60-(ctime-self.history[-1])

在views.py中:

from app01.service.throttles import *

class BookViewSet(generics.ListCreateAPIView):
    throttle_classes = [VisitThrottle,]
    queryset = Book.objects.all()
    serializer_class = BookSerializers

全局視圖throttle

REST_FRAMEWORK={
    "DEFAULT_AUTHENTICATION_CLASSES":["app01.service.auth.Authentication",],
    "DEFAULT_PERMISSION_CLASSES":["app01.service.permissions.SVIPPermission",],
    "DEFAULT_THROTTLE_CLASSES":["app01.service.throttles.VisitThrottle",]
}

內置throttle類

在app01.service.throttles.py修改為:

class VisitThrottle(SimpleRateThrottle):

    scope="visit_rate"
    def get_cache_key(self, request, view):

        return self.get_ident(request)

settings.py設置:

REST_FRAMEWORK={
    "DEFAULT_AUTHENTICATION_CLASSES":["app01.service.auth.Authentication",],
    "DEFAULT_PERMISSION_CLASSES":["app01.service.permissions.SVIPPermission",],
    "DEFAULT_THROTTLE_CLASSES":["app01.service.throttles.VisitThrottle",],
    "DEFAULT_THROTTLE_RATES":{
        "visit_rate":"5/m",
    }
}

六、解析器

request類

django的request類和rest-framework的request類的源碼解析

局部視圖

from rest_framework.parsers import JSONParser,FormParser
class PublishViewSet(generics.ListCreateAPIView):
    parser_classes = [FormParser,JSONParser]
    queryset = Publish.objects.all()
    serializer_class = PublshSerializers
    def post(self, request, *args, **kwargs):
        print("request.data",request.data)
        return self.create(request, *args, **kwargs)

全局視圖

REST_FRAMEWORK={
    "DEFAULT_AUTHENTICATION_CLASSES":["app01.service.auth.Authentication",],
    "DEFAULT_PERMISSION_CLASSES":["app01.service.permissions.SVIPPermission",],
    "DEFAULT_THROTTLE_CLASSES":["app01.service.throttles.VisitThrottle",],
    "DEFAULT_THROTTLE_RATES":{
        "visit_rate":"5/m",
    },
    "DEFAULT_PARSER_CLASSES":['rest_framework.parsers.FormParser',]
}

七、分頁

簡單分頁

from rest_framework.pagination import PageNumberPagination,LimitOffsetPagination

class PNPagination(PageNumberPagination):
        page_size = 1
        page_query_param = 'page'
        page_size_query_param = "size"
        max_page_size = 5

class BookViewSet(viewsets.ModelViewSet):

    queryset = Book.objects.all()
    serializer_class = BookSerializers
    def list(self,request,*args,**kwargs):

        book_list=Book.objects.all()
        pp=LimitOffsetPagination()
        pager_books=pp.paginate_queryset(queryset=book_list,request=request,view=self)
        print(pager_books)
        bs=BookSerializers(pager_books,many=True)

        #return Response(bs.data)
        return pp.get_paginated_response(bs.data)

偏移分頁

from rest_framework.pagination import LimitOffsetPagination





您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 【需求:】數據從競品網站爬過來,經過分析處理之後,把結果通過網頁實時反饋給業務人員。 【應用:】2個應用: 一個是爬取數據的應用:不斷從競品網站爬數據,每次爬到的數據為一批。然後,對每一批爬到的數據進行清洗和分析,生成唯一批次號(batch_no),將分析結果持久化入庫。 一個是展示頁面:實時刷新持 ...
  • 單例模式:對於類的單例模式設計,就是採取一定的方法保證在整個軟體系統中,對某個類只能存在一個對象實例,並且該類只提供一個取得其對象實例的方法(靜態方法)。 單例模式有8種方式: 1、餓漢式(靜態常量) // 2、餓漢式(靜態代碼塊) 3、懶漢式(線程不安全) 4、懶漢式(線程安全,同步方法) 5、懶 ...
  • 前言 今天講的是結構型設計模式中的最後一個,這個模式也就是代理模式,在前段時間我寫的一篇關於正向代理和反向代理的文章。雖說此代理非彼代理。但是代理一詞還是具有相似的含義的。這裡我們繼續使用文章中的代購一個例子來講述一下代理模式吧,人不方便去購買哪些物品,這時就有一個中間人,他來購買。他代替我去購買。 ...
  • 1.nfs實現的原理解析? 2.安裝、配置、nfs服務 1.安裝 2.配置 3.根據配置進行初始化環境 4.啟動 5.客戶端測試 6.錯誤的示範 7.多個客戶端共用一個存儲伺服器 (NFS) 8.實現開機自動掛載(因為伺服器不重啟) 擴展瞭解即可 3.nfs相關的配置參數 4.rw 和 ro 2.驗 ...
  • 如何界定爬蟲的合法性,我通過翻閱大量文章、事件、分享、司法案例,總結出界定的三個關鍵點 ...
  • 併發編程 併發(偽):由於執行速度特別快,人感覺不到 並行(真):創建10個人同時操作 線程 1. 單進程,單線程的應用程式 print('666') 2. 到底什麼是線程?什麼是進程 Python自己沒有這玩意,Python中調用的操作系統的線程和進程(偽線程) 3. 多線程 工作的最小單元 共用 ...
  • 一、線程替代方案 1.subprocess (1)完全跳過線程,使用進程 (2)是派生進程的主要替代方案 (3)python2.4後引入 2.multiprocessing (1)使用threading介面派生,使用子進程 (2)允許為多核或者多CPU派生進程,介面很threading非常相似 (3 ...
  • 上一篇博客已經給大家介紹了一些演算法題,明天剛好是中秋了,這裡祝大家中秋快樂。剛好趕上數學建模了,今天就先介紹與衡量演算法水平的重要指標時間複雜度吧。在時間充裕情況下會更新5+2。之後還會介紹空間複雜度以及python內置函數的時間複雜度。 1.簡介 先看一下什麼是時間複雜度: 衡量代碼的好壞,包括兩個 ...
一周排行
    -Advertisement-
    Play Games
  • 前言 本文介紹一款使用 C# 與 WPF 開發的音頻播放器,其界面簡潔大方,操作體驗流暢。該播放器支持多種音頻格式(如 MP4、WMA、OGG、FLAC 等),並具備標記、實時歌詞顯示等功能。 另外,還支持換膚及多語言(中英文)切換。核心音頻處理採用 FFmpeg 組件,獲得了廣泛認可,目前 Git ...
  • OAuth2.0授權驗證-gitee授權碼模式 本文主要介紹如何筆者自己是如何使用gitee提供的OAuth2.0協議完成授權驗證並登錄到自己的系統,完整模式如圖 1、創建應用 打開gitee個人中心->第三方應用->創建應用 創建應用後在我的應用界面,查看已創建應用的Client ID和Clien ...
  • 解決了這個問題:《winForm下,fastReport.net 從.net framework 升級到.net5遇到的錯誤“Operation is not supported on this platform.”》 本文內容轉載自:https://www.fcnsoft.com/Home/Sho ...
  • 國內文章 WPF 從裸 Win 32 的 WM_Pointer 消息獲取觸摸點繪製筆跡 https://www.cnblogs.com/lindexi/p/18390983 本文將告訴大家如何在 WPF 裡面,接收裸 Win 32 的 WM_Pointer 消息,從消息裡面獲取觸摸點信息,使用觸摸點 ...
  • 前言 給大家推薦一個專為新零售快消行業打造了一套高效的進銷存管理系統。 系統不僅具備強大的庫存管理功能,還集成了高性能的輕量級 POS 解決方案,確保頁面載入速度極快,提供良好的用戶體驗。 項目介紹 Dorisoy.POS 是一款基於 .NET 7 和 Angular 4 開發的新零售快消進銷存管理 ...
  • ABP CLI常用的代碼分享 一、確保環境配置正確 安裝.NET CLI: ABP CLI是基於.NET Core或.NET 5/6/7等更高版本構建的,因此首先需要在你的開發環境中安裝.NET CLI。這可以通過訪問Microsoft官網下載並安裝相應版本的.NET SDK來實現。 安裝ABP ...
  • 問題 問題是這樣的:第三方的webapi,需要先調用登陸介面獲取Cookie,訪問其它介面時攜帶Cookie信息。 但使用HttpClient類調用登陸介面,返回的Headers中沒有找到Cookie信息。 分析 首先,使用Postman測試該登陸介面,正常返回Cookie信息,說明是HttpCli ...
  • 國內文章 關於.NET在中國為什麼工資低的分析 https://www.cnblogs.com/thinkingmore/p/18406244 .NET在中國開發者的薪資偏低,主要因市場需求、技術棧選擇和企業文化等因素所致。歷史上,.NET曾因微軟的閉源策略發展受限,儘管後來推出了跨平臺的.NET ...
  • 在WPF開發應用中,動畫不僅可以引起用戶的註意與興趣,而且還使軟體更加便於使用。前面幾篇文章講解了畫筆(Brush),形狀(Shape),幾何圖形(Geometry),變換(Transform)等相關內容,今天繼續講解動畫相關內容和知識點,僅供學習分享使用,如有不足之處,還請指正。 ...
  • 什麼是委托? 委托可以說是把一個方法代入另一個方法執行,相當於指向函數的指針;事件就相當於保存委托的數組; 1.實例化委托的方式: 方式1:通過new創建實例: public delegate void ShowDelegate(); 或者 public delegate string ShowDe ...