目錄
serializers.ModelSerializer:... 3
rest_framework.request.Request和rest_framework.response.Response:... 5
rest_framework.decorators.api_view和rest_framework.views.APIView:... 5
api CBV,rest_framework.views.APIView:... 6
api CBV,使用rest_framework.mixins:... 7
api CBV,使用generics.ListCreateAPIView和generics.RetrieveUpdateDestroyAPIView:... 8
django rest framework
是django用來restful api的框架,風格完全和django一樣,使用起來像是django本身提供的;
https://www.django-rest-framework.org/
(webproject) C:\webproject\mysite>pip install djangorestframework
INSTALLED_APPS = [
'rest_framework',
serializers.Serializer
rest_framework.serializers.Serializer和django.forms.Form:
功能一樣,都是將用戶提交的數據轉爲py數據結構,可用此來完成校驗;
Form用在post提交中的form表單;
Serializer用在用戶提交的json;
from rest_framework import serializers
from .models import Author
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):
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
底層實現:
>>> from books.serializer import AuthorSerializer
>>> from rest_framework.renderers import JSONRenderer #py結構-->json
>>> from rest_framework.parsers import JSONParser #json-->py結構
>>> from books.models import Author
>>> Author.objects.all()
<QuerySet [<Author: chai jowin>, <Author: dsfdfd sfdsfdsf>]>
>>> a = Author.objects.get(id=1)
>>> s = AuthorSerializer(a)
>>> s.data #dict
{'last_name': 'jowin', 'email': '[email protected]', 'id': 1, 'first_name': 'chai'}
>>> content = JSONRenderer().render(s.data)
>>> content
b'{"id":1,"first_name":"chai","last_name":"jowin","email":"[email protected]"}'
>>> from django.utils.six import BytesIO
>>> stream = BytesIO(content)
>>> stream
<_io.BytesIO object at 0x00000000046389E8>
>>> data = JSONParser().parse(stream)
>>> data
{'last_name': 'jowin', 'email': '[email protected]', 'id': 1, 'first_name': 'chai'}
>>> s = AuthorSerializer(data=data)
>>> s
AuthorSerializer(data={'last_name': 'jowin', 'email': '[email protected]', 'id': 1, 'first_name': 'chai'}):
id = IntegerField(read_only=True)
first_name = CharField(max_length=100)
last_name = CharField(allow_blank=True, max_length=100, required=False)
email = EmailField(allow_blank=True, max_length=100, required=False)
>>> s.is_valid()
True
>>> s.validated_data #返回ordereddict
OrderedDict([('first_name', 'chai'), ('last_name', 'jowin'), ('email', '[email protected]')])
>>> s.save()
<Author: chai jowin>
>>> Author.objects.all()
<QuerySet [<Author: chai jowin>, <Author: dsfdfd sfdsfdsf>, <Author: chai jowin>]>
>>> s = AuthorSerializer(Author.objects.all(), many=True) #序列化多個對象時要加many=True,調用many_init()
>>> s.data
[OrderedDict([('id', 1), ('first_name', 'chai'), ('last_name', 'jowin'), ('email', '[email protected]')]), OrderedDict([('id', 2), ('first_name', 'dsfdfd'), ('la
st_name', 'sfdsfdsf'), ('email', '[email protected]')]), OrderedDict([('id', 3), ('first_name', 'chai'), ('last_name', 'jowin'), ('email', '[email protected]')])
]
serializers.ModelSerializer:
rest_framework.serializers.ModelSerializer同django.forms.ModelForm;
class AuthorSerializer(serializers.ModelSerializer):
class Meta:
model = Author
fields = ['id', 'first_name', 'last_name', 'email']
api FBV:
from django.http import HttpResponse
from rest_framework.renderers import JSONRenderer
from rest_framework.parsers import JSONParser
from .serializer import AuthorSerializer
from .models import Author
from django.views.decorators.csrf import csrf_exempt
class JSONResponse(HttpResponse): #可用django.http.JsonResponse
def __init__(self, data, **kwargs):
content = JSONRenderer().render(data)
kwargs['content_type'] = 'application/json'
super(JSONResponse, self).__init__(content, **kwargs) #同super().__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, safe=False) # 默認safe=True,In order to allow non-dict objects to be serialized set the safe parameter to False.
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):
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)
url(r'^authors/$', api.author_list, name='author_list'),
url(r'^authors/(?P<pk>[0-9]+)/$', api.author_detail, name='author_detail'),
rest_framework.request.Request和rest_framework.response.Response:
request.POST # Only handles form data. Only works for 'POST' method.
request.data # Handles arbitrary data. Works for 'POST', 'PUT' and 'PATCH' methods.
return Response(data) # Renders to content type as requested by the client.根據客戶端的請求渲染內容類型
rest_framework.decorators.api_view和rest_framework.views.APIView:
The @api_view decorator for working with function based views.
The APIView class for working with class-based views. #同django.views.View
例,@api_view:
@api_view(['GET', 'POST']) #只作爲接口使用,用browser訪問報WrappedAttributeError,'CSRFCheck' object has no attribute 'process_request'
@csrf_exempt
def author_list(request):
if request.method == 'GET':
authors = Author.objects.all()
serializer = AuthorSerializer(authors, many=True)
# return JSONResponse(serializer.data)
# return JsonResponse(serializer.data, safe=False)
return Response(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 Response(serializer.data, status=201)
# return JsonResponse(serializer.errors, status=400)
return Response(serializer.errors, status=400)
用postman測GET和POST;
api CBV,rest_framework.views.APIView:
from rest_framework.views import APIView
from rest_framework import status
from django.http import Http404
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)
# url(r'^authors/$', api.author_list, name='author_list'),
url(r'^authors/$', AuthorList.as_view()),
# url(r'^authors/(?P<pk>[0-9]+)/$', api.author_detail, name='author_detail'),
url(r'^authors/(?P<pk>[0-9]+)/$', AuthorDetail.as_view()),
api CBV,使用rest_framework.mixins:
from rest_framework import mixins
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 put(self, request, *args, **kwargs):
return self.update(request, *args, **kwargs)
def delete(self, request, *args, **kwargs):
return self.destroy(request, *args, **kwargs)
api CBV,使用generics.ListCreateAPIView和generics.RetrieveUpdateDestroyAPIView:
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
postman測試時,PUT方法注意要用JSON;
分頁:
REST_FRAMEWORK = {
# 'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.PageNumberPagination',
'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.LimitOffsetPagination',
"PAGE_SIZE": 2,
認證:
django支持認證方式:
Basic,默認;
Session;
Token;
自定義認證;
默認用Basic認證,輸入Username和Password,會自動生成到Headers中,用base64加密;
例,使用token認證:
INSTALLED_APPS = [
'rest_framework.authtoken',
REST_FRAMEWORK = {
"DEFAULT_AUTHENTICATION_CLASSES": (
# 'rest_framework.authentication.BasicAuthentication',
# 'rest_framework.authentication.SessionAuthentication',
'rest_framework.authentication.TokenAuthentication',
)
}
(webproject) C:\webproject\mysite>python manage.py makemigrations
(webproject) C:\webproject\mysite>python manage.py migrate
>>> from django.contrib.auth.models import User
>>> from rest_framework.authtoken.models import Token
>>> t = Token.objects.create(user=User.objects.get(id=1))
>>> t.key
'219c0ec96617256b93b36d0ab95b70e7c893ac1b'
例,用session認證:
KEY中Cookie,VALUE中粘貼網頁中Network中csrftoken;
授權:
https://www.django-rest-framework.org/api-guide/permissions/#api-reference
rest_framework內置權限:
AllowAny
IsAuthenticated
IsAdminUser
IsAuthenticatedOrReadOnly
DjangoModelPermissions
DjangoModelPermissionsOrAnonReadOnly
DjangoObjectPermissions
REST_FRAMEWORK = {
"PAGE_SIZE": 1,
"DEFAULT_AUTHENTICATION_CLASSES": (
# 'rest_framework.authentication.BasicAuthentication',
# 'rest_framework.authentication.SessionAuthentication',
'rest_framework.authentication.TokenAuthentication',
'rest_framework.permissions.IsAuthenticated', #全局配置默認權限
)
}
例,view中使用權限控制:
from rest_framework import generics
from rest_framework import permissions
class AuthorList(generics.ListCreateAPIView):
queryset = Author.objects.all()
serializer_class = AuthorSerializer
permission_classes = (permissions.IsAuthenticated,) #多個是and的關係
例,自定義權限:
from rest_framework import generics
from rest_framework import permissions
class IsSuperUser(permissions.BasePermission): #繼承permissions.BasePermission,重寫has_permission()
def has_permission(self, request, view):
return request.user.is_superuser()
class AuthorList(generics.ListCreateAPIView):
queryset = Author.objects.all()
serializer_class = AuthorSerializer
# permission_classes = (permissions.IsAuthenticated,)
permission_classes = (IsSuperUser,)
rest_framework.viewsets和rest_framework.routers.DefaultRouter:
ViewSet與View,不同之處在於ViewSet提供read或update之類的操作,而不是get或put等方法處理程序;當它被實例化成一組視圖的時候,通過使用Router類來處理自己定義的url;
例:
from rest_framework import viewsets
class AuthorViewSet(viewsets.ReadOnlyModelViewSet): #僅提供list和detail操作
queryset = Author.objects.all()
serializer_class = AuthorSerializer
# permission_classes = (permissions.IsAuthenticatedOrReadOnly,)
例:
from rest_framework import viewsets
class AuthorViewSet(viewsets.ModelViewSet): #提供list|create|retrieve|update|destroy
queryset = Author.objects.all()
serializer_class = AuthorSerializer
# permission_classes = (permissions.IsAuthenticatedOrReadOnly,)
author_list = AuthorViewSet.as_view({
'get': 'list',
'post': 'create'
})
author_detail = AuthorViewSet.as_view({
'get': 'retrieve',
'put': 'update',
'pathch': 'partial_update',
'delete': 'destroy',
})
# url(r'^authors/$', api.author_list, name='author_list'),
# url(r'^authors/$', AuthorList.as_view()),
url(r'^authors/$', author_list, name='author-list'),
# url(r'^authors/(?P<pk>[0-9]+)/$', api.author_detail, name='author_detail'),
# url(r'^authors/(?P<pk>[0-9]+)/$', AuthorDetail.as_view()),
url(r'^authors/(?P<pk>[0-9]+)/$', author_detail, name='author-detail'),
例,使用routers:
from rest_framework import viewsets
class AuthorViewSet(viewsets.ModelViewSet):
queryset = Author.objects.all()
serializer_class = AuthorSerializer
# permission_classes = (permissions.IsAuthenticatedOrReadOnly,)
router = DefaultRouter()
router.register(r'authors', AuthorViewSet)
urlpatterns = [
……
]
urlpatterns += router.urls #方式1
# urlpatterns += [ #方式2
# url(r'^', include(router.urls)),
# ]