本文是快速入門,不涉及源碼分析,閱讀源碼能對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/