当前位置: 首页 > 工具软件 > Django Cool > 使用案例 >

【Django】Django RestFramework框架

吴宏扬
2023-12-01

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='ibuler@qq.com')
>>> m = Author.objects.create(first_name='ma', last_name='ge', email='ma@magedu.com')
>>> serializer = AuthorSerializer(g)
>>> serializer.data
ReturnDict([('id', 1),
			('first_name', u'guang'),
			('last_name', u'hongwei'),
			('email', u'ibuler@qq.com')])
>>> content = JSONRenderer().render(serializer.data)
>>> content
'{"id": 1, "first_name": "guang", "last_name": "hongwei", "email": "ibuler@qq.com"}'

>>> from django.utils.six import BytesIO
>>> content = '{"first_name": "li", "last_name": "xueming", "email": "comyn@magedu.com"}'
>>> stream = BytesIO(content)
>>> data = JSONParser().parse(stream)
>>> data
{u'email': u'comyn@magedu.com', 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', 'comyn@magedu.com')])
>>> serializer.validated_data					# 转化成Python类型
OrderedDict([('first_name', 'li'),
			 ('last_name', 'xueming'),
			 ('email', 'comyn@magedu.com')])
>>> 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认证
    • 自定义认证

Django RestFramework默认是使用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)报警、记录、分析、处理。
堡垒机核心功能:单点登录功能、账号管理、身份认证、资源授权、访问控制、操作审计。

 类似资料: