Django 2.1 Polls实战 创建视图和表单(2)

188 阅读3分钟
原文链接: zhuanlan.zhihu.com

代码地址:

https://github.com/Danielyan86/Django-Polls.gitgithub.com

参考教程:

Writing your first Django app, part 3

Writing your first Django app, part 4

创建更多的视图

Django的视图层是用来处理前端页面的请求的方法,在Django里面可以通过简单的匹配规则找到后端的方法。

在这个poll应用中,我们定义四个主要views:

  1. 问题索引页面(index)-显示最新的问题
  2. 详细页面(details)- 显示问题内容
  3. 结果页面(results)- 显示一个特定问题的结果
  4. 投票页面(vote)- 处理一个问题的投票

views通过url的匹配模式找到对应的方法,以index页面为例:

顶层mysite.urls定义了第一级URL的访问路径的匹配模式:

urlpatterns = [
    path('admin/', admin.site.urls),
    path('polls/', include('polls.urls')),
    path('', include('polls.urls')),
    path('index/', include('polls.urls')),
]

通过include 加载下级的URL匹配模式到urls里面,比如polls.url里面定义的url pattern

Django也支持更复杂的url模式匹配,比如加了<int:question_id>标签

urlpatterns = [
    path('', views.index, name='index'),
    # ex: /polls/5/  通过view.detail 找到对应的在view里面定义的detail方法
    path('<int:question_id>/', views.detail, name='detail'),
    # ex: /polls/5/results/
    path('<int:question_id>/results/', views.results, name='results'),
    # ex: /polls/5/vote/
    path('<int:question_id>/vote/', views.vote, name='vote'),
]

当我们访问http://127.0.0.1:8000/index/ 时候index方法会接收到前端的一个http请求,这个请求封装在request里面,然后通过path('', views.index, name='index')找到了polls里面定义的index方法,index方法处理请求之后返回相应的内容到前端:

# use template
def index(request):
    # return HttpResponse("Hello, world. You're at the polls index.")
    latest_question_list = Question.objects.order_by('-pub_date')[:5] # 取出对象按时间排序,然后取前五个
    context = {'latest_question_list': latest_question_list} #定义模板渲染的字典
    return render(request, 'polls/index.html', context)      #渲染模板,返回http response给前端

这里面没有直接返回内容,而是通过django的模板引擎渲染了一个我们在templates下面自定的一个模板

模板渲染路径:

可以在settings里面的TEMPLATES配置,默认会从templates里面找

模板内容

{#如果latest_question_list变量存在,则加载下面的代码#}
{% if latest_question_list %}
    <ul>
        {#遍历latest_question_list里面的值#}
        {% for question in latest_question_list %}
            {#取出对应的值#}
            <li><a href="{% url 'detail' question.id %}">{{ question.question_text }}</a></li>
        {% endfor %}
    </ul>
{% else %}
    <p>No polls are available.</p>
{% endif %}

访问127.0.0.1:8000/index 得到以下内容:

命名空间

模板里面使用URL标签来寻找对应的url

<li><a href="{% url 'detail' question.id %}">{{ question.question_text }}</a></li>

如果有更多的应用,比如poll2,polls3,怎么来区分呢?答案是通过命名空间

在urls里面添加app_name

from . import views

app_name = 'polls'
urlpatterns = [

更新模板:

<li><a href="{% url 'polls:detail' question.id %}">{{ question.question_text }}</a></li>

问题显示部分完成了,接下我们需要完成投票功能,这个时候需要创建提交表单页面。

提交表单

通过在前端创建表单提交功能,向后端发起一个post的数据提交请求,也就是我们的投票工程

创建模板:

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

投票页面刚开始还没有显示数据,因为数据库对应的choice表还没有数据,通过脚本write_data_into_DB.py 添加数据到数据库,这时可以再投票页面开始投票了

对应投票的视图代码:

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  # 投票结果写入DB
        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,)))

说明:

  1. request.POST是一个字典,里面存储了前端post过来的数据,通过key找到全段提交的内容
  2. request.POST['choice']会报出keyError异常,添加try-except代码处理异常
  3. 完成投票之后使用HttpResponseRedirect跳转到结果页面

投票之后可以看到结果:

到这时,一个简单的投票器应用完成了。