表单 form
此后的 app 名以 polls 为例
<h1>{{ question.question_text }}</h1>
{% if error_message %}
<p>
<strong>{{ error_message }}</strong>
</p>
{% endif %}
<form action="{% url 'polls:vote' question.id %}" method="post">
{% csrf_token %}
{% for choice in question.choice_set.all %}
<input type="radio" name="choice" id="choice{{ forloop.counter }}" value="{{ choice.id }}">
<label for="choice{{ forloop.counter }}">{{ choice.choice_text }}</label><br>
{% endfor %}
<input type="submit" value="Vote">
</form>
简要说明:
- 上面的模板显示一系列单选按钮,按钮的值是选项的ID,按钮的名字是字符串"choice"。这意味着,当你选择了其中某个按钮,并提交表单,一个包含数据choice=#的POST请求将被发送到指定的url,#是被选择的选项的ID。这就是HTML表单的基本概念。
- 如果你有一定的前端开发基础,那么form标签的action属性和method属性你应该很清楚它们的含义,action表示你要发送的目的url,method表示提交数据的方式,一般分post和get。
- forloop.counter是Django模板系统专门提供的一个变量,用来表示你当前循环的次数,一般用来给循环项目添加有序数标。
- 由于我们发送了一个POST请求,就必须考虑一个跨站请求伪造的安全问题,简称CSRF(具体含义请百度)。Django为你提供了一个简单的方法来避免这个困扰,那就是在form表单内添加一条
{% csrf_token %}
标签,标签名不可更改,固定格式,位置任意,只要是在form表单内。这个方法对form表单的提交方式方便好使,但如果是用ajax
的方式提交数据,那么就不能用这个方法了。
使用通用视图:减少重复代码
具有类似的业务逻辑,实现类似的功能:通过从URL传递过来的参数去数据库查询数据,加载一个模板,利用刚才的数据渲染模板,返回这个模板。由于这个过程是如此的常见,Django很善解人意的帮你想办法偷懒,于是它提供了一种快捷方式,名为“通用视图”。
现在,让我们来试试看将原来的代码改为使用通用视图的方式,整个过程分三步走:
- 修改URLconf设置
- 删除一些旧的无用的视图
- 采用基于类视图的新视图
Django的视图类型可以分为函数视图和类视图,也就是FBV和CBV,两者各有优缺点,CBV不一定就高大上。大多数场景下,函数视图更简单易懂,代码量更少。但是在需要继承、封装某些视图的时候,CBV就能发挥优势。
改良URLconf
打开polls/urls.py文件,将其修改成下面的样子:
from django.urls import path
from . import views
app_name = 'polls'
urlpatterns = [
path('', views.IndexView.as_view(), name='index'),
path('<int:pk>/', views.DetailView.as_view(), name='detail'),
path('<int:pk>/results/', views.ResultsView.as_view(), name='results'),
path('<int:question_id>/vote/', views.vote, name='vote'),
]
在这里,我们使用了两种通用视图ListView和DetailView(它们是作为父类被继承的)。这两者分别代表“显示一个对象的列表”和“显示特定类型对象的详细页面”的抽象概念。
- 每一种通用视图都需要知道它要作用在哪个模型上,这通过model属性提供。
- DetailView 及其子类需要从url捕获到的称为"pk"的主键值,所以需要修改url中的参数
默认情况下,DetailView
通用视图使用一个称作<app name>/<model name>_detail.html
的模板。在本例中,实际使用的是polls/detail.html
。template_name
属性就是用来指定这个模板名的,用于代替自动生成的默认模板名。(一定要仔细观察上面的代码,对号入座,注意细节。)同样的,在results列表视图中,指定template_name
为polls/results.html
,这样就确保了虽然resulst
视图和detail
视图同样继承了DetailView
类,使用了同样的model:Qeustion
,但它们依然会显示不同的页面.
类似的,ListView
通用视图使用一个默认模板称为<app name>/<model name>_list.html
。我们也使用template_name
这个变量来告诉ListView
使用我们已经存在的 "polls/index.html"模板,而不是使用它自己默认的那个。