4:表单和通用视图
表单和通用视图
1、编写一个简单的表单(1)更新polls/detail.html文件 使其包含一个html < form > 元素(2)创建一个Django视图来处理提交的数据(3)当有人对 Question 进行投票后,vote()视图将请求重定向到 Question 的结果页面。(4)创建polls/results.html 模板
2、使用通用视图,代码还是少一些比较好3、改良视图
1、编写一个简单的表单
(1)更新polls/detail.html文件 使其包含一个html < form > 元素
<!DOCTYPE html> <html lang="en" xmlns="http://www.w3.org/1999/html"> <head> <meta charset="UTF-8"> <title>Polls Details</title> </head> <body> <h1>{{question.question_text}}</h1> <ul> {% for choice in question.choice_set.all %} <li>{{ choice.choice_text }}</li> {% endfor %} </ul> <form action="{% url polls:vote question.id %}" method="post"> {% csrf_token %} <fieldset> <legend><h1>{{ question.question_text }}</h1></legend> {% if error_message %}<p><strong>{{ error_message }}</strong></p>{% endif %} {% 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 %} </fieldset> <input type="submit" value="Vote"> </form> </body> </html>1234567891011121314151617181920212223242526272829
代码解释
1、表单开始标签: <form action="{% url polls:vote question.id %}" method="post"> <form>:定义表单。 action="{% url polls:vote question.id %}":表单提交的URL,由Django的url模板标签生成,指向名为polls:vote的视图,传递当前问题的ID。 method="post":表单提交方法为POST。 2、CSRF保护:由于我们创建了一个POST表单(它具有修改数据的作用),所以我们要小心跨站点请求伪造 {% csrf_token %}:Django模板标签,用于生成CSRF令牌,防止跨站请求伪造攻击。 3、表单字段集 <fieldset>:将表单控件分组。 <legend><h1>{{ question.question_text }}</h1></legend>:为字段集提供标题,显示投票问题。 {% if error_message %}<p><strong>{{ error_message }}</strong></p>{% endif %}:如果存在错误信息,则显示。 {% for choice in question.choice_set.all %}:遍历问题的所有选项。 <input type="radio" name="choice" id="choice{{ forloop.counter }}" value="{{ choice.id }}">:定义一个单选按钮,name属性用于组名,id属性唯一标识每个单选按钮,value属性为选项ID。 <label for="choice{{ forloop.counter }}">{{choice.choice_text}}</label>:定义单选按钮的标签。 <br>:换行符。 4、提交按钮 <input type="submit" value="Vote">:定义表单的提交按钮。1234567891011121314151617181920
(2)创建一个Django视图来处理提交的数据
将以下代码 添加到 polls.views.py
导入模块 from django.db.models import F #导入F表达式,用于在数据库层面进行字段操作 from django.http import HttpResponse, HttpResponseRedirect from django.shortcuts import get_object_or_404, render from django.urls import reverse #导入reverse函数,用于反向解析URL from .models import Choice, Question #... def vote(request,question_id): #获取投票问题 question=get_object_or_404(Question,pk=question_id) #处理投票请求 try: selected_choice=question.choice_set.get(pk=request.POST["choice"]) #异常处理:捕获KeyError和Choice.DoesNotExist异常,表示用户没有选择任何选项或选择的选项不存在 except(KeyError,Choice.DoesNotExist): #重新渲染投票页面,并显示错误信息 return render(request,"polls/detail.html" ,{"question":question,"error_message":"You didnt select a choice."}) #更新投票数并保存 else: selected_choice.votes=F("votes")+1 selected_choice.save() #重定向到结果页面,生成结果页面的URL return HttpResponseRedirect(reverse("polls:results",args=(question.id,)))12345678910111213141516171819202122232425
(3)当有人对 Question 进行投票后,vote()视图将请求重定向到 Question 的结果页面。
def results(request,question_id): question=get_object_or_404(Question,pk=question_id) return render(request,"polls/results.html",{"question":question}) 123(4)创建polls/results.html 模板
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Polls Results</title> </head> <body> <h1> {{ question.question_text }} </h1> <ul> {% for choice in question.choice_set.all %} <li>{{ choice.choice_text }}--{{ choice.votes}} vote {{ choice.votes|pluralize}}</li> {% endfor %} </ul> <a href="{%url polls:detail question.id %}">Vote again?</a> </body> </html>12345678910111213141516
访问polls/3/并进行投票
注意
如果报错,原因很可能是:args 期望的是一个可迭代对象,但你传递的是一个整数需要确保 args 是一个包含单个元素的元组。在Python中,如果元组只有一个元素,需要在元素后面加一个逗号来明确它是一个元组
2、使用通用视图,代码还是少一些比较好
视图反映基本的网络开发中一个常见情况,根据URL中的参数,从数据库中获取数据,载入模板,返回渲染后的模板。由于这种情况十分常见,Django提供了一种快捷方式——“通用视图”系统
通用视图蒋昌建的模式抽象到了一种地步,不需要编写python代码就可以创建一个应用程序。
1、转换URLconf
2、删除一些旧的、不再需要的视图
3、基于Django的通用视图引入新的视图改良URLconf
修改 polls.url 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"), ] 123456我们将detail和results路径字符串匹配模式名称从<question_id>改成了。这是因为我们将使用通用视图替代原来的视图,它期望从URL中捕获的主键值被称为“pk”
3、改良视图
打开polls/views 删除index detail results视图,用通用视图代替
from django.views import generic class IndexView(generic.ListView): template_name = "polls/index.html" context_object_name = "latest_question_list" def get_queryset(self): return Question.object.order_by("-pub_date")[:5] class DetailView(generic.DetailView): model = Question template_name = "polls/detail.html" class ResultsView(generic.DetailView): model = Question template_name = "polls/results.html" 1234567891011121314template_name属性用来告诉django使用一个指定的模板名字
而不是自动生成的默认名字,template_name 属性允许你指定一个不同于默认命名约定的模板文件名称。通过设置这个属性,你可以让同一个通用视图类在渲染不同内容时使用不同的模板。这使得你可以为不同的视图提供不同的外观和感觉,即使它们在后台使用相同的视图类默认上下文变量名:
DetailView 默认提供的上下文变量名是模型名的小写形式,如 question。
ListView 默认提供的上下文变量名是模型名的小写复数形式,如 question_list。
自定义上下文变量名:
使用 context_object_name 属性,你可以覆盖默认的上下文变量名,使用你想要的变量名。
这是更便捷的方法,而不是修改模板以匹配默认的上下文变量名再次启动服务器
没有问题未完待续…
Ongwu博客 版权声明:以上内容未经允许不得转载!授权事宜或对内容有异议或投诉,请联系站长,将尽快回复您,谢谢合作!