使用通用视图编辑数据
与显示数据所需的代码一样,允许用户修改数据的代码也是重复的。 这也可能很繁琐,因为需要执行几个步骤来确保数据有效并正确发送。 幸运的是,通用视图系统可简化启用此功能所需的代码量。
创建新项
在探讨 Django 如何简化开发之前,应回顾允许用户修改数据的过程。 让我们探讨一下服务器用于管理创建新项或数据的过程的工作流,以及创建 HTML 窗体的工作。
创建工作流
从表面上看,允许用户创建项的代码似乎微不足道。 事实证明,这是一个比想象中更重要的过程。
- 用户发送一个 GET 请求,表示他们希望窗体创建一个新项。
- 服务器发送带有特殊标记的窗体以防止跨网站请求伪造 (CSRF)。
- 用户完成窗体并选择“提交”,这将发送 POST 请求以指示窗体已完成。
- 服务器验证 CSRF 令牌,以确保未发生篡改。
- 服务器对所有信息进行验证,以确保其满足规则。 如果验证失败,将返回一条错误消息。
- 服务器尝试将项保存到数据库。 如果失败,将向用户返回一条错误消息。
- 成功保存新项后,服务器会将用户重定向到成功页。
此过程需要非常多的代码! 大部分都是样板代码,这意味着每次创建它时都是一样的。
窗体
创建 HTML 窗体可能比较繁琐。 开发人员通常会复制粘贴 input
标记,遍历列表以创建下拉列表并设置单选按钮。 每当模型发生更改时,必须更新窗体。
你可能已注意到,我们在 Django 中创建的模型包含创建窗体所需的所有内容。 添加各个字段后,我们指示数据类型,这些数据类型与不同的 HTML 元素耦合在一起。 例如,一个布尔字段将是一个复选框,而一个外键通常是一个下拉列表。
用于修改数据的通用视图
Django 的主要目标之一是消除不断重新创建相同代码块的需要。 为了支持此数据修改目标,Django 提供了一组通用类和窗体来为我们管理此工作负载。 如我们所见,它包括所有必要的代码,甚至可以为我们动态创建窗体。 用于创建、更新和删除数据的类称为 CreateView
、UpdateView
和 DeleteView
。
CreateUser
类 CreateView
用于允许用户创建项。 它将执行前面的过程并动态创建窗体。 成功后,它将显示新创建的项的详细信息页。
可以指定要与之关联的 model
和 template_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
类 DeleteView
与 UpdateView
类似。 它允许用户删除项并使用 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>
标记或“提交”按钮。 模板必须包含四个项:
- 将具有
method
的form
元素设置为“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>