zoukankan      html  css  js  c++  java
  • Django笔记 3

    接下来我们需要设计视图和页面了,一共要有四个视图:index,detail,vote,results,相应的也会有四个页面。

    URL映射

    首先需要解决的就是url映射,django在使用URL时首先找到ROOT_URLCONF这个设置(在settings.py里面),然后加载这个module,寻找里面的一个叫做urlpatterns的变量。它是一个元组,其中每一项的格式是“(regular expression,callback function[,optional dictionary])”。找到这个变量之后就从头到尾地进行匹配,匹配成功之后就调用回调函数,并将HttpRequest作为第一个参数。

    在urls.py里添加关于投票的url映射信息:

    urlpatterns = patterns(’’,
    url(r’^polls/$’, ’polls.views.index’),
    url(r’^polls/(?P<poll_id>\d+)/$’, ’polls.views.detail’),
    url(r’^polls/(?P<poll_id>\d+)/results/$’, ’polls.views.results’),
    url(r’^polls/(?P<poll_id>\d+)/vote/$’, ’polls.views.vote’),
    url(r’^admin/’, include(admin.site.urls)),
    )

    实现视图和模版

    这里的所有view都没有实现,那么,下面就简单实现一下了:

    from django.http import HttpResponse
    
    def index(request):
        return HttpResponse("Hello, world. You’re at the poll index.")
    def detail(request, poll_id):
        return HttpResponse("You’re looking at poll %s." % poll_id)
    def vote(request, poll_id):
        return HttpResponse("You’re voting on poll %s." % poll_id)
    def results(request, poll_id):
        return HttpResponse("You’re looking at the results of poll %s." % poll_id)

    这仅仅是个最简单的示例,以后还要一一实现。要注意,每一个view要么返回一个HttpResponse,要么抛出Http404异常。

    index视图是用来显示投票列表的,为了不显示太多,我们把它修改为只显示最近的5个:

    from django.http import HttpResponse
    from polls.models import Poll
    
    def index(request):
        latest_poll_list=Poll.objects.all().order_by('-pub_date')[:5]
        t=loader.get_template("polls/index.html")
        c=Context({'latest_poll_list':latest_poll_list,})
        return HttpResponse(t.render(c))

    这里用到的就是django里面的模版渲染:载入一个html模版,然后将context传入进去。context是一个字典,字典的项就是模版中要用到的变量。

    我们之前设置过所有模版的根文件夹,即TEMPLATE_DIRS这个变量,只需要在下面建立polls/index.html就行了:

    {% if latest_poll_list %}
    <ul>
    {% for poll in latest_poll_list %}
    <li><a href="/polls/{{ poll.id }}/">{{ poll.question }}</a></li>
    {% endfor %}
    </ul>
    {% else %}
    <p>No polls are available.</p>
    {% endif %}

    如果现在运行服务器,就可以看到http://localhost:8000/polls/这个页面了,显示的内容就是所有的投票的问题。

    两个捷径

    第一个是django提供的模版渲染捷径:render_to_response()。这个方法有两个参数:模版页面和词典,因此上个例子可以改为:return render_to_response("polls/index.html",{'latest_poll_list':latest_poll_list})

    在index页面的每一项会超连接到detail页面,首先会根据投票的id从数据库中找到相应的对象,当然,如果找不到就会抛出ObjectDoesNotExist异常,因此,detail视图应该是这样的:

    def detail(request, poll_id):
        try:
            p=Poll.objects.get(pk=poll_id)
        except Poll.DoesNotExist:
            raise Http404
        return render_to_response('polls/detail.html',{'poll':p})

    这就要引出我们说的第二个捷径了:get_object_or_404。它将一个model作为第一个参数,把get object时用到的一系列关键词作为第二个参数。因此上面的try except可以合并为一句:p = get_object_or_404(Poll, pk=poll_id)

    要多说的是,如果真的出现了404错误,django就会调用URLConf中的handler404这个视图,你需要定义它,但如果没有,就默认调用django.views.defaults.page_not_found()这个视图。此外,还要自己实现一个404.html,因为本来没有这个页面,再加上DEBUG被设为False的话,就会产生HTTP500,500的意思是server error。当然,你也可以像404错误一样设定handler500.

    改进URL映射

    patterns的第一个参数的意思是下面所有view的共同前缀,因为关于投票的四个视图都以polls.views开头,因此可以改为:

    urlpatterns = patterns(’polls.views’,
    url(r’^polls/$’, ’index’),
    url(r’^polls/(?P<poll_id>\d+)/$’, ’detail’),
    url(r’^polls/(?P<poll_id>\d+)/results/$’, ’results’),
    url(r’^polls/(?P<poll_id>\d+)/vote/$’, ’vote’),
    )

    但是admin和它们又没有共同前缀,因此可以写成这样:

    urlpatterns = patterns(’polls.views’,
    url(r’^polls/$’, ’index’),
    url(r’^polls/(?P<poll_id>\d+)/$’, ’detail’),
    url(r’^polls/(?P<poll_id>\d+)/results/$’, ’results’),
    url(r’^polls/(?P<poll_id>\d+)/vote/$’, ’vote’),
    )
    urlpatterns += patterns(’’,
    url(r’^admin/’, include(admin.site.urls)),
    )

    前面说过,每一个application都是可插拔的,它独立于整个工程存在,但是这里的urls.py是在project文件夹下面的,也就是说,关于投票这个应用的url信息出现了工程的文件夹下。所以,为了实现松耦合,因此我们需要做一些改动:将mysite文件夹下的urls.py拷贝到polls文件夹下面,并将mysite/urls.py改为:

    from django.conf.urls import patterns, include, url
    from django.contrib import admin
    
    admin.autodiscover()
    
    urlpatterns = patterns(’’,
    url(r’^polls/’, include(’polls.urls’)),
    url(r’^admin/’, include(admin.site.urls)),
    )

    include语句调用了另一个URLConf,这时,django匹配过程变为首先找到polls/,如果匹配,将剩下的部分传递给引用的URLConf中。因此,polls/url.py应为:

    from django.conf.urls import patterns, url
    
    urlpatterns = patterns(’polls.views’,
    url(r’^$’, ’index’),
    url(r’^(?P<poll_id>\d+)/$’, ’detail’),
    url(r’^(?P<poll_id>\d+)/results/$’, ’results’),
    url(r’^(?P<poll_id>\d+)/vote/$’, ’vote’),
    )

    之前有一个模版文件index.html里用到了引用<a href="/polls/{{ poll.id }}/">{{ poll.question }}</a> ,现在应改为:<a href="{% url polls.views.detail poll.id %}">{{poll.question}}</a>。django的url语法是这样的,{%url path-to-view args1 args2 %}.

    更改detail模版

    我们之前的polls/detail.html模版仅仅是显示出了问卷的问题,让我们把这个模版改一下,里面加上一个form表单:

    <!-- 显示出这个投票的题目 -->
    <h1>{{poll.question}}</h1>
    
    {% if error_message %}<p><strong>{{ error_message }}</strong></p>{% endif %}
    
    <!-- 表单提交到vote视图 -->
    <form action=" {% url polls.views.vote poll_id=poll.id %}" method="post">
    <!-- 为了防止跨域攻击,使用下面的标签 -->
    {% csrf_token %}
    {% for choice in poll.choice_set.all %}
        <!-- value值为选项的choice_id,因此,当表单提交的时候也就提交了choice_id,即"choice=choice_id" -->
        <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标签,因此就不能用context了,而要用RequestContext:

    return render_to_response(’polls/detail.html’, {’poll’: p},context_instance=RequestContext
    (request))

    表单提交后到了vote视图:

    def vote(request,poll_id):
        #找到传进来的poll
        p=get_object_or_404(Poll,pk=poll_id)
        try:
        #之前表单传入的参数是choice,值是choice_id,这里使用request.POST方法将它的值提取出来
            selected_choice=p.choice_set.get(pk=request.POST['choice'])
        #提取错误时,显示错误信息
        except(KeyError,Choice.DoesNotExist):
            return render_to_response('polls/detail.html',{
            'poll':p,
            'error_message':"You didn't select a choice.",
            },context_instance=RequestContext(request))
        #没有错误就给选中的那一项投一票,然后保存,将来写入到数据库中
        else:
            selected_choice.votes+=1
            selected_choice.save()
          #页面跳转到results视图
            return HttpResponseRedirect(reverse('polls.views.results',args=(p.id,)))

    reverse就是指定跳转的视图,定义是reverse(viewname, urlconf=None, args=None, kwargs=None, current_app=None)。results视图用来显示结果:

    def results(request,poll_id):
        p=get_objects_or_404(Poll,pk=poll_id)
        return render_to_response('polls/results.html',{'poll':p})

    results.html的内容:

    <h1>{{ poll.question }}</h1>
    
    <ul>
    {% for choice in poll.choice_set.all %}
        <li>{{ choice.choice_text }} -- {{ choice.votes}} vote{{ choice.votes|pluralize }}</li>
    {% endfor %}
    </ul>
    
    <a href="{% url polls.views.vote poll_id=poll.id %}">Vote again?</a>

    最后不说了,上图:

  • 相关阅读:
    C#捕获摄像头进行拍照和录像资料总结
    MySQL:日期函数、时间函数总结(MySQL 5.X)
    apache 虚拟主机详细配置:http.conf配置详解
    [转载文章]6个重要的.NET概念:栈,堆,值类型,引用类型,装箱,拆箱
    GetType和typeof的区别
    [转]C#读写xml文件
    DateTime 格式化
    jquery sortable 插件参数详解
    [转]一个人脸检测器
    why SOA
  • 原文地址:https://www.cnblogs.com/cubika/p/2772254.html
Copyright © 2011-2022 走看看