Django App(四) Submit a form

      经过前面的努力,到这里我们已经基本完成了,从服务器到浏览器的数据下发,还没有解决从浏览器到服务器的数据上传,这一节将创建一个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命名空间:

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

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

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

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

 1 from django.shortcuts import get_object_or_404, render
 2 from django.http import HttpResponseRedirect, HttpResponse
 3 from django.urls import reverse
 4 
 5 from .models import Choice, Question
 6 # ...
 7 def vote(request, question_id):
 8     question = get_object_or_404(Question, pk=question_id)
 9     try:
10         selected_choice = question.choice_set.get(pk=request.POST['choice'])
11     except (KeyError, Choice.DoesNotExist):
12         # Redisplay the question voting form.
13         return render(request, 'polls/detail.html', {
14             'question': question,
15             'error_message': "You didn't select a choice.",
16         })
17     else:
18         selected_choice.votes += 1
19         selected_choice.save()
20         # Always return an HttpResponseRedirect after successfully dealing
21         # with POST data. This prevents data from being posted twice if a
22         # user hits the Back button.
23         return HttpResponseRedirect(reverse('polls:results', args=(question.id,)))
24 
25 def index(request):
26     latest_question_list = Question.objects.order_by('-pub_date')[:5]
27 
28     context = {
29         'latest_question_list': latest_question_list,
30     }
31     return  render(request,'polls/index.html',context)
32 # ...
33 def detail(request, question_id):
34     question = get_object_or_404(Question, pk=question_id)
35     return render(request, 'polls/detail.html', {'question': question})
36 
37 def results(request, question_id):
38     question = get_object_or_404(Question, pk=question_id)
39     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 


 1 from django.shortcuts import get_object_or_404, render
 2 from django.http import HttpResponseRedirect
 3 from django.urls import reverse
 4 from django.views import generic
 5 from django.utils import timezone
 6 
 7 from .models import Choice, Question
 8 
 9 
10 class IndexView(generic.ListView):
11     template_name = 'polls/index.html'
12     context_object_name = 'latest_question_list'
13 
14     def get_queryset(self):
15         """Return the last five published questions."""
16         return Question.objects.order_by('-pub_date')[:5]
17 
18 
19 class DetailView(generic.DetailView):
20     model = Question
21     template_name = 'polls/detail.html'
22 
23 
24 class ResultsView(generic.DetailView):
25     model = Question
26     template_name = 'polls/results.html'
27 
28 def vote(request, question_id):
29     question = get_object_or_404(Question, pk=question_id)
30     try:
31         selected_choice = question.choice_set.get(pk=request.POST['choice'])
32     except (KeyError, Choice.DoesNotExist):
33         # Redisplay the question voting form.
34         return render(request, 'polls/detail.html', {
35             'question': question,
36             'error_message': "You didn't select a choice.",
37         })
38     else:
39         selected_choice.votes += 1
40         selected_choice.save()
41         # Always return an HttpResponseRedirect after successfully dealing
42         # with POST data. This prevents data from being posted twice if a
43         # user hits the Back button.
44         return HttpResponseRedirect(reverse('polls:results', args=(question.id,)))

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

原文地址:https://www.cnblogs.com/andayhou/p/8340994.html