基于How To Tango With Django 1.9的重新实践(6)——Models, Templates and Views

现在我们已经建立了模型并且导入了一些数据,现在我们要把这些连一起.我们将会弄清楚如何在视图中访问数据以及如何通过模板展示数据.

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

在Django中创建数据驱动页面必须执行以下5步.

  1. 首先,在你应用的views.py文件中导入你要添加的模型.
  2. 在视图里访问模型,导入你需要的数据.
  3. 把模型的数据传递给模板.
  4. 设置模板给用户呈现数据.
  5. 如果还没有映射URL,映射一下吧.

上面的步骤告诉你如何使用Django里的模型,视图和模板.

6.2 展示Rango主页上的目录

我们需要在rango的主页显示5个最多的目录.

6.2.1 导入需要的模型

为了达到目的,我们需要完成上面的步骤.首先,打开rango/view.py并导入rango的models.py文件的Category模块.

from rango.models import Category

6.2.2 修改index视图

有了第一步,我们需要修改index()函数.让我们回想一下,这个index()函数负责管理主页的视图.修改如下.

def index(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
    # that 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(request, 'rango/index.html', context_dict)

这里写图片描述

6.3 创建详细页面

通过Rango的详细描述,我们需要列出目录的每个页面.现在我们需要克服许多困难.我们需要创建一个新的视图作为参数.我们同事需要创建URL模式和URL字符串来对应每个目录的名字.

6.3.1 URL设计与映射

让我们着手解决URL问题.有一种方法是为我们的目录在URL中设立唯一的ID,我们可以创建像/rango/category/1/或者/rango/category/2/,这里的数字1和2就是它们的ID.但是这样做对我们来说不太好理解.尽管我们知道数字关联着目录,但我们怎么知道1和2代表哪个目录呢?用户不试一下就不会知道.

另一种方法就是用目录名作为URL./rango/category/Python/将会返回给我们关于Python的目录.这是一个简单的,可读的URL.

6.3.2 为Category表增加Slug字段

为了建立简洁的url我们需要在Category模型里增加slug字段.首先我们需要从django导入slugify函数,这个函数的作用是把空格用连字符代替,例如”how do i create a slug in django”将会转换成”how-do-i-create-a-slug-in-djang”.

接下来我们将会重写Category模型的save方法,我们将会调用slugify方法并更新slug字段.注意任何时候目录名称更改都会更改slug.像下面一样修改模型.

这里写图片描述

现在需要运行下面的命令更新模型和数据库.

$ python manage.py makemigrations rango

$ python manage.py migrate

此处如果按照原书操作的话,会产生错误
解决方案如下:
这里写图片描述
GitHub上的解决方案
我用的是MySQL,按照此方法同样可以解决

在管理界面你或许希望在填写目录名的时候自动填充slug字段.按照下面的方法.

6.3.3 目录页面流程

我们设计完URL以后,看看我们接下来的步骤.

  • 在rango/views.py导入Page模型.
  • 在rango/views.py中创建category视图 - 这个category视图将会增加一个
  • category_name_url参数来存储目录名.
  • 我们需要一些函数来帮助我们对category_name_url进行编码.
  • 创建一个新模板,templates/rango/category.html.
  • 修改rango/urls.py里的urlpatterns映射新的category视图.
  • 同样我们需要修改index()视图和index.html模板来提供到目录页面的链接.

6.3.4 目录视图

在rango/views.py中,我们需要导入Page模型.如下.

from rango.models import Page

下面我们将会加入我们的category()视图:

def category(request, category_name_slug):

    # Create a context dictionary which we can pass to the template rendering engine.
    context_dict = {}

    try:
        # Can we find a category name slug 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(slug=category_name_slug)
        context_dict['category_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(request, 'rango/category.html', context_dict)

和index()视图一样我们的新视图也要执行同样的基本步骤.我们需要定义一个字典,然后尝试从模型中导出数据,并把数据添加到字典里.我们通过参数category_name_slug的值来决定是哪个目录.如果在Category模型中找到目录,我们就会把context_dict字典传递给相关页面.

6.3.5 目录模板

现在为我们的新视图创建模板.在<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_name变量和category和pages对象.如果category在模板上下文并没有定义,或者在数据库并没有发现这个目录,那么就会提示一个友好的错误信息.相反的话如果存在,我们将会检查pages.如果pages没有被定义或者不存在元素,我们同样也会呈现友好的错误提示.否则的话目录里包含的页面就会写入HTML李彪.对于在pages列表的每个页面我们都会展示它的title和url.

6.3.6 参数化的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_slug>[\w\-]+)/$', views.category, name='category'),)  # New!

你能看到当正则表达式r'^(?P<category_name_slug>\w+)/$匹配时会调用view.category()函数.我们的正则表达式会匹配URL斜杠前所有的字母数字(例如 a-z, A-Z, 或者 0-9)和连字符(-).然后把这个值作为category_name_slug参数传递给views.category(),这个参数必须在强制的request参数之后.

url(r'^category/(?P<category_name_slug>[\w\-]+)/$', views.category, name='category') 我们可以从这里找到在category/和后面的/之间的字符串,并把它作为参数category_name_slug传递给views.category()参数.例如,URLcategory/python-books/将会返回的category_name_slug参数是python-books. 需要知道的十,所有的视图函数必须带至少一个参数.这个参数是request - 它会提供HTTP请求用户的相关信息。当参数化URL时,可以给视图添加已经命名德尔参数.使用上面的例子,我们的category视图是这样的. def category(request, category_name_slug): 附加参数的位置不重要,重要的是在URL模式中定义的参数名称.注意如何为我们的视图在URL模式匹配中定义category_name_slug参数.

6.3.7 修改index模板

虽然我们的视图已经建立了,但是还要做的工作许多.我们的index模板需要修改并提供给用户category列表.我们可以通过slug为index.htnl模板中添加目录页面.

<!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.slug }}">{{ category.name }}</a></li>
                {% endfor %}
            </ul>
       {% else %}
            <strong>There are no categories present.</strong>
       {% endif %}

    </body>
</html>

这里为每个列表元素(<li>)增加一个HTML超链接(<a>).超链接有一个href属性,我们用{{ category.slug}}来定义目标URL.

这里写图片描述

这里写图片描述

这里写图片描述

这里写图片描述

Exercises

Reinforce what you’ve learnt in this chapter by trying out the following exercises.

  • Update the population script to add some value to the views count for each page.

这里写图片描述

运行populate_rango.py的时候,不知道为啥又报错,于是又把数据库里表单删了一次就好了…


  • Modify the index page to also include the top 5 most viewed pages.

  • Include a heading for the “Most Liked Categories” and “Most Viewed Pages”.

这里写图片描述

这里写图片描述

这里写图片描述


  • Include a link back to the index page from the category page.

这里写图片描述

这里写图片描述


  • Undertake part three of official Django tutorial if you have not done so already to reinforce what you’ve learnt here.
  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值