Young_

V2

2022/09/28阅读:23主题:橙心

Django笔记

学习路径

1. 序列化

  1. 对象处理
snippet = Snippet(code='foo = "bar"\n')
snippet.save()

snippet = Snippet(code='print "hello, world"\n')
snippet.save()
  1. 实例序列化
serializer = SnippetSerializer(snippet)
serializer.data
# {'id': 2, 'title': u'', 'code': u'print "hello, world"\n', 'linenos': False, 'language': u'python', 'style': u'friendly'}
  1. 转json
content = JSONRenderer().render(serializer.data)
content
# '{"id": 2, "title": "", "code": "print \\"hello, world\\"\\n", "linenos": false, "language": "python", "style": "friendly"}'

2. 反序列化

stream = BytesIO(content)
data = JSONParser().parse(stream)
  1. 恢复对象实例
serializer = SnippetSerializer(data=data)
serializer.is_valid()
# True
serializer.validated_data
# OrderedDict([('title', ''), ('code', 'print "hello, world"\n'), ('linenos', False), ('language', 'python'), ('style', 'friendly')])
serializer.save()
# <Snippet: Snippet object>
  1. (可选)序列化查询结果集(querysets)而不是模型实例
serializer = SnippetSerializer(Snippet.objects.all(), many=True)
serializer.data
# [OrderedDict([('id', 1), ('title', u''), ('code', u'foo = "bar"\n'), ('linenos', False), ('language', 'python'), ('style', 'friendly')]),
OrderedDict([('id'2), ('title'u''), ('code'u'print "hello, world"\n'), ('linenos'False), ('language''python'), ('style''friendly')]),
OrderedDict([('id'3), ('title'u''), ('code'u'print "hello, world"'), ('linenos'False), ('language''python'), ('style''friendly')])]

3. 基于类视图CBV

  1. 继承APIView

简单的继承APIView

class SnippetList(APIView):
    """
    列出所有的snippets或者创建一个新的snippet。
    """

    def get(self, request, format=None):
        snippets = Snippet.objects.all()
        serializer = SnippetSerializer(snippets, many=True)
        return Response(serializer.data)

    def post(self, request, format=None):
        serializer = SnippetSerializer(data=request.data)
        if serializer.is_valid():
            serializer.save()
            return Response(serializer.data, status=status.HTTP_201_CREATED)
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
  1. 使用混合

    继承  mixins.UpdateModelMixin|DestroyModelMixingenerics.GenericaAPIView

    class SnippetDetail(mixins.RetrieveModelMixin,
                        mixins.UpdateModelMixin,
                        mixins.DestroyModelMixin,
                        generics.GenericAPIView)
    :

        queryset = Snippet.objects.all()
        serializer_class = SnippetSerializer

        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. 通用的基于类的视图

    更换 genericView → generics.RetrieveUpdateDestroyAPIView

    from snippets.models import Snippet
    from snippets.serializers import SnippetSerializer
    from rest_framework import generics

    class SnippetList(generics.ListCreateAPIView):
        queryset = Snippet.objects.all()
        serializer_class = SnippetSerializer

    class SnippetDetail(generics.RetrieveUpdateDestroyAPIView):
        queryset = Snippet.objects.all()
        serializer_class = SnippetSerializer

4. 认证和权限

前提条件:

  • 代码片段始终与创建者相关联。
  • 只有通过身份验证的用户可以创建片段。
  • 只有代码片段的创建者可以更新或删除它。
  • 未经身份验证的请求应具有完全只读访问权限。

操作步骤:

  1. model添加 owner highlighted 字段

  2. model中增加 .save() 方法

  3. 为用户模型增加路径

    1. serializers.py 中追加

    2. 添加基于类的通用视图

    3. 添加urls.py

      url(r'^users/$', views.UserList.as_view()),
      url(r'^users/(?P<pk>[0-9]+)/$', views.UserDetail.as_view()),
  4. 将snippet和用户关联

    • snippeList 追加 perform_create 方法
    • 更新序列化器
  5. 添加视图所需权限

  6. 给Browsable API添加登录

  7. 对象级别权限控制

    • 新增 permissions.py
  8. 使用API 进行身份验证

5. 视图集ViewSets和路由器

前言:

  • ViewSet类与View类几乎相同,不同之处在于它们提供诸如readupdate之类的操作,而不是getput等方法处理程序。

  • 最后一个ViewSet类只绑定到一组方法处理程序,当它被实例化成一组视图的时候,通常通过使用一个Router类来处理自己定义URL conf的复杂性。

  1. 使用ViewSets重构

  2. 将viewSets 绑定到url

    • 显示

      from snippets.views import SnippetViewSet, UserViewSet, api_root
      from rest_framework import renderers

      snippet_list = SnippetViewSet.as_view({
          'get''list',
          'post''create'
      })
      snippet_detail = SnippetViewSet.as_view({
          'get''retrieve',
          'put''update',
          'patch''partial_update',
          'delete''destroy'
      })
      snippet_highlight = SnippetViewSet.as_view({
          'get''highlight'
      }, renderer_classes=[renderers.StaticHTMLRenderer])
      user_list = UserViewSet.as_view({
          'get''list'
      })
      user_detail = UserViewSet.as_view({
          'get''retrieve'
      })
    • 具体视图

      urlpatterns = format_suffix_patterns([
          url(r'^$', api_root),
          url(r'^snippets/$', snippet_list, name='snippet-list'),
          url(r'^snippets/(?P<pk>[0-9]+)/$', snippet_detail, name='snippet-detail'),
          url(r'^snippets/(?P<pk>[0-9]+)/highlight/$', snippet_highlight, name='snippet-highlight'),
          url(r'^users/$', user_list, name='user-list'),
          url(r'^users/(?P<pk>[0-9]+)/$', user_detail, name='user-detail')
      ])
    • 使用路由器

      # 创建路由器并注册我们的视图。
      router = DefaultRouter()
      router.register(r'snippets', views.SnippetViewSet)
      router.register(r'users', views.UserViewSet)

      # API URL现在由路由器自动确定。
      # 另外,我们还要包含可浏览的API的登录URL。
      urlpatterns = [
          url(r'^', include(router.urls)),
          url(r'^api-auth/', include('rest_framework.urls', namespace='rest_framework'))
      ]

5.1 视图(views)vs视图集(viewsets)之间的权衡

使用视图集可以是一个非常有用的抽象。它有助于确保URL约定在你的API中保持一致,最大限度地减少编写所需的代码量,让你能够专注于API提供的交互和表示,而不是URLconf的细节。

这并不意味着采用视图集总是正确的方法。在使用基于类的视图而不是基于函数的视图时,有一个类似的权衡要考虑。使用视图集不像单独构建视图那样明确。

6. 概要和客户端库

  • 概要: 机器可读文档、描述可用api路径 ,其urls以及 支持的操作
  • 概要: 自动生成文档的有用工具,也可以用于驱动可以与api进行交互的动态客户端库

6.1 Core API

为了提供概要支持REST框架使用Core API

Core API是用于描述API的文档规范。它用于提供可用路径的内部表示形式和API公开的可能的交互。它可以用于服务器端或客户端。

6.2 添加概要

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),
    ...
]

如果你在浏览器中访问API根路径,那么你现在应该可以看到corejson表示形式是一个可用选项。

6.3 使用命令行客户端

现在我们的API暴露了一个概要路径,我们可以使用一个动态的客户端库与API进行交互。为了演示这个,我们来使用Core API命令行客户端。

命令行客户端作为一个coreapi-cli包提供:

$ pip install coreapi-cli

现在检查它在命令行上是否可用...

$ coreapi
Usage: coreapi [OPTIONS] COMMAND [ARGS]...

  Command line client for interacting with CoreAPI services.

  Visit http://www.coreapi.org for more information.

Options:
  --version  Display the package version number.
  --help     Show this message and exit.

Commands:
...

首先,我们将使用命令行客户端加载API概要。

$ coreapi get http://127.0.0.1:8000/schema/
<Pastebin API "http://127.0.0.1:8000/schema/">
    snippets: {
        highlight(id)
        list()
        read(id)
    }
    users: {
        list()
        read(id)
    }

我们还没有认证,所以现在我们只能看到只读路径,这与我们设置的API权限是一致的。

6.4 验证我们的客户端

如果我们想要创建,编辑和删除代码片段,我们需要进行有效性用户身份验证。在这种情况下,我们只需使用基本的auth。

请确保使用实际的用户名和密码替换下面的<username><password>

$ coreapi credentials add 127.0.0.1 <username>:<password> --auth basic
Added credentials
127.0.0.1 "Basic <...>"

现在,如果我们再次提取概要,我们应该能够看到一组可用的交互。

$ coreapi reload

分类:

后端

标签:

Python

作者介绍

Young_
V2

佛学代表、趟平系代言人、内卷领军人物