注册 登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

being23

写给未来的自己

 
 
 

日志

 
 
关于我

真正的坚定,就是找到力量去做自己喜欢的事情,并为之努力,这样才会觉得生活是幸福的。

网易考拉推荐

模型,模板和视图  

2013-12-14 16:00:30|  分类: work@oppo |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |

原文见6. Models, Templates and Views


6. 模型,模板和视图

目前我们已经建好了模型并填充了数据,现在可以将组装零件了。我们会了解如何将数据放到视图中,以及如何在模板中展示数据。

6.1. 基本流程:数据驱动页面

在Django中创建数据驱动的页面主要有5个步骤。

  1. 首先,在应用的views.py文件中导入使用的模型
  2. 在使用的视图中,查询模型来获得需要展示的数据
  3. 将模型的结果传递到模板的上下文中
  4. 建立模板以想要的方式展示数据
  5. 如果你目前还没有做这些,映射一个URL到视图中

这几个步骤概括了Django的框架是如何分离模型,视图和模板的。

6.2. 在Rango主页展示分类

主页的需求之一就是展示访问最多的5个分类。

6.2.1. 导入需要的模型

这个需求需要通过上面5个步骤来完成。首先,打开rango/views.py,从Rango的models.py文件导入模型Category

# Import the Category model
from rango.models import Category

6.2.2. 修改INDEX视图

在开始之前,我们需要修改我们的index()函数。回想一下,index()函数应该是负责主页视图。修改函数如下。

def index(request):
    # Obtain the context from the HTTP request.
    context = RequestContext(request)

    # Query the database for a list of ALL categories currently stored.
    # Order the categories by no. likes in descending order.
    # Retrieve the top 5 only - or all if less than 5.
    # Place the list in our context_dict dictionary which will be passed to the template engine.
    category_list = Category.objects.order_by('-likes')[:5]
    context_dict = {'categories': category_list}

    # Render the response and send it back!
    return render_to_response('rango/index.html', context_dict, context)

这里在一次执行了步骤2和步骤3。首先,我们查询Category来获得访问最多的5个分类。这里我们使用方法order_by()以降序排列分类的受欢迎程度——即符号-表示降序。然后限制列表中开始的5个Category对象。

查询结束后,我们将列表的索引(存在变量category_list中)传递给一个字典,context_dict。这个字典在render_to_response()调用中作为上下文的一部分传递给模板引擎。

6.2.3. 修改主页模板

更新了视图后,我们还要做的就是修改位于工程template目录的模板文件rango/index.html。修改HTML代码如下。

<!DOCTYPE html>
<html>
    <head>
        <title>Rango</title>
    </head>

    <body>
        <h1>Rango says...hello world!</h1>

        {% if categories %}
            <ul>
                {% for category in categories %}
                <li>{{ category.name }}</li>
                {% endfor %}
            </ul>
        {% else %}
            <strong>There are no categories present.</strong>
        {% endif %}

        <a href="/rango/about/">About</a>
    </body>
</html>

这里,我们使用Django的模板语言iffor控制语句来展示数据。在页面的<body>中,测试categories——含有我们列表的上下文变量——实际上包含任何分类(例如{% if categories %})。

如果有,我们进而构建出一个无需的HTML列表(在标签<ul>中)。循环{% for category in categories %}遍历结果列表,在一对<li>标签中作为列表元素输出每个分类的名字({{ category.name }})。

如果没有分类存在,会输出一条消息。

就像在Django模板语言中看到的,所有的命令都是通过{%%}括起来,而变量是通过{{}}括起来。

如果你现在通过地址http://127.0.0.1:8000/rango ,你就会在标题的下面看到三个分类,如图[1]


rango-categories-simple

6.3. 创建一个Details页面

根据Rango需求,还需要展示一个与分类相关的页面列表。这里有些挑战。需要新建一个新的可参数化的视图。还需要新建URL规则和URL字符串来表示分类名。

6.3.1. URL设计和映射

我们首先考虑URL的问题。一种方式就是在URL中给每个分类一个唯一的ID。例如,我们可以这样创建分类/rango/category/1/或者/rango/category/2,这里数值分别对应ID为1和2的分类。然而,这样的分类规则不易被人们理解。虽然我们可以推断出数值是对应分类的,但是用户怎么会知道那个分类对应ID1或者2?如此一来,用户只能去尝试。

不过,我们可以将分类名作为URL的一部分。/rango/category/Python/应该会给我们一个关于Python分类的页面列表。这是一个简单的,可读的并且有意义的URL。如果我们采用这种方法,那就必须处理分类名由多个单词组成的情形,例如“Other Frameworks”,等。

注意:

设计简洁的URL是web设计中一个非常重要的方面。细节见Wikipedia’s article on Clean URLs

6.3.2. 分类页面流程

选好了URLs设计规范,可以开始后续工作了。我们要采取下面的步骤。

  1. 导入页面模型到rango/views.py
  2. rango/views.py中创建一个新视图——名为category——这个视图会接收一个用来存放编码后的分类名的参数category_name_url
  3. 创建一个模板,templates/rango/category.html
  4. 更新Rango的urlpatterns,将category视图映射到rango/urls.py的URL模式

我们还要更新index()视图和index.html模板来提供到分类视图的链接。

6.3.3. 分类视图

rango/views.py中,我们首先需要导入Page模型。这意味着,我们必须在文件的开头加入下面的导入语句。

from rango.models import Page

接下来,添加新视图,category()

def category(request, category_name_url):
    # Request our context from the request passed to us.
    context = RequestContext(request)

    # Change underscores in the category name to spaces.
    # URLs don't handle spaces well, so we encode them as underscores.
    # We can then simply replace the underscores with spaces again to get the name.
    category_name = category_name_url.replace('_', ' ')

    # Create a context dictionary which we can pass to the template rendering engine.
    # We start by containing the name of the category passed by the user.
    context_dict = {'category_name': category_name}

    try:
        # Can we find a category with the given name?
        # If we can't, the .get() method raises a DoesNotExist exception.
        # So the .get() method returns one model instance or raises an exception.
        category = Category.objects.get(name=category_name)

        # Retrieve all of the associated pages.
        # Note that filter returns >= 1 model instance.
        pages = Page.objects.filter(category=category)

        # Adds our results list to the template context under name pages.
        context_dict['pages'] = pages
        # We also add the category object from the database to the context dictionary.
        # We'll use this in the template to verify that the category exists.
        context_dict['category'] = category
    except Category.DoesNotExist:
        # We get here if we didn't find the specified category.
        # Don't do anything - the template displays the "no category" message for us.
        pass

    # Go render the response and return it to the client.
    return render_to_response('rango/category.html', context_dict, context)

新视图的步骤跟index()视图一致。我们首先从request中获得context,然后构建一个上下文字典,渲染模板,发送结果。在这里,区别就是上下文字典的构造有点复杂。要构造上下文字典,我们需要根据传递给视图函数category()的参数category_name_url来确定哪个分类可见。一旦确定了分类,从数据库中取得相关信息,并将结果添加到上下文字典context_dict中。后面会给出如何从URL中获得category_name_url的值。

在视图函数category()中,我们假设分类名category_name_url中的空格被转成了下划线。所以我们把所有的下划线替换成了空格。不幸的是,这是一种相当原始的处理URL中分类名编解码的方式。作为后续的联系,你需要完成两个函数来完成分类名的编解码。

6.3.4. 分类模板

现在给新视图创建模板。在目录<workspace>/tango_with_django_project/templates/rango/中,创建category.html。在新建的文件中,添加下面的代码。

<!DOCTYPE html>
<html>
    <head>
        <title>Rango</title>
    </head>

    <body>
        <h1>{{ category_name }}</h1>
        {% if category %}
            {% if pages %}
            <ul>
                {% for page in pages %}
                <li><a href="{{ page.url }}">{{ page.title }}</a></li>
                {% endfor %}
            </ul>
            {% else %}
                <strong>No pages currently in category.</strong>
            {% endif %}
        {% else %}
            The specified category {{ category_name }} does not exist!
        {% endif %}
    </body>
</html>

上面的HTML实例代码中,再次说明了我们是如何获得通过上下文传递给模板的数据的。我们使用了变量category_namecategorypages对象。如果category在模板上下文中没有定义,即数据库中没有这个分类,会出现一条友好的提示说明这种情况。如果情况相反,我们继续处理pages。如果pages没有定义或者没有任何元素,我们会给出一条消息说明没有页面。否则,会在HTML的列表中展示某个分类的页面。对于列表中的每个页面,会给出titleurl属性。

6.3.5. 参数化URL的映射

现在,看下我们是怎么把category_name_url传递给函数category()的。要完成这个,我们需要修改Rango的urls.py,更新urlpatterns元组如下。

urlpatterns = patterns('',
    url(r'^$', views.index, name='index'),
    url(r'^about/$', views.about, name='about'),
    url(r'^category/(?P<category_name_url>\w+)/$', views.category, name='category'),) #New!

正如你看到的,我们添加了一个相当复杂的元素,它会在正则表达式r'^(?P<category_name_url>\w+)/$'匹配的时候调用函数view.category()。我们的正则表达式会在删除URL的斜杠之前去匹配任意的字符序列(例如 a-z,A-Z,_,或者0-9)。匹配的值会作为强制参数request后面的唯一参数category_name_url传递给views.category()。本质上说,硬编码到正则表达式中的变量名就是Django在你的视图函数定义中寻找的参数名。

6.3.6. 修改INDEX视图和模板

我们写好了新的视图,一切就绪——不过,还需要完成一件事。主页视图需要更新以便用户可以看到列出的分类页面。更新rango/views.py视图的index()的如下。

def index(request):
    # Obtain the context from the HTTP request.
    context = RequestContext(request)

    # Query for categories - add the list to our context dictionary.
    category_list = Category.objects.order_by('-likes')[:5]
    context_dict = {'categories': category_list}

    # The following two lines are new.
    # We loop through each category returned, and create a URL attribute.
    # This attribute stores an encoded URL (e.g. spaces replaced with underscores).
    for category in category_list:
        category.url = category.name.replace(' ', '_')

    # Render the response and return to the client.
    return render_to_response('rango/index.html', context_dict, context)

正如行间的注释所指出的,取出数据库返回的每个分类,遍历分类表对每个分类进行友好的URL编码。这种友好的URL会作为属性保存到Category对象的内部(例如,我们利用python的动态类型随时添加这个属性)。

然后将分类列表category_list传递到模板的上下文,这样就可以渲染了。当每个分类的url属性变得可用,可以更新模板index.html如下。

<!DOCTYPE html>
<html>
    <head>
        <title>Rango</title>
    </head>

    <body>
        <h1>Rango says..hello world!</h1>

        {% if categories %}
            <ul>
                {% for category in categories %}
                <!-- Following line changed to add an HTML hyperlink -->
                <li><a href="/rango/category/{{ category.url }}">{{ category.name }}</a></li>
                {% endfor %}
            </ul>
       {% else %}
            <strong>There are no categories present.</strong>
       {% endif %}

    </body>

这里我们更新了每个列表元素(<li>),在其中添加了一个HTML超链接(<a>)。这个超链接有一个href属性,我们使用这个属性来指定由{{ category.url }}定义的目标URL。

6.3.7. DEMO

现在访问Rango的主页。你就会看到主页列出了所有的分类。分类应该是可以点击的链接。在Python上点击会带你到Python细节分类的视图,如图2所示。如果你看到类似Official Python Tutorial的链接列表,那么你已经成功的建立了新视图。试着访问并不存在的分类,例如/rango/category/computers。你应该会看到该分类没有页面的提示消息。

rango-links

 

20131214@南山 桃苑公寓

  评论这张
 
阅读(491)| 评论(0)
推荐 转载

历史上的今天

在LOFTER的更多文章

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2017