Django REST framework快速入門

簡介

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

序列化 serializers

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)

這樣,登錄以後纔有修改權限,只能修改本身建立的。

超連接API

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/

相關文章
相關標籤/搜索