经过前面的努力,到这里我们已经基本完成了,从服务器到浏览器的数据下发,还没有解决从浏览器到服务器的数据上传,这一节将创建一个Form获取从浏览器提交的数据

1.新建Form

接着前面建的项目,网上调查,每一个Question有多个Choice,当用户针对特定问题,可以提交选择,数据库记录每个Choice的vote数,所以新建:

polls/templates/detail.html

编写代码如下:

<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>

{% csrf_token %} django为了防止跨站点伪造请求,POST Form 应当在请求中使用{% csrf_token%}标签

{% url 'polls:vote' question.id %}的写法,是为了防止页面硬编码[查看上一篇内容],引入的url的另一种写法, polls:vote 的写法是给polls/urls.py 加了url命名空间:

 from django.urls import path
from . import views
app_name="polls"
urlpatterns=[
path('',views.index,name='index'),
path('<int:question_id>/detail',views.detail,name="detail"), #定义detail view
path('<int:question_id>/results',views.results,name='results'),#定义格式:/参数[参数类型为int]/results
#这里将原来的vote/<int:question_id>改成<Vote/<int:question_id>
path('vote/<int:question_id>',views.vote,name='vote') #定义格式:vote/参数[参数类型为int]
]

上面建的表单要提交一个question_id 和 Choice_Id 到 /vote view,为了表单提交数据的安全性,这里指定使用POST传输,这点view没有特别要求,改造view/vote 对指定的question_id的choice_id的votes+1

2.接收Form数据并处理业务

修改polls/views.py/vote如下,(为了方便对比这里贴出来整个Views.py):

 from django.shortcuts import get_object_or_404, render
from django.http import HttpResponseRedirect, HttpResponse
from django.urls import reverse 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'])
except (KeyError, Choice.DoesNotExist):
# Redisplay the question voting form.
return render(request, 'polls/detail.html', {
'question': question,
'error_message': "You didn't select a choice.",
})
else:
selected_choice.votes += 1
selected_choice.save()
# Always return an HttpResponseRedirect after successfully dealing
# with POST data. This prevents data from being posted twice if a
# user hits the Back button.
return HttpResponseRedirect(reverse('polls:results', args=(question.id,))) def index(request):
latest_question_list = Question.objects.order_by('-pub_date')[:5] context = {
'latest_question_list': latest_question_list,
}
return render(request,'polls/index.html',context)
# ...
def detail(request, question_id):
question = get_object_or_404(Question, pk=question_id)
return render(request, 'polls/detail.html', {'question': question}) def results(request, question_id):
question = get_object_or_404(Question, pk=question_id)
return render(request, 'polls/results.html', {'question': question})

编辑polls/templates/polls/index.html如下:

{% if latest_question_list %}
<ul>
{% for question in latest_question_list %}
<li><a href="{% url 'polls:detail' question.id %}">{{ question.question_text }}</a></li>
{% endfor %}
</ul>
{% else %}
<p>No polls are available.</p>
{% endif %}

以上完成了投票功能,最后需要对投票的结果进行展示,新建网页:polls/templates/polls/results.html

<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>

启动站点,浏览http://localhost:8000/polls/

投票完成之后,查询数据:

3.view改良

首先每张表都有主键,对polls/urls.py的改良就是将<int:question_id>替换成<int:pk>

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'),
]

polls/views.py中原来定义的index,detail,results 换成 Django generic的view


 from django.shortcuts import get_object_or_404, render
from django.http import HttpResponseRedirect
from django.urls import reverse
from django.views import generic
from django.utils import timezone from .models import Choice, Question class IndexView(generic.ListView):
template_name = 'polls/index.html'
context_object_name = 'latest_question_list' def get_queryset(self):
"""Return the last five published questions."""
return Question.objects.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' 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'])
except (KeyError, Choice.DoesNotExist):
# Redisplay the question voting form.
return render(request, 'polls/detail.html', {
'question': question,
'error_message': "You didn't select a choice.",
})
else:
selected_choice.votes += 1
selected_choice.save()
# Always return an HttpResponseRedirect after successfully dealing
# with POST data. This prevents data from being posted twice if a
# user hits the Back button.
return HttpResponseRedirect(reverse('polls:results', args=(question.id,)))

view vote牵涉到表单提交,数据库的操作,所以没有使用通用view改造

Django App(四) Submit a form的更多相关文章

  1. Django App(六) Customing Admin Form

    这一篇主要是呼应第二篇时留下来的一个问题,就是如何自定义默认app admin下的Form  1.绑定数据实体 通过第二篇的努力,已经完成了数据实体到数据库的映射,可以将界面的更改保存到数据库,我们建 ...

  2. frist Django app — 四、 完善View

    上一篇已经完成了polls的基本功能,接下来完善剩下的vote功能和并使用generic views改进请求处理view.包含表单的简单运用和前后台参数传递. 目录 vote:完善投票功能 gener ...

  3. Django 2.0.1 官方文档翻译: 编写你的第一个 Django app,第四部分(Page 9)

    编写你的第一个 Django app,第四部分(Page 9)转载请注明链接地址 该教程上接前面的第三部分.我们会继续开发 web-poll 应用,并专注于简单的表单处理和简化代码. 写一个简单的表单 ...

  4. python笔记-20 django进阶 (model与form、modelform对比,三种ajax方式的对比,随机验证码,kindeditor)

    一.model深入 1.model的功能 1.1 创建数据库表 1.2 操作数据库表 1.3 数据库的增删改查操作 2.创建数据库表的单表操作 2.1 定义表对象 class xxx(models.M ...

  5. Python-Django 第一个Django app

    第一个Django app   by:授客 QQ:1033553122 测试环境: Python版本:python-3.4.0.amd64 下载地址:https://www.python.org/do ...

  6. day 68 Django基础四之模板系统

      Django基础四之模板系统   本节目录 一 语法 二 变量 三 过滤器 四 标签Tags 五 模板继承 六 组件 七 自定义标签和过滤器 八 静态文件相关 一 语法   模板渲染的官方文档 关 ...

  7. day 54 Django基础四之模板系统

    Django基础四之模板系统   本节目录 一 语法 二 变量 三 过滤器 四 标签Tags 五 模板继承 六 组件 七 自定义标签和过滤器 八 静态文件相关 一 语法   模板渲染的官方文档 关于模 ...

  8. Struts(十四):通用标签-form表单

    form标签是struts2标签中一个重要标签: 可以生成html标签,使用起来和html的form标签差不多: Strut2的form标签会生成一个table,进行自动布局: 可以对表单提交的值进行 ...

  9. Django基础(四)

    Django-4 知识预览 分页器(paginator) COOKIE 与 SESSION Django的用户认证 FORM 回到顶部 分页器(paginator) 分页器的使用 1 2 3 4 5 ...

随机推荐

  1. 查看内存和cpu

    top: 主要参数 d:指定更新的间隔,以秒计算. q:没有任何延迟的更新.如果使用者有超级用户,则top命令将会以最高的优先序执行. c:显示进程完整的路径与名称. S:累积模式,会将己完成或消失的 ...

  2. c#全宇宙最牛的编程软件

    c#走的道路!PC,PD,电脑一体,一个账户就可以三合一,可以跨平台的编程,在未来的道路如果微软能一直走下去,那么c#将成为宇宙最牛B的编程软件.

  3. MySQL 字符集问题及安全的更新操作

    一.字符集乱码 1.操作系统字符集 [root@mysql5 ~]# cat /etc/system-release /etc/sysconfig/i18n CentOS release 6.5 (F ...

  4. Raspberry Pi中可用的Go IDE:liteide

    p { margin-bottom: 0.25cm; line-height: 120% } a:link { } Raspberry Pi中可用的Go IDE:liteide p { margin- ...

  5. python3.5 + PyQt5 +Eric6 实现的一个计算器

    目前可以实现简单的计算.计算前请重置,设计的时候默认数字是0,学了半天就做出来个这么个结果,bug不少. python3.5 + PyQt5 +Eric6 在windows7 32位系统可以完美运行 ...

  6. unity创建和加载AssetBundle

    先说一下为什么要使用AssetBundle吧,以前做东西一直忽略这个问题,现在认为这个步骤很重要,代码是次要的,决策和为什么这样搞才是关键. 一句话概括吧,AssetBundle实现了资源与服务分离, ...

  7. jquery获取select选中的值

    http://blog.csdn.net/renzhenhuai/article/details/19569593 误区: 一直以为jquery获取select中option被选中的文本值,是这样写的 ...

  8. Android 获取唯一标识替代方法

    private static String getTheOnlyID() { String onlyOne; //获取IMEI TelephonyManager TelephonyMgr = (Tel ...

  9. Winform跨窗体操作控件(使用委托)

    Winform跨窗体操作控件是winform开发中很常见的形式,最常见且简单有效的方式便是使用委托的方式来进行操作,下面我将通过一个小实例来说明如何使用委托跨窗体实现控件操作. 实例介绍:两个窗体,F ...

  10. Java中ArrayList与LinkedList的区别

    Java中ArrayList与LinkedList的区别 一般大家都知道ArrayList和LinkedList的区别: 1. ArrayList的实现是基于数组,LinkedList的实现是基于双向 ...