发布于 2026-01-06 5 阅读
0

轻松将 Django 基于函数的视图转换为基于类的视图

轻松将 Django 基于函数的视图转换为基于类的视图

在本教程中,我将使用基于函数的视图 (FBV) 构建一个简单的笔记应用程序,并将其转换为基于类的视图 (CBV)。

本文将作为 YouTube 教程的指南,因此我建议观看完整的视频教程并参考源代码

我们基于功能的观点

让我们先快速看一下我们目前的观点。

我们的视图文件包含用于执行创建、读取、更新和删除笔记的基本 CRUD 操作的视图。

def TaskList(request):
    if request.method == 'GET':
        tasks = Task.objects.all().order_by('-updated')
        context = {'tasks':tasks}
        return render(request, 'base/index.html', context)

    if request.method == 'POST':
        task = Task.objects.create(
            body=request.POST.get('body')
        )
        task.save()
        return redirect('tasks')

## ------------------------------------------------------

def TaskDetail(request, pk):
    if request.method == 'GET':
        task = Task.objects.get(id=pk)
        context = {'task':task}
        return render(request, 'base/task.html', context)

    if request.method == 'POST':
        task = Task.objects.get(id=pk)
        task.body = request.POST.get('body')
        task.save()
        return redirect('tasks')

## ------------------------------------------------------

def TaskDelete(request, pk):
    task = Task.objects.get(id=pk)

    if request.method == 'POST':
        task.delete()
        return redirect('tasks')

    context = {'task':task}   
    return render(request, 'base/delete.html', context)
Enter fullscreen mode Exit fullscreen mode

保持我们基于阶级的观点

基于类的视图之所以复杂,并非因为它们难以使用,而是因为它们存在一层抽象,这使得我们难以理解其具体运作机制以及如何修改它们。Django 提供了许多内置视图供我们选择,这有助于快速开发,但如果您不了解这些视图的来龙去脉,反而可能会感到困惑,因为底层有很多“魔法”。

因此,我不会使用内置视图,而是保持原始状态,只扩展 Django 提供的基础视图,并从头开始编写所有逻辑,这样您就可以看到基于类的视图与基于函数的视图有何异同。

关于基于类的视图的一些事项

在开始之前,我想先让你了解一些关于基于类的视图的知识。

扩展基类 View

每个基于类的视图都继承自基View类。由于我们没有使用任何其他内置视图,请确保导入View“View”并将其传递给每个类:

from django.views import View
...
class OurView(View):
Enter fullscreen mode Exit fullscreen mode

通过 HTTP 方法进行分离

使用基于类的视图,我们将代码拆分为 HTTP 动词。因此,我们无需执行类似 `get()` 这样的操作if request.method == 'POST',只需修改类post提供的方法View,让该方法处理请求时发生的一切post。请求也是如此get

前任:

class OurView(View):
    def get(self, request):
        pass

    def post(self, request):
        pass
Enter fullscreen mode Exit fullscreen mode

让我们从第一个视图开始。

任务列表视图

让我们把这个视图注释掉TaskList,然后从头开始重建它。

现在我们将视图重写为一个类,并使其继承自View该类。我们还要向这个新类添加两个方法(get& post),并确保在每个方法中都传入self参数。request

有了类和两个方法之后,让我们从基于函数的视图中提取逻辑,并根据每个 HTTP 方法将其添加到新类中,如下所示:

from django.views import View
....
class TaskList(View):

    def get(self, request):
        tasks = Task.objects.all().order_by('-updated')
        context = {'tasks':tasks}
        return render(request, 'base/index.html', context)

    def post(self, request):
        task = Task.objects.create(
            body=request.POST.get('body')
        )
        task.save()
        return redirect('tasks')
Enter fullscreen mode Exit fullscreen mode

现在要使用此视图,我们需要在 urls.py 中引用该类,然后使用该as_view()方法。

path('', views.TaskList.as_view(), name="tasks"),
Enter fullscreen mode Exit fullscreen mode

就这样,我们把第一个基于函数的视图转换成了基于类的视图!

任务详情视图

现在让我们对TaskDetail. 同样地,我们将注释掉基于函数的视图,并将所有逻辑提取出来并分离到 http 方法中。

class TaskDetail(View):
    def get(self, request, pk):
        task = Task.objects.get(id=pk)
        context = {'task':task}
        return render(request, 'base/task.html', context)

    def post(self, request, pk):
        task = Task.objects.get(id=pk)
        task.body = request.POST.get('body')
        task.save()
        return redirect('tasks')
Enter fullscreen mode Exit fullscreen mode

然后将其添加as_view()到调用此视图时的 URL 路径中。

path('<str:pk>/', views.TaskDetail.as_view(), name="task"),
Enter fullscreen mode Exit fullscreen mode

任务删除视图

我相信你现在应该已经开始看出规律了,所以我们对“删除”视图也做同样的事情。

class TaskDelete(View):
    def get(self, request, pk):
        task = Task.objects.get(id=pk)
        context = {'task':task}   
        return render(request, 'base/delete.html', context)

    def post(self, request, pk):
        task = Task.objects.get(id=pk)
        task.delete()
        return redirect('tasks')
Enter fullscreen mode Exit fullscreen mode
path('<str:pk>/delete/', views.TaskDelete.as_view(), name="delete"),
Enter fullscreen mode Exit fullscreen mode

让我们回顾一下我们做了什么。

对于每个视图,我们:

  • 改为defclass
  • 扩展了基View
  • 按方法分离逻辑,并在请求之前http添加。self
  • 添加as_view()到每个视图中urls.py
文章来源:https://dev.to/dennisivy11/easily-convert-django-function-based-views-to-class-based-views-3okb