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/

相关文章
相关标签/搜索