本文是快速入门,不涉及源码分析,阅读源码能对Django REST framework 有更深入的理解。html
Django REST framework 官网文档 : http://www.django-rest-framework.org/python
pip install djangorestframework
Settings配置git
TryDRF/settings.pygithub
注册rest_framework数据库
INSTALLED_APPS = ( ... 'rest_framework', )
Django REST framework配置项django
REST_FRAMEWORK = { 'DEFAULT_PERMISSION_CLASSES': [ 'rest_framework.permissions.IsAdminUser', ], 'PAGE_SIZE': 10 }
建立数据库表TryDRF/app01/models.pyjson
from django.db import models class Publisher(models.Model): name = models.CharField(max_length=32, verbose_name="名称", unique=True) address = models.CharField(max_length=128, verbose_name="地址") def __str__(self): return self.name class Meta: verbose_name = "出版社" verbose_name_plural = verbose_name
数据库迁移:在Tools-Run manage.py Task 中输入makemigrations 和migrateapi
添加一条数据。能够使用Tools-Python Console服务器
URLapp
url(r'^publishers/', views.publish_list),
VIEW
from django.shortcuts import render, HttpResponse from app01 import models import json def publish_list(request): querset = models.Publisher.objects.all() data = [] for i in querset: p_tmp = { 'name': i.name, 'address': i.address } data.append(p_tmp) return HttpResponse(json.dumps(data,ensure_ascii=False), content_type='application/json')
访问http://127.0.0.1:8000/publishers/
Django中内置了一个把模型对象转换成字典的方法 model_to_dict
上面的VIEW改写成
from django.shortcuts import HttpResponse from app01 import models import json from django.forms.models import model_to_dict def publish_list(request): querset = models.Publisher.objects.all() data = [] for i in querset: data.append(model_to_dict(i)) return HttpResponse(json.dumps(data, ensure_ascii=False), content_type='application/json')
这样利用model_to_dict虽然不用一个字段一个字段的将对象转换成字典格式,可是有些字段包括图片是不能转换的,
使用django自带的序列化
from django.shortcuts import HttpResponse from app01 import models from django.core import serializers def publish_list(request): querset = models.Publisher.objects.all() data=serializers.serialize("json",querset) return HttpResponse(data, content_type="application/json")
以上这些序列化方式咱们都不用, 下面讲解更牛逼的Django REST framework给咱们提供的序列化,不单单将对象转换成字典还能将字典转换为models里的对象
它和django的form很是类似
在app01下建立serializers.py
from rest_framework import serializers from app01 import models class PublisherSerializer(serializers.Serializer): id = serializers.IntegerField(read_only=True) name = serializers.CharField(max_length=32) address = serializers.CharField(max_length=128) def create(self, validated_data): return models.Publisher.objects.create(**validated_data) def update(self, instance, validated_data): instance.name = validated_data.get("name", instance.name) instance.address = validated_data.get("address", instance.address) instance.save() return instance
将一个模型对象转换为字典或者将字典转换为模型对象
回到VIEWS,使用这个组件
from django.shortcuts import HttpResponse from app01 import models import json from django.core import serializers from app01 import serializers def publish_list(request): querset = models.Publisher.objects.all() serializer = serializers.PublisherSerializer(querset, many=True) return HttpResponse(json.dumps(serializer.data, ensure_ascii=False), content_type="application/json")
Django REST framework还提供了一个ModelSerializer,使得咱们不须要再从新写model里定义过的字段
serializers.py
from rest_framework import serializers from app01 import models class PublisherSerializer(serializers.ModelSerializer): class Meta: model = models.Publisher fields = ( "id", "name", "address", )
结果跟上面的同样的。也就是说能够本身写PublisherSerializer下的字段也能够继承ModelSerializer,两种方式。
REST framework的Request
类扩展了标准的HttpRequest
,添加对REST framework的灵活请求解析和请求身份验证的支持。
FBV
url(r'^publishers/$', views.publisher_list), url(r'^publishers/(?P<pk>[0-9]+)$', views.publisher_detail),
VIEWS
from app01 import models from rest_framework.decorators import api_view from rest_framework.response import Response from rest_framework import status from app01 import serializers @api_view(['GET', 'POST']) # 容许的请求方式 GET, POST def publisher_list(request, format=None): """ 列出全部的出版社,或者建立一个新的出版社 """ if request.method == "GET": queryset = models.Publisher.objects.all() # 全部的出版社 s = serializers.PublisherSerializer(queryset, many=True) return Response(s.data) if request.method == "POST": # 建立出版社 s = serializers.PublisherSerializer(data=request.data) if s.is_valid(): s.save() return Response(s.data, status=status.HTTP_201_CREATED) else: return Response(s.errors, status=status.HTTP_400_BAD_REQUEST) @api_view(['GET', 'PUT', 'DELETE']) def publisher_detail(request, pk, format=None): """ 获取,更新或删除一个出版社实例。 """ try: publisher = models.Publisher.objects.get(pk=pk) except models.Publisher.DoesNotExist: return Response(status=status.HTTP_404_NOT_FOUND) if request.method == 'GET': s = serializers.PublisherSerializer(publisher) return Response(s.data) elif request.method == 'PUT': s = serializers.PublisherSerializer(publisher, data=request.data) if s.is_valid(): s.save() return Response(s.data) return Response(s.errors, status=status.HTTP_400_BAD_REQUEST) elif request.method == 'DELETE': publisher.delete() return Response(status=status.HTTP_204_NO_CONTENT)
补充:在url中添加下面的url就能够调出登录组件,能够登录admin用户
url(r'^api-auth/', include('rest_framework.urls', namespace='rest_framework')),
CBV
URL
url(r'^publishers/$', views.PublisherList.as_view()), url(r'^publishers/(?P<pk>[0-9]+)$', views.PublisherDetail.as_view()),
VIEWS
from django.http import Http404 from rest_framework.views import APIView from rest_framework.response import Response from rest_framework import status from app01 import models from app01 import serializers class PublisherList(APIView): """ 列出全部的出版社,或者建立一个新的出版社 """ def get(self, request, format=None): queryset = models.Publisher.objects.all() # 查询出全部的出版社 s = serializers.PublisherSerializer(queryset, many=True) return Response(s.data) def post(self, request, format=None): s = serializers.PublisherSerializer(data=request.data) if s.is_valid(): # 若是数据没问题 s.save() return Response(s.data, status=status.HTTP_201_CREATED) return Response(s.errors, status=status.HTTP_400_BAD_REQUEST) class PublisherDetail(APIView): """ 具体的出版社,查看,修改,删除视图 """ def get_object(self, pk): try: return models.Publisher.objects.get(pk=pk) except models.Publisher.DoesNotExist: raise Http404 # 查看具体的出版社信息 def get(self, request, pk, format=None): publisher = self.get_object(pk) s = serializers.PublisherSerializer(publisher) return Response(s.data) # 修改出版社信息 def put(self, request, pk, format=None): publisher = self.get_object(pk) s = serializers.PublisherSerializer(publisher, data=request.data) if s.is_valid(): s.save() return Response(s.data) return Response(s.errors, status=status.HTTP_400_BAD_REQUEST) # 删除出版社信息 def delete(self, request, pk, format=None): publisher = self.get_object(pk) publisher.delete() return Response(status=status.HTTP_204_NO_CONTENT)
使用混合(mixins):
使用基于类视图的最大优点之一是它能够轻松地建立可复用的行为
到目前为止,咱们使用的建立/获取/更新/删除操做和咱们建立的任何基于模型的API视图很是类似。这些常见的行为是在REST框架的mixin类中实现的(功能和上面的彻底同样)。
让咱们来看看咱们是如何经过使用mixin类编写视图的。这是咱们的views.py
模块
from app01 import models from app01 import serializers from rest_framework import mixins from rest_framework import generics class PublisherList(mixins.ListModelMixin, mixins.CreateModelMixin, generics.GenericAPIView): queryset = models.Publisher.objects.all() serializer_class = serializers.PublisherSerializer 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 PublisherDetail(mixins.RetrieveModelMixin, mixins.UpdateModelMixin, mixins.DestroyModelMixin, generics.GenericAPIView): queryset = models.Publisher.objects.all() serializer_class = serializers.PublisherSerializer 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 app01 import models from app01 import serializers from rest_framework import generics class PublisherList(generics.ListCreateAPIView): queryset = models.Publisher.objects.all() serializer_class = serializers.PublisherSerializer class PublisherDetail(generics.RetrieveUpdateDestroyAPIView): queryset = models.Publisher.objects.all() serializer_class = serializers.PublisherSerializer
改一下数据库表
from django.db import models class Publisher(models.Model): name = models.CharField(max_length=32, verbose_name="名称", unique=True) address = models.CharField(max_length=128, verbose_name="地址") operator = models.ForeignKey("auth.User") def __str__(self): return self.name class Meta: verbose_name = "出版社" verbose_name_plural = verbose_name
serializers.py
from rest_framework import serializers from app01 import models class PublisherSerializer(serializers.ModelSerializer): operator = serializers.ReadOnlyField(source="operator.username") class Meta: model = models.Publisher fields = ( "id", "name", "address", "operator" )
此时访问一下能够看到lcg,表示建立代码段的用户,若是不加operator 那一段的话看到的是1:
app01下建立permissions.py
from rest_framework import permissions class IsOwnerOrReadOnly(permissions.BasePermission): """ 自定义权限只容许对象的全部者编辑它。 """ def has_object_permission(self, request, view, obj): # 读取权限容许任何请求, # 因此咱们老是容许GET,HEAD或OPTIONS请求。 if request.method in permissions.SAFE_METHODS: return True # 只有该snippet的全部者才容许写权限。 return obj.operator == request.user
views.py
from app01 import models from app01 import serializers from rest_framework import generics from rest_framework import permissions from app01.permissions import IsOwnerOrReadOnly class PublisherList(generics.ListCreateAPIView): queryset = models.Publisher.objects.all() serializer_class = serializers.PublisherSerializer permission_classes = (permissions.IsAuthenticatedOrReadOnly, IsOwnerOrReadOnly) def perform_create(self, serializer): serializer.save(operator=self.request.user) # 保存的用户设置为当前用户 class PublisherDetail(generics.RetrieveUpdateDestroyAPIView): queryset = models.Publisher.objects.all() serializer_class = serializers.PublisherSerializer permission_classes = (permissions.IsAuthenticatedOrReadOnly, IsOwnerOrReadOnly)
这样,登录以后才有修改权限,只能修改本身建立的。
models.py
from django.db import models class Publisher(models.Model): name = models.CharField(max_length=32, verbose_name="名称", unique=True) address = models.CharField(max_length=128, verbose_name="地址") operator = models.ForeignKey("auth.User") def __str__(self): return self.name class Meta: verbose_name = "出版社" verbose_name_plural = verbose_name class Book(models.Model): title = models.CharField(max_length=32, verbose_name="书名") publisher = models.ForeignKey("Publisher") def __str__(self): return self.title class Meta: verbose_name = "书" verbose_name_plural = verbose_name
serializers.py
from rest_framework import serializers from app01 import models class PublisherSerializer(serializers.ModelSerializer): operator = serializers.ReadOnlyField(source="operator.username") class Meta: model = models.Publisher fields = ( "id", "name", "address", "operator" ) class BookSerializer(serializers.HyperlinkedModelSerializer): class Meta: model = models.Book fields = ( "id", "title", "publisher" )
项目urls.py
from django.conf.urls import url, include from django.contrib import admin urlpatterns = [ url(r'^api/', include("app01.urls")), url(r'^admin/', admin.site.urls), ]
app01/urls.py
from django.conf.urls import url, include from app01 import views from rest_framework.urlpatterns import format_suffix_patterns urlpatterns = [ url(r'^$', views.api_root), url(r'^publishers/$', views.PublisherList.as_view(), name="publisher-list"), url(r'^publishers/(?P<pk>[0-9]+)/$', views.PublisherDetail.as_view(), name="publisher-detail"), url(r'^books/$', views.BookList.as_view(), name="book-list"), url(r'^books/(?P<pk>[0-9]+)/$', views.BookDetail.as_view(), name="bool-detail"), url(r'^api-auth/', include('rest_framework.urls', namespace='rest_framework')), ] urlpatterns = format_suffix_patterns(urlpatterns)
views.py
from rest_framework.response import Response from app01 import models from app01 import serializers from rest_framework import generics from rest_framework import permissions from app01.permissions import IsOwnerOrReadOnly from rest_framework.decorators import api_view from rest_framework.reverse import reverse class PublisherList(generics.ListCreateAPIView): queryset = models.Publisher.objects.all() serializer_class = serializers.PublisherSerializer permission_classes = (permissions.IsAuthenticatedOrReadOnly, IsOwnerOrReadOnly) def perform_create(self, serializer): serializer.save(operator=self.request.user) class PublisherDetail(generics.RetrieveUpdateDestroyAPIView): queryset = models.Publisher.objects.all() serializer_class = serializers.PublisherSerializer permission_classes = (permissions.IsAuthenticatedOrReadOnly, IsOwnerOrReadOnly) class BookList(generics.ListCreateAPIView): queryset = models.Book.objects.all() serializer_class = serializers.BookSerializer permission_classes = (permissions.IsAuthenticatedOrReadOnly, ) class BookDetail(generics.RetrieveUpdateDestroyAPIView): queryset = models.Book.objects.all() serializer_class = serializers.BookSerializer permission_classes = (permissions.IsAuthenticatedOrReadOnly, ) @api_view(['GET']) def api_root(request, format=None): return Response({ 'publishers': reverse('publisher-list', request=request, format=format), 'books': reverse('book-list', request=request, format=format) })
访问http://127.0.0.1:8000/api/
访问http://127.0.0.1:8000/api/books/
将上面的代码再进行简化。可应用视图集和路由器
views.py
from app01 import models from app01 import serializers from rest_framework import permissions from app01.permissions import IsOwnerOrReadOnly from rest_framework import viewsets class BookViewSet(viewsets.ModelViewSet): queryset = models.Book.objects.all() serializer_class = serializers.BookSerializer permission_classes = (permissions.IsAuthenticatedOrReadOnly,) class PublisherViewSet(viewsets.ModelViewSet): queryset = models.Publisher.objects.all() serializer_class = serializers.PublisherSerializer permission_classes = (permissions.IsAuthenticatedOrReadOnly, IsOwnerOrReadOnly)
app01/urls.py
from django.conf.urls import url, include from app01 import views from rest_framework.routers import DefaultRouter # 建立路由器并注册咱们的视图。 router = DefaultRouter() router.register('books', views.BookViewSet) router.register('publishers', views.PublisherViewSet) urlpatterns = [ url(r'^', include(router.urls)), url(r'^api-auth/', include('rest_framework.urls', namespace='rest_framework')), ]
Core API是用于描述API的文档规范。它用于提供可用路径的内部表示形式和API公开的可能的交互。它能够用于服务器端或客户端。
当使用服务器端时,coreAPI容许API支持呈现范围普遍的概要或超媒体格式。
当使用客户端时,核心API容许动态驱动的客户端库,它能够与任何公开受支持的概要或超媒体格式的API交互。
添加概要
REST框架支持明肯定义的概要视图或自动生成的概要。因为咱们使用的是视图集和路由器,咱们能够简单地使用自动概要生成。
你须要安装coreapi
python包才能包含API概要。
pip install coreapi
如今咱们能够经过在URL配置中包含一个自动生成的概要视图来为API添加概要。
from rest_framework.schemas import get_schema_view schema_view = get_schema_view(title='Pastebin API') urlpatterns = [ url('^schema/$', schema_view), ... ]
文档 更简单更强大,也经过在URL配置
from rest_framework.documentation import include_docs_urls urlpatterns = [ ...... url(r'docs/',include_docs_urls(title='图书管理系统')), ]
翻译文档:https://q1mi.github.io/Django-REST-framework-documentation/tutorial/7-schemas-and-client-libraries_zh/