Django REST framework笔记(一)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/hua1011161696/article/details/81475066

一:REST framework简介

REST framework是什么?
Django REST框架是一个功能强大且灵活的工具包,用于构建Web API

REST framework的优点 :
1,Web可浏览API为开发人员带来了巨大的可用性。(The Web browsable API is a huge usability win for your developers.)
2,身份验证策略包括OAuth1a和OAuth2的程序包;
3,支持ORM和非ORM数据源的序列化;
4,可自定义;
5,丰富的文档和良好的社区支持;
6,受到国际知名公司的使用和信任,包括Mozilla,Red Hat,Heroku和Eventbrite。

在Django项目中使用:

1,在Django项目settings.py的INSTALLED_APPS中注册rest_framework 应用
2,每个视图类继承自 from rest_framework.views import APIView

下载:(使用清华源)
pip install -i https://pypi.tuna.tsinghua.edu.cn/simple djangorestframework

二:请求与响应

1,请求

REST framework 的 Request 类扩展自标准的 HttpRequest,并做了相应的增强,比如更加灵活的请求解析和认证

#使用组合的方式扩展了HttpRequest类
class Request(object):
    def __init__(self, request, parsers=None, authenticators=None,
                 negotiator=None, parser_context=None):
        self._request = request


#在REST framework中初始化request对象
class APIView(View):
    def initialize_request(self, request, *args, **kwargs):
        parser_context = self.get_parser_context(request)

        return Request(
            request,
            parsers=self.get_parsers(),
            authenticators=self.get_authenticators(),
            negotiator=self.get_content_negotiator(),
            parser_context=parser_context
        )

request.data :返回请求主体的解析内容,包括所有解析的内容,文件(file) 和 非文件(non-file inputs);不仅仅支持表单数据,还支持JSON数据;支持解析 POST 以外的 HTTP method ,比如 PUT,PATCH

request.query_params :等同于 request.GET;为了代码更加清晰可读,推荐使用 request.query_params

request.parsers :当前使用的解析器列表

request.user:通常会返回 django.contrib.auth.models.User 的一个实例,但其行为取决于正在使用的身份验证策略;若请求未经身份验证,则返回 django.contrib.auth.models.AnonymousUser 的实例

request.auth:返回任何附加的认证上下文(authentication context),通常可能是请求经过身份验证的令牌(token)实例

request.authenticators:当前使用的认证器(authenticator)列表

2,响应

REST framework 的 Response 类是 Django 的 SimpleTemplateResponse 的子类

构造方法: Response(data, status=None, template_name=None, headers=None, content_type=None)

data: 响应的序列化数据。

status: 响应的状态代码。默认为200。

template_name: 选择 HTMLRenderer 时使用的模板名称。

headers: 设置 HTTP header,字典类型。

content_type: 响应的内容类型,通常渲染器会根据内容协商的结果自动设置,但有些时候需要手动指定。

class Response(SimpleTemplateResponse):

    @property
    def rendered_content(self):
        #使用渲染器渲染序列化后的数据
        renderer = getattr(self, 'accepted_renderer', None)
        ret = renderer.render(self.data, accepted_media_type, context)

三:视图

REST framework 提供了一个 APIView 类,它继承于 Django 的 View 类。

1,View与APIView源码分析

View:

#views.py
from django.views import View

class BookView(View):
    pass
#-----------------------------
#urls.py

url(r'^books/$', views.BookView.as_view())    #项目启动时找到类方法as_view并执行
#View部分源码
class View(object):

    @classonlymethod
    def as_view(cls, **initkwargs):  #在视图类BookView的父类View中找到类方法as_view,执行它返回一个view函数

        def view(request, *args, **kwargs):   # 当对应url中的路径匹配成功时,调用执行此view函数
            self = cls(**initkwargs)
            return self.dispatch(request, *args, **kwargs)

        return view

    #分发方法
    def dispatch(self, request, *args, **kwargs):
        #http_method_names = ['get', 'post', 'put', 'patch', 'delete', 'head', 'options', 'trace']

        if request.method.lower() in self.http_method_names:
            handler = getattr(self, request.method.lower(), self.http_method_not_allowed)
        else:
            handler = self.http_method_not_allowed
        return handler(request, *args, **kwargs)    #在这里调用我们在视图类中的定义的get,post等函数,并返回响应

APIView:

#views.py
from rest_framework.views import APIView

class BookView(APIView):
     pass

#------------------------------------------------
#urls.py

url(r'^books/$', views.BookView.as_view()) #项目启动时找到类方法as_view并执行
#APIView部分源码
class APIView(View):
    @classmethod
    def as_view(cls, **initkwargs):   #项目启动时最先在这找到类方法as_view,执行它返回view函数
        view = super(APIView, cls).as_view(**initkwargs)  # 此view函数继承自其父类View
        return csrf_exempt(view)

    #执行view函数时,self.dispatch(request, *args, **kwargs)   调用dispatch方法,
    #先从对象的类中找,再去其父类APIView中找,在这能找到dispatch方法,所以最终调用的
    #是APIView类中的dispatch方法,而不再是View类中的dispatch方法!
    def dispatch(self, request, *args, **kwargs):   
            if request.method.lower() in self.http_method_names:
                handler = getattr(self, request.method.lower(),
                                  self.http_method_not_allowed)
            else:
                handler = self.http_method_not_allowed

            response = handler(request, *args, **kwargs)
            self.response = self.finalize_response(request, response, *args, **kwargs)
            return self.response

initialize_request(self, request, *args, **kwargs):
确保传递给处理方法的请求对象是 Request 的一个实例,而不是通常的 Django HttpRequest。

initial(self, request, *args, **kwargs):
用于执行处理方法被调用之前需要的任何操作。此方法用于强制执行权限和限流,并执行内容协商。

使用APIView 5种接口的实现:

    url(r'^books/$', views.BookView.as_view()),
    url(r'^books/(\d+)/$', views.BookDetailView.as_view()),
from rest_framework.views import APIView
from rest_framework.response import Response
from .models import Book
from .serializers import BookSerializer

class BookView(APIView):
    def get(self, request):
        book_list = Book.objects.all()
        serializer = BookSerializer(book_list, many=True)

        return Response(serializer.data)

    def post(self, request):
        serializer = BookSerializer(data=request.data)
        if serializer.is_valid():
            serializer.save()
            return Response(serializer.data)
        else:
            return Response(serializer.errors)


class BookDetailView(APIView):
    def get(self, request, pk):
        book_obj = Book.objects.filter(pk=pk).first()
        serializer = BookSerializer(book_obj, many=False)
        return Response(serializer.data)

    def put(self, request, pk):
        book_obj = Book.objects.filter(pk=pk).first()
        serializer = BookSerializer(data=request.data, instance=book_obj)
        if serializer.is_valid():
            serializer.save()
            return Response(serializer.data)
        else:
            return Response(serializer.errors)

    def delete(self, request, pk):
        Book.objects.filter(pk=pk).delete()
        return Response("ok")

2,GenericAPIView / mixin类

2.1  GenericAPIView 类继承于 REST framework 的 APIView 类,为标准列表和详细视图添加了常见的行为。

get_queryset(self) -->默认返回由 queryset 属性指定的查询集;
应该始终使用此方法, 而不是直接访问 self.queryset,因为 REST 会在内部对 self.queryset 的结果进行缓存用于后续所有请求。

get_serializer_class(self) -->返回用于序列化的类。默认返回 serializer_class 属性

2.2  mixin 类用于提供基本视图行为的操作

ListModelMixin -->提供一个 list(request, *args, **kwargs) 方法,实现了列出一个查询集;响应数据可以设置分页。

CreateModelMixin -->提供 create(request, *args, **kwargs) 方法,实现创建和保存新模型实例

RetrieveModelMixin -->提供 retrieve(request, *args, **kwargs) 方法,该方法实现在响应中返回现有的模型实例

UpdateModelMixin -->提供 update(request, *args, **kwargs) 方法,实现更新和保存现有模型实例。
还提供了一个 partial_update(request, *args, **kwargs) 方法,它与更新方法类似,只是更新的所有字段都是可选的。这允许支持 HTTP PATCH 请求。

DestroyModelMixin -->提供一个 destroy(request, *args, **kwargs) 方法,实现现有模型实例的删除

使用GenericAPIView与mixin 类 5种接口的实现:

    url(r'^books/$', views.BookView.as_view()),
    url(r'^books/(?P<pk>\d+)/$', views.BookDetailView.as_view()),
from rest_framework.mixins import CreateModelMixin,ListModelMixin,DestroyModelMixin,RetrieveModelMixin,UpdateModelMixin
from rest_framework.generics import GenericAPIView

class BookView(CreateModelMixin,ListModelMixin,GenericAPIView):
    queryset=Book.objects.all()
    serializer_class=BookSerializers

    def get(self,request):
        return self.list(request)
    def post(self,request):
        return self.create(request)


class BookDetailView(DestroyModelMixin,UpdateModelMixin,RetrieveModelMixin,GenericAPIView):
    queryset = Book.objects.all()
    serializer_class = BookSerializers

    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)

2.3  内置通用视图类

class CreateAPIView(CreateModelMixin,GenericAPIView) -->仅用于创建实例;提供一个 post 请求的处理方法

class ListAPIView(ListModelMixin,GenericAPIView) -->仅用于读取模型实例列表。提供一个 get 请求的处理方法

class RetrieveAPIView(RetrieveModelMixin,GenericAPIView) -->仅用于查询单个模型实例。提供一个 get 请求的处理方法

class DestroyAPIView(DestroyModelMixin,GenericAPIView) -->仅用于删除单个模型实例;提供一个 delete 请求的处理方法

class UpdateAPIView(UpdateModelMixin,GenericAPIView) -->仅用于更新单个模型实例。提供 put 和 patch 请求的处理方法

ListCreateAPIView -->既可以获取实例集合,也可以创建实例列表;提供 get 和 post 请求的处理方法
RetrieveUpdateDestroyAPIView -->同时支持查询,更新,删除;提供 get,put,patch 和 delete 请求的处理方法

使用内置通用视图 5种接口的实现:

    url(r'^books/$', views.BookView.as_view()),
    url(r'^books/(?P<pk>\d+)/$', views.BookDetailView.as_view()),
from rest_framework.generics import ListCreateAPIView,RetrieveUpdateDestroyAPIView

class BookView(ListCreateAPIView):
    queryset=Book.objects.all
    serializer_class=BookSerializers

class BookDetailView(RetrieveUpdateDestroyAPIView):
    queryset = Book.objects.all
    serializer_class = BookSerializers

3, 视图集 ViewSet

Django REST framework 允许将一组相关视图的逻辑组合到一个称为 ViewSet 的类中。

ModelViewSet 类继承自 GenericAPIView,并通过混合各种 mixin 类的行为来包含各种操作的实现。

使用ModelViewSet 类 5种接口的实现:

    url(r'^books/$', views.BookModelView.as_view({'get':'list','post':'create'})),
    url(r'^books/(?P<pk>\d+)/$', views.BookModelView.as_view({'get':'retrieve','put':'update','delete':'destroy'})),
from rest_framework.viewsets import ModelViewSet

class BookModelView(ModelViewSet):
    queryset = Book.objects.all()
    serializer_class = BookSerializer

4,各种视图类的继承关系图

四:序列化

序列化器允许将诸如查询集和模型实例之类的复杂数据转换为原生 Python 数据类型,然后可以将它们轻松地呈现(渲染)为 JSON,XML 或其他内容类型。序列化器还提供反序列化,在首次验证传入数据之后,可以将解析的数据转换回复杂类型。

REST framework 提供了一个 Serializer 类,它提供了一种强大的通用方法来控制响应的输出,以及一个 ModelSerializer 类,它为创建处理模型实例和查询集的序列化提供了有效的快捷方式。

1,声明序列化类

声明一个序列化类,使用它来序列化和反序列化与对象相对应的数据;声明一个序列化类看起来非常类似于声明一个表单

好的做法是将所有的序列化类写在一个 serializers.py文件中。

from .models import Book
from rest_framework import serializers

class BookSerializer(serializers.Serializer):
    title = serializers.CharField()
    # publishDate = serializers.DateField()
    price = serializers.CharField()

    # 多对一字段
    publish_name = serializers.CharField(source='publish.name')
    # publish_city = serializers.CharField(source='publish.city')

    # 多对多字段
    authors = serializers.SerializerMethodField()
    # 默认方法名为get_<fieldName>
    def get_authors(self,obj):
        data = []
        for author_obj in obj.authors.all():
            author_data = {}
            author_data['name']=author_obj.name
            author_data['age']=author_obj.age
            data.append(author_data)
        return data

ModelSerializer 类提供了一个快捷方式,可让你自动创建一个 Serializer 类,其中的字段与模型类字段对应

ModelSerializer 类与常规 Serializer 类不同之处在于:
①它会根据模型自动生成一组字段。

②它会自动为序列化类生成验证器,例如 unique_together 验证器。

③它包含 .create() 和 .update() 的简单默认实现

从版本 3.3.0 开始,必须提供其中一个属性 fields 或 exclude。

任何关系(如模型上的外键)都将映射到 PrimaryKeyRelatedField。

ModelSerializer 对关系字段的默认表示是使用相关实例的主键。

class BookSerializer(serializers.ModelSerializer):
    class Meta:
        model = Book
        fields = '__all__'
        # fields = ('title','price')
        # exclude = ('id', 'publishDate')
class BookSerializer(serializers.ModelSerializer):
    # 一对多和多对多字段默认取其id值,若想提供其他值,需要自定义;其他简单字段也可以显示指定字段以覆盖默认字段
    # title = serializers.CharField()
    publish = serializers.CharField(source='publish.name')
    authors = serializers.SerializerMethodField()
    def get_authors(self, obj):
        data = []
        for author_obj in obj.authors.all():
            author_data = {}
            author_data['name'] = author_obj.name
            author_data['age'] = author_obj.age
            data.append(author_data)
        return data

    class Meta:
        model = Book
        fields = '__all__'

查看ModelSerializer自动创建的Serializer 类的字段信息:
>>> from myapp.serializers import AccountSerializer
>>> serializer = AccountSerializer()
>>> print(repr(serializer))

HyperlinkedModelSerializer 类与 ModelSerializer 类相似,只不过它使用超链接来表示关系而不是主键。
默认情况下,序列化器将包含一个 url 字段而不是主键字段。

class AccountSerializer(serializers.HyperlinkedModelSerializer):
    class Meta:
        model = Account
        fields = ('url', 'id', 'account_name', 'users', 'created')

2,BaseSerializer  API

Serializer 类继承自BaseSerializer,ModelSerializer 类继承自Serializer 类。
BaseSerializer 类可以用来方便地支持其他序列化和反序列化风格。

.data - 返回传出的原始表示。
.is_valid() - 反序列化并验证传入的数据。
.validated_data - 返回验证的传入数据。
.errors - 在验证期间返回错误。
.save() - 将验证的数据保存到对象实例中。

有四种方法可以被覆盖,这取决于你希望序列化类支持的功能:
.to_representation() - 重写此操作以支持序列化,用于读取操作。
.to_internal_value() - 重写此操作以支持反序列化,以用于写入操作。
.create() 和 .update() - 覆盖其中一个或两个以支持保存实例。

3,序列化对象与反序列化对象

将模型实例转换为 Python 原生数据类型
serializer = CommentSerializer(comment)
serializer.data

序列化多个对象
queryset = Book.objects.all()
serializer = BookSerializer(queryset, many=True)
serializer.data

反序列化对象:

将原生数据类型恢复成通过验证的数据字典
serializer = CommentSerializer(data=request.data)
serializer.is_valid()
# True;通过验证的数据字典
serializer.validated_data

# False;包含一个代表错误消息的字典
serializer.errors  

4,保存实例

需要实现 .create() 和 .update() 方法

    def create(self, validated_data):
        return Comment.objects.create(**validated_data)

    def update(self, instance, validated_data):
        instance.email = validated_data.get('email', instance.email)
        instance.content = validated_data.get('content', instance.content)
        instance.created = validated_data.get('created', instance.created)
        instance.save()
        return instance

调用 .save() 将创建一个新实例或更新现有实例,具体取决于在实例化序列化类时是否传递了现有实例

#save方法的源码

class BaseSerializer(Field):
    def save(self, **kwargs):
        if self.instance is not None:
            self.instance = self.update(self.instance, validated_data)
            assert self.instance is not None, (
                '`update()` did not return an object instance.'
            )
        else:
            self.instance = self.create(validated_data)
            assert self.instance is not None, (
                '`create()` did not return an object instance.'
            )

        return self.instance

在保存实例的时候注入额外的数据。这些附加数据可能包含当前用户,当前时间或其他任何不属于请求数据的信息。
调用 .create() 或 .update() 时,任何其他关键字参数都将包含在 validated_data 参数中
serializer.save(owner=request.user)

5,字段验证

validate_<field_name> 方法来指定自定义字段级验证;这些与 Django 表单上的 clean_<field_name> 方法类似。
只有一个参数,就是需要验证的字段值;应返回验证值或引发 serializers.ValidationError

def validate_title(self, value):
        if 'django' not in value.lower():
            raise serializers.ValidationError("Blog post is not about Django")
        return value

如果要对多个字段进行其他的验证,请将一个名为 validate() 的方法添加到Serializer 子类中。
只有一个参数,它是一个字段值(field-value)的字典;应返回验证值或引发 serializers.ValidationError

def validate(self, data):
        if data['start'] > data['finish']:
            raise serializers.ValidationError("finish must occur after start")
        return data

序列化器上的各个字段可以包含验证器,方法是在字段实例上声明它们:

def multiple_of_ten(value):
    if value % 10 != 0:
        raise serializers.ValidationError('Not a multiple of ten')

class GameRecord(serializers.Serializer):
    score = IntegerField(validators=[multiple_of_ten])

6,其他补充

部分更新:
默认情况下,序列化程序必须为所有必填字段传递值,否则会引发验证错误。可以使用 partial 参数以允许部分更新。
serializer = CommentSerializer(comment, data={'content': u'foo bar'}, partial=True)

嵌套对象:

Serializer 类本身就是一种 Field,可以用来表示一个对象类型嵌套在另一个对象类型中的关系;
如果嵌套对象可以是 None 值,则应将 required = False 标志传递给嵌套的序列化类;
同样,如果嵌套对象是一个列表,则应将 many = True 标志传递给嵌套的序列化类。

class CommentSerializer(serializers.Serializer):
    user = UserSerializer()
    content = serializers.CharField(max_length=200)
    created = serializers.DateTimeField()

自定义多个对象的创建:

class BookListSerializer(serializers.ListSerializer):
    def create(self, validated_data):
        books = [Book(**item) for item in validated_data]
        return Book.objects.bulk_create(books)

class BookSerializer(serializers.Serializer):
    ...
    class Meta:
        list_serializer_class = BookListSerializer

自定义多个对象的更新 -->见官方文档

猜你喜欢

转载自blog.csdn.net/hua1011161696/article/details/81475066