1. Serialization components
Simple use
The first thing to develop our Web API is to provide a way for our Web API to serialize and deserialize code snippet instances into representations such as json.We can do this by declaring serializers that are very similar to Django forms.
models section:
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 section:
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() # Serialization method 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") # Serialization mode 2: # data=serializers.serialize("json",book_list) # return HttpResponse(data) # Serialization mode 3: bs=BookSerializers(book_list,many=True) return Response(bs.data)
ModelSerializer
class BookSerializers(serializers.ModelSerializer): class Meta: model=Book fields="__all__" depth=1
Submit post request
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)
Override create method in save
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 and put requests for single data
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)
Hyperlink API:Hyperlink
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
The urls section:
`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"``),``]`
2. View Trilogy of View Components
Use mixins
View section of the previous section:
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 class authoring view
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)
Use a generic class-based view
By using the mixin class, we override these views with less code, but we can go further.The REST framework provides a set of mixed-in common views that we can use to simplify our views.py module.
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
3. Authentication components
Local View Authentication
In 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("Validation failed!") return (token_obj.user,token_obj)
In 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"]="User name or password error" 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})
Global View Authentication Component
The settings.py configuration is as follows:
`REST_FRAMEWORK``=``{`` ``"DEFAULT_AUTHENTICATION_CLASSES"``:[``"app01.service.auth.Authentication"``,]``}`
IV. Permission Components
Local View Permissions
In app01.service.permissions.py:
from rest_framework.permissions import BasePermission class SVIPPermission(BasePermission): message="SVIP Can access!" def has_permission(self, request, view): if request.user.user_type==3: return True return False
In views.py:
from app01.service.permissions import * class BookViewSet(generics.ListCreateAPIView): permission_classes = [SVIPPermission,] queryset = Book.objects.all() serializer_class = BookSerializers
Global View Permissions
The settings.py configuration is as follows:
`REST_FRAMEWORK``=``{`` ``"DEFAULT_AUTHENTICATION_CLASSES"``:[``"app01.service.auth.Authentication"``,],`` ``"DEFAULT_PERMISSION_CLASSES"``:[``"app01.service.permissions.SVIPPermission"``,]``}`
5. throttle components
Local view throttle
In 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])
In views.py:
from app01.service.throttles import * class BookViewSet(generics.ListCreateAPIView): throttle_classes = [VisitThrottle,] queryset = Book.objects.all() serializer_class = BookSerializers
Global view throttle
REST_FRAMEWORK={ "DEFAULT_AUTHENTICATION_CLASSES":["app01.service.auth.Authentication",], "DEFAULT_PERMISSION_CLASSES":["app01.service.permissions.SVIPPermission",], "DEFAULT_THROTTLE_CLASSES":["app01.service.throttles.VisitThrottle",] }
Built-in throttle class
In app01.service.throttles.py, change to:
class VisitThrottle(SimpleRateThrottle): scope="visit_rate" def get_cache_key(self, request, view): return self.get_ident(request)
settings.py settings:
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", } }
6. Parser
request class
Source code resolution for django's request class and rest-framework's request class
Local View
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)
Global View
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',] }
7. Paging
Simple Paging
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)
Offset Paging
from rest_framework.pagination import LimitOffsetPagination