Django-port4

2020-06-29  本文已影响0人  一技破万法

表单form

为了接收用户的投票选择,我们需要在前端页面显示一个投票界面。让我们重写先前的polls/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>

简要说明:

path('<int:question_id>/vote/', views.vote, name='vote'),

以及“占坑”的vote视图函数(polls/views.py),我们把坑填起来:

from django.http import HttpResponse, HttpResponseRedirect
from django.shortcuts import get_object_or_404, render
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):     
        return render(request, 'polls/detail.html', {
            'question': question,
            'error_message': "You didn't select a choice.",
        })
    else:
        selected_choice.votes += 1
        selected_choice.save()       
        return HttpResponseRedirect(reverse('polls:results', args=(question.id,)))

有些新的东西,我们要解释一下:

from django.shortcuts import get_object_or_404, render
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/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>

现在你可以到浏览器中访问/polls/1/了,投票吧。你会看到一个结果页面,每投一次,它的内容就更新一次。如果你提交的时候没有选择项目,则会得到一个错误提示。

使用通用视图

三步将原来的代码改成使用通用视图的方式:

修改URLconf设置

打开polls/urls.py文件,将其修改成下面的样子:

修改视图

接下来,打开polls/views.py文件,删掉index、detail和results视图,替换成Django的通用视图,如下所示:

from django.http import HttpResponseRedirect
from django.shortcuts import get_object_or_404, render
from django.urls import reverse
from django.views import generic

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):
    ... # 同前面的一样,不需要修改

在这里,我们使用了两种通用视图ListView和DetailView(它们是作为父类被继承的)。这两者分别代表“显示一个对象的列表”和“显示特定类型对象的详细页面”的抽象概念。

默认情况下,DetailView通用视图使用一个称作<app name>/<model name>_detail.html的模板。在本例中,实际使用的是polls/detail.html。template_name属性就是用来指定这个模板名的,用于代替自动生成的默认模板名。(一定要仔细观察上面的代码,对号入座,注意细节。)同样的,在resutls列表视图中,指定template_name为'polls/results.html',这样就确保了虽然resulst视图和detail视图同样继承了DetailView类,使用了同样的model:Qeustion,但它们依然会显示不同的页面。(模板不同嘛!so easy!)

类似的,ListView通用视图使用一个默认模板称为<app name>/<model name>_list.html。我们也使用template_name这个变量来告诉ListView使用我们已经存在的 "polls/index.html"模板,而不是使用它自己默认的那个。

在教程的前面部分,我们给模板提供了一个包含question和latest_question_list的上下文变量。而对于DetailView,question变量会被自动提供,因为我们使用了Django的模型(Question),Django会智能的选择合适的上下文变量。然而,对于ListView,自动生成的上下文变量是question_list。为了覆盖它,我们提供了context_object_name属性,指定说我们希望使用latest_question_list而不是question_list。

现在可以运行开发服务器,然后试试基于类视图的应用程序了

一技破万法
上一篇 下一篇

猜你喜欢

热点阅读