【Django】Django RestFramework框架

  • 2020 年 2 月 14 日
  • 笔记

Install RestFramework

$ pip install djangorestframework    # settings.py  INSTALLED_APPS = (  	...  	'rest_framework',  )

创建Serializer class

from rest_framework import serializers  from .models import Book, Author, Publisher    class AuthorSerializer(serializers.Serializer):  	id = serializers.IntegerField(read_only=True)  	first_name = serializers.CharField(max_length=100)  	last_name = serializers.CharField(required=False, allow_blank=True, max_length=100)  	email = serializers.EmailField(required=False, allow_blank=True, max_length=100)    	def create(self, validated_data):  		# Create and return a new 'Snippet' instance, given the validated data.  		return Author.objects.create(**validated_data)    	def update(self, instance, validated_data):  		instance.first_name = validated_data.get('first_name', instance.first_name)  		instance.last_name = validated_data.get('last_name', instance.last_name)  		instance.email = validated_data.get('email', instance.email)  		instance.save()  		return instance

使用提供的API

>>> from books.serializers import *  >>> from rest_framework.renderers import JSONRenderer  >>> from rest_framework.parsers import JSONParser  >>> g = Author.objects.create(first_name='guang', last_name='hongwei', email='[email protected]')  >>> m = Author.objects.create(first_name='ma', last_name='ge', email='[email protected]')  >>> serializer = AuthorSerializer(g)  >>> serializer.data  ReturnDict([('id', 1),  			('first_name', u'guang'),  			('last_name', u'hongwei'),  			('email', u'[email protected]')])  >>> content = JSONRenderer().render(serializer.data)  >>> content  '{"id": 1, "first_name": "guang", "last_name": "hongwei", "email": "[email protected]"}'    >>> from django.utils.six import BytesIO  >>> content = '{"first_name": "li", "last_name": "xueming", "email": "[email protected]"}'  >>> stream = BytesIO(content)  >>> data = JSONParser().parse(stream)  >>> data  {u'email': u'[email protected]', u'first_name': u'li', u'last_name': u'xueming'}  >>> serializer = AuthorSerializer(data=data)  >>> serializer.is_valid()  >>> serializer.data								# 不是Python类型  ReturnDict([('first_name', 'li'),  			('last_name', 'xueming'),  			('email', '[email protected]')])  >>> serializer.validated_data					# 转化成Python类型  OrderedDict([('first_name', 'li'),  			 ('last_name', 'xueming'),  			 ('email', '[email protected]')])  >>> serializer.save()    >>> serializer = AuthorSerializer(Author.objects.all(), many=True)  >>> serializer.data

使用ModelSerializers

class AuthorSerializer(serializers.ModelSerializer):  	class Meta:  		model = Author  		fields = ('id', 'first_name', 'last_name', 'email')

API Function View

from django.http import HttpResponse  from django.http import HttpResponse  from django.views.decorators.csrf import csrf_exempt  from rest_framework.renderers import JSONRenderer  from rest_framework.parsers import JSONParser  from .models import Author  from .serializers import AuthorSerializer    class JSONResponse(HttpResponse):  	# An HttpResponse that renders its content into JSON.  	def __init__(self, data, **kwargs):  		content = JSONRenderer().render(data)  		kwargs['content-type'] = 'application/json'  		super(JSONResponse, self).__init__(content, **kwargs)    @csrf_exempt  def author_list(request):  	if request.method == 'GET':  		authors = Author.objects.all()  		serializer = AuthorSerializer(authors, many=True)  		return JSONResponse(serializer.data)  	elif request.method == 'POST':  		data = JSONParser().parse(request)  		serializer = AuthorSerializer(data=data)  		if serializer.is_valid():  			serializer.save()  			return JSONResponse(serializer.data, status=201)  		return JSONResponse(serializer.errors, status=400)    @csrf_exempt  def author_detail(request, pk):  	# Retrieve, update or delete a code snippet.  	try:  		author = Author.objects.get(pk=pk)  	except Author.DoesNotExist:  		return JSONResponse('', status=404)    	if request.method == 'GET':  		serializer = AuthorSerializer(author)  		return JSONResponse(serializer.data)  	elif request.method == 'PUT':  		data = JSONParser().parse(request)  		serializer = AuthorSerializer(author, data=data)  		if serializer.is_valid():  			serializer.save()  			return JSONResponse(serializer.data)  		return JSONResponse(serializer.errors, status=400)  	elif request.method == 'DELETE':  		author.delete()  		return JSONResponse('', status=204)    # urls.py  urlpatterns = [  	url(r'^authors/$', views.author_list, name='author_list'),  	url(r'^authors/(?P<pk>[0-9]+)/$', views.author_detail, name='author_detail'),  ]

Request And Response

  • request
    • request.POST # Only handles form data. Only works for ‘POST’ method.
    • request.data # Handles arbitrary data. Works for ‘POST’, ‘PUT’ and ‘PATCH’ methods.
  • Response(data) # Renders to content type as requested by the client.

包装API View

from rest_framework.decorators import api_view  ...  @api_view(['GET', 'POST'])  def author_list(request):  	pass

使用Class-based Views

from django.http import Http404  from rest_framework.views import APIView  from rest_framework.response import Response  from rest_framework import status    class AuthorList(APIView):  	def get(self, request, format=None):  		authors = Author.objects.all()  		serializer = AuthorSerializer(authors, many=True)  		return Response(serializer.data)    	def post(self, request, format=None):  		serializer = AuthorSerializer(data=request.data)  		if serializer.is_valid():  			serializer.save()  			return Response(serializer.data, status=status.HTTP_201_CREATED)  		return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)    class AuthorDetail(APIView):  	def get_object(self, pk):  		try:  			return Author.objects.get(pk=pk)  		except Author.DoesNotExist:  			return Http404    	def get(self, request, pk, format=None):  		author = self.get_object(pk)  		serializer = AuthorSerializer(author)  		return Response(serializer.data)    	def put(self, request, pk, format=None):  		author = self.get_object(pk)  		serializer = AuthorSerializer(author, data=request.data)  		if serializer.is_valid():  			serializer.save()  			return Response(serializer.data)  		return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)    	def delete(self, request, pk, format=None):  		author = self.get_object(pk)  		author.delete()  		return Response(status=status.HTTP_204_NO_CONTENT)
  • APIView

使用Mixin

from rest_framework import mixins  # from rest_framework.mixins import CreateModelMixin, ListModelMixin  from rest_framework import generics    class AuthorList(mixins.ListModelMixin, mixins.CreateModelMixin, generics.GenericAPIView):  	queryset = Author.objects.all()  	serializer_class = AuthorSerializer    	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 AuthorDetail(mixins.RetrieveModelMixin, mixins.UpdateModelMixin, mixins.DestroyModelMixin, generics.GenericAPIView):  	queryset = Author.objects.all()  	serializer_class = AuthorSerializer    	def get(self, request, *args, **kwargs):  		return self.retrieve(request, *args, **kwargs)    	def post(self, request, *args, **kwargs):  		return self.create(request, *args, **kwargs)    class AuthorDetail(mixins.RetrieveModelMixin, mixins.UpdateModelMixin, mixins.DestroyModelMixin, generics.GenericAPIView):  	queryset = Author.objects.all()  	serializer_class = AuthorSerializer    	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)

使用Generic class-based views

...  from rest_framework import generics    class AuthorList(generics.ListCreateAPIView):  	queryset = Author.objects.all()  	serializer_class = AuthorSerializer    class AuthorDetail(generics.RetrieveUpdateDestroyAPIView):  	queryset = Author.objects.all()  	serializer_class = AuthorSerializer

分页

# settings.py  REST_FRAMEWORK = {  	'PAGE_SIZE': 10  }

认证授权

详见:http://www.django-rest-framework.org/api-guide/permissions/#api-reference

  • rest framework内置权限
    • AllowAny
    • IsAuthenticated
    • IsAdminUser
    • IsAuthenticatedOrReadOnly
    • DjangoModelPermissions
    • DjangoModelPermissionsOrAnonReadOnly
    • DjangoObjectPermissions
  • 全局配置默认权限
# settings.py  REST_FRAMEWORK = {  	'DEFAULT_PERMISSION_CLASSES': (  		'rest_framework.permissions.IsAuthenticated',  	)  }
  • view中使用鉴权
# views.py  from rest_framework import permissions    class UserList(generics.ListAPIView):  	queryset = User.objects.all()  	serializer_class = UserSerializer  	permission_classes = (permissions.IsAuthenticated, )
  • 自定义权限
from rest_framework import permissions    class IsSuperUser(permissions.BasePermission):  	def has_permission(self, request, view):  		return request.user.is_superuser()    # views  from .permissions import IsSuperUser    class UserList(generics.ListAPIView):  	queryset = User.objects.all()  	serializer_class = UserSerializer  	permission_classes = (IsSuperUser,)
  • Django支持认证方式
    • Basic认证
    • Session认证
    • Token认证
    • 自定义认证

djangorestframework默认是使用Basic认证

# settings.py  REST_FRAMEWORK = {  	'DEFAULT_AUTHENTICATION_CLASSES': (  		'rest_framework.authentication.BasicAuthentication',  		# 'rest_framework.authentication.SessionAuthentication',  	)  }
  • 使用Basic认证 postman请求,填写Authorization,用户名admin,密码django user admin的密码
  • 使用token认证
    • INSTALLED_APPS加入rest_framework.authtoken

    INSTALLED_APPS = ( … 'rest_framework.authtoken' )

    • 启用TOKEN认证

    REST_FRAMEWORK = { 'DEFAULT_AUTHENTICATION_CLASSES': ( 'rest_framework.authentication.BasicAuthentication', 'rest_framework.authentication.TokenAuthentication', ) }

    • 创建token

    >>> from rest_framework.authtoken.models import Token >>> token = Token.objects.create(user=…) >>> print(token.key)

    • 使用Token请求postman,设置Authorization头

    Authorization:Token 9944b09199c62bcf9418ad846dd0e4bbdfc6ee4b

Viewset和Router

# views.py  from rest_framework import viewsets  from .models import Author  from .serializers import AuthorSerializer    # version 1  class AuthorViewSet(viewsets.ReadOnlyModelViewSet):  	# This viewset automatically provides 'list' and 'detail' actions.  	queryset = Author.objects.all()  	serializer_class = AuthorSerializer    # version 2  class AuthorViewSet(viewsets.ModelViewSet):  	# This viewset automatically provides 'list', 'create', 'retrieve', 'update' and 'destroy' actions.  	queryset = Author.objects.all()  	serializer_class = AuthorSerializer  	permission_classes = (permissions.IsAuthenticationOrReadOnly,)    #urls.py  from . import views  from rest_framework import renders    # version 1  author_list = AuthorViewSet.as_view({  	'get': 'list',  	'post': 'create',  })  author_detail = AuthorViewSet.as_view({  	'get': 'retrieve',  	'put': 'update',  	'patch': 'partial_update',  	'delete': 'destroy',  })  urlpatterns += [  	url(r'^authors/$', author_list, name='author-list'),  	url(r'^authors/(?P<pk>[0-9]+)/$', author_detail, name='author-detail'),  ]    # version 2 user Routers  from django.conf.urls import url, include  from rest_framework.routers import DefaultRouter    router = DefaultRouter()  router.register(r'authors', views.AuthorViewSet)    urlpatterns = [  	url(r'^publisher/(?P<pk>[0-9]+)/$', views.PublisherDetail.as_view()),  ]    urlpatterns += [  	url(r'^', include(router.urls)),  ]  urlpatterns += router.urls

Django RestFramework框架应用

跳板机:是一台服务器,运维人员在维护过程中首先要统一登录到这台服务器,然后再登录到目标设备进行维护和操作。在腾讯,跳板机是开发者登录到服务器的唯一途径,开发者必须先登录跳板机,再通过跳板机登录到应用服务器。 堡垒机:堡垒机的理念起源于跳板机,但是可以进行: (1)核心系统运维和安全审计管控; (2)过滤和拦截非法访问、恶意攻击,阻断不合法命令,审计监控、报警、责任追踪; (3)报警、记录、分析、处理。 堡垒机核心功能:单点登录功能、账号管理、身份认证、资源授权、访问控制、操作审计。