使用通用视图编辑数据

已完成

与显示数据所需的代码一样,允许用户修改数据的代码也是重复的。 这也可能很繁琐,因为需要执行几个步骤来确保数据有效并正确发送。 幸运的是,通用视图系统可简化启用此功能所需的代码量。

创建新项

在探讨 Django 如何简化开发之前,应回顾允许用户修改数据的过程。 让我们探讨一下服务器用于管理创建新项或数据的过程的工作流,以及创建 HTML 窗体的工作。

创建工作流

从表面上看,允许用户创建项的代码似乎微不足道。 事实证明,这是一个比想象中更重要的过程。

  1. 用户发送一个 GET 请求,表示他们希望窗体创建一个新项。
  2. 服务器发送带有特殊标记的窗体以防止跨网站请求伪造 (CSRF)
  3. 用户完成窗体并选择“提交”,这将发送 POST 请求以指示窗体已完成。
  4. 服务器验证 CSRF 令牌,以确保未发生篡改。
  5. 服务器对所有信息进行验证,以确保其满足规则。 如果验证失败,将返回一条错误消息。
  6. 服务器尝试将项保存到数据库。 如果失败,将向用户返回一条错误消息。
  7. 成功保存新项后,服务器会将用户重定向到成功页。

此过程需要非常多的代码! 大部分都是样板代码,这意味着每次创建它时都是一样的。

窗体

创建 HTML 窗体可能比较繁琐。 开发人员通常会复制粘贴 input 标记,遍历列表以创建下拉列表并设置单选按钮。 每当模型发生更改时,必须更新窗体。

你可能已注意到,我们在 Django 中创建的模型包含创建窗体所需的所有内容。 添加各个字段后,我们指示数据类型,这些数据类型与不同的 HTML 元素耦合在一起。 例如,一个布尔字段将是一个复选框,而一个外键通常是一个下拉列表。

用于修改数据的通用视图

Django 的主要目标之一是消除不断重新创建相同代码块的需要。 为了支持此数据修改目标,Django 提供了一组通用类和窗体来为我们管理此工作负载。 如我们所见,它包括所有必要的代码,甚至可以为我们动态创建窗体。 用于创建、更新和删除数据的类称为 CreateViewUpdateViewDeleteView

CreateUser

CreateView 用于允许用户创建项。 它将执行前面的过程并动态创建窗体。 成功后,它将显示新创建的项的详细信息页。

可以指定要与之关联的 modeltemplate_name,就像对其他通用视图执行的操作一样。 CreateView 的主要区别在于包含了 fields 属性,可以在其中列出可编辑字段。 通过使用此属性,可以确保不会在窗体上显示不应编辑的字段(例如创建日期)。 用于创建新狗的视图可能类似于以下示例:

from . import models
from django.views import generic

class DogCreateView(generic.CreateView):
    model = models.Dog
    template_name = 'dog_form.html'
    fields = ['name', 'description', 'shelter']

UpdateView

UpdateView 的行为方式与 CreateView 相同。 唯一的区别在于,它会根据 pk 参数自动加载项。 Django 使用此约定作为项的主键。

from . import models
from django.views import generic

class DogUpdateView(generic.CreateView):
    model = models.Dog
    template_name = 'dog_form.html'
    fields = ['name', 'description', 'shelter']

成功创建或更新某一项后,Django 将重定向到该项的详细信息页。 它通过在关联的模型上使用 get_absolute_url 来检索详细信息的 URL。 你通过返回正确的 URL 来实现此方法。 可以使用 reverse 从 URLconf 中检索相应的 URL。 请注意,kwargs 用于将 pk 或主键参数传递给路由。

from django.db import models
# TODO: Import reverse
from django.urls import reverse
class Dog(models.Model):
    # Existing code
    def get_absolute_url(self):
        return reverse('dog_detail', kwargs={"pk": self.pk})

DeleteView

DeleteViewUpdateView 类似。 它允许用户删除项并使用 pk 标识要删除的项。 与 UpdateView 不同,fields 不是必需的,因为你将删除整个项。 此外,由于未新创建或更新任何项,我们需要确定要将用户重定向到的位置。 可以通过将 success_url 设置为适当的值来创建重定向。 可以使用 reverse_lazy 查找 URL。

from . import models
from django.views import generic
from django.urls import reverse_lazy

class AuthorDelete(DeleteView):
    model = Author
    success_url = reverse_lazy('author-list')

备注

鉴于将信息加载到 Django 中的顺序,我们使用 reverse_lazy

用于创建和更新的窗体模板

通用视图可以为我们动态创建 HTML 窗体。 我们只需提供一个模板,用作窗体的占位符。 占位符模板可确保窗体与网站的其余部分相匹配。 幸运的是,我们不需要使用很多代码来创建它。

通用视图会自动为我们的模板创建一个 form 变量。 Django 提供的窗体元素可以显示在 <p> 标记内或显示为 <table>

form 变量包含用于从窗体创建控件的所有适当的 HTML。 它本身不包含 <form> 标记或“提交”按钮。 模板必须包含四个项:

  • 将具有 methodform 元素设置为“POST”,因为此设置会触发服务器上的保存操作。
  • 用于添加 CSRF 令牌以防止欺骗的代码 {% csrf_token %}
  • 用于显示动态生成的窗体的代码 {{ form.as_p }}{{ form.as_table }}
  • submit 按钮。

下面的代码可用作任何通用视图窗体的宿主。

<form method="post">{% csrf_token %}
    {{ form.as_p }}
    <button type="submit">Save</button>
</form>