geekdoc-python-zh/docs/realpython/django-rest-framework-class...

8.3 KiB
Raw Permalink Blame History

Django Rest 框架——基于类的视图

原文:https://realpython.com/django-rest-framework-class-based-views/

在这篇文章中,让我们继续开发 Django Talk 项目和 Django Rest 框架,同时实现基于 T2 类的视图,并做一些简单的重构来保持代码的干爽。本质上,我们正在将现有的基于函数视图的 RESTful API 迁移到基于类的视图。

这是本系列教程的第四部分。

**需要迎头赶上?**看看第一部分第一部分和第二部分第五部分,我们将讨论 Django 和 AJAX还有第三部分第七部分,我们将介绍 Django Rest 框架。

**需要代码吗?**从回购下载。

要获得关于 Django Rest 框架的更深入的教程,请务必查看第三个 Real Python 课程。

重构

在进入基于类的视图之前,让我们对当前代码做一个快速重构。在def post_element()视图中,进行以下更新:

post = get_object_or_404(Post, id=pk)

# try:
#     post = Post.objects.get(pk=pk)
# except Post.DoesNotExist:
#     return HttpResponse(status=404)

所以这里我们使用 get_object_or_404 快捷方式来引发 404 错误而不是异常。

请确保也更新导入:

from django.shortcuts import render, get_object_or_404

测试一下。尝试查看一个不存在的元素——即http://localhost:8000/API/v1/posts/202format=json 。您应该会在浏览器中看到以下响应:

{ "detail":  "Not found" }

如果你在 Chrome 开发者工具中打开网络标签,你应该会看到一个 404 状态码。很酷,对吧?不幸的是,我们不会使用它太久,因为是时候告别我们当前的基于函数的视图并添加基于类的视图了。

Remove ads

基于类的视图

虽然函数很容易使用,但使用基于类的视图来重用功能通常是有益的,尤其是对于具有许多端点的大型 API。

注释掉基于函数的视图的代码。

收藏

为集合的基于类的视图添加以下代码:

class PostCollection(mixins.ListModelMixin,
                     mixins.CreateModelMixin,
                     generics.GenericAPIView):

    queryset = Post.objects.all()
    serializer_class = PostSerializer

    def get(self, request, *args, **kwargs):
        return self.list(request, *args, **kwargs)

    def post(self, request, *args, **kwargs):
        return self.create(request, *args, **kwargs)

欢迎来到 mixins 的力量!

  1. ListModelMixin提供了list()函数,用于将集合序列化为 JSON然后将其作为 GET 请求的响应返回。
  2. 同时,CreateModelMixin提供了用于创建新对象的create()函数,以响应 POST 请求。
  3. 最后,GenericAPIView mixin 提供了 RESTful API 所需的“核心”功能。

请参考 DRF 官方文档了解更多关于这些混合的信息。

成员

现在为成员添加代码:

class PostMember(mixins.RetrieveModelMixin,
                   mixins.DestroyModelMixin,
                   generics.GenericAPIView):

    queryset = Post.objects.all()
    serializer_class = PostSerializer

    def get(self, request, *args, **kwargs):
        return self.retrieve(request, *args, **kwargs)

    def delete(self, request, *args, **kwargs):
        return self.destroy(request, *args, **kwargs)

这里,我们简单地使用GenericAPIView作为“核心功能”,其余的 mixins 提供处理 GET 和 DELETE 请求所需的功能。

URLs

最后,让我们更新 urls.py 来说明基于类的视图:

from django.conf.urls import patterns, url
from talk import views

urlpatterns = patterns(
    'talk.views',
    url(r'^$', 'home'),

    # api
    url(r'^api/v1/posts/$', views.PostCollection.as_view()),
    url(r'^api/v1/posts/(?P<pk>[0-9]+)/$', views.PostMember.as_view())
)

请注意as_view()方法,它提供了一点魔力来将类作为视图函数处理。

测试一下。启动开发服务器,然后:

  1. 确保所有帖子都已加载
  2. 添加新帖子
  3. 删除一个帖子

发生了什么事?尝试添加新帖子时,您应该会看到以下错误:

400:  { "text":  ["This field is required."], "author":  ["This field is required."] }

幸运的是,这很容易解决。

Remove ads

重构 AJAX

我们需要改变发送 POST 请求数据的方式。首先,将the_post键更新为text:

data  :  {  text  :  $('#post-text').val()  },  // data sent with the post request

如果您现在测试它,错误应该只是表明我们缺少了author字段。我们可以通过多种方式获取登录的用户,但是最简单的方式是直接从 DOM 获取。

值得注意的是,我们可以覆盖视图中的默认功能,从请求对象中获取用户名。然而,最好按照预期使用基于 DRF 类的视图:在 JSON 请求中传递所有适当的参数——例如,textauthor——然后使用序列化程序保存它们。

在“模板/对话”目录下打开index.html。在文件的顶部,您会看到我们直接从request对象访问用户名:

<h2>Hi, {{request.user.username}}</h2>

让我们隔离实际的用户名,以便更容易用 jQuery 获取:

<h2>Hi, <span id="user">{{request.user.username}}</span></h2>

现在再次更新data:

data  :  {  text  :  $('#post-text').val(),  author:  $('#user').text()}

测试一下;一切都会好的。

基于通用的视图

想要事半功倍?看看这个。注释掉我们刚刚添加的代码,然后像这样更新视图:

from talk.models import Post
from talk.forms import PostForm
from talk.serializers import PostSerializer
from rest_framework import generics
from django.shortcuts import render

def home(request):
    tmpl_vars = {'form': PostForm()}
    return render(request, 'talk/index.html', tmpl_vars)

#########################
### class based views ###
#########################

class PostCollection(generics.ListCreateAPIView):
    queryset = Post.objects.all()
    serializer_class = PostSerializer

class PostMember(generics.RetrieveUpdateDestroyAPIView):
    queryset = Post.objects.all()
    serializer_class = PostSerializer

因此,我们不仅可以像以前一样处理所有相同的请求,还可以处理更新每个成员的 PUT 请求。更多。给很多少。

在继续之前,跳回基于函数的视图,将代码与基于类的视图进行比较。哪个更容易阅读?其实哪个更好理解?如有必要,添加注释,以帮助您更好地理解基于类的视图背后发生的事情。

你不仅牺牲了基于类的视图的可读性,而且测试也更加困难。然而,我们现在利用了继承,对于有许多相似视图的大型项目,基于类的视图是完美的,因为你不必一遍又一遍地写相同的代码。在跳到基于阶级的观点之前,一定要权衡利弊。

在继续之前,一定要测试端点。

  1. 确保所有帖子都已加载
  2. 添加新帖子
  3. 删除一个帖子

对 PUT 请求感到好奇?通过 HTML 表单从可浏览的 API(即http://localhost:8000/API/v1/posts/1/)中测试它。想要完全删除 PUT 方法处理程序吗?像这样更新代码:

class PostMember(generics.RetrieveDestroyAPIView):
    queryset = Post.objects.all()
    serializer_class = PostSerializer

现在测试一下。有问题吗?查看文档

Remove ads

结论

暂时就这些了。在以后的文章中,我们可能会跳回到 Django Rest 框架来看看分页、权限和基本验证,但在此之前,我们将在前端添加 AngularJS 来消费数据。

干杯!***