Django07模型,模板和视图

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

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

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

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

2. 展示Rango主页上的目录

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

2.1 导入需要的模型

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

2.2 修改index视图

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

def index(request):
    category_list = Category.objects.order_by('-likes')[:5]
    context_dict = {'categories': category_list}
    return render(request, 'rango/index.html', context_dict)

这里我们做了第二步和第三步.首先,我们访问Category模型得到5个最多的目录.这里用order_by()方法对喜欢的数量进行降序排序 - 注意带着-.最后我们取前5个目录保存到category_list

当访问数据库结束,我们把这个列表(category_list)传给了字典context_dict.这个字典同时会作为render()的参数返回给模板.

2.3 修改index模板

修改完视图后,最后剩下的就是更改rango/index.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模板语言里的if和for控制语句.在页面的<body>里我们检查categories是否为空(例如,{% if categories %}).
如果不为空,会建立一个无序HTML列表(在ul标签里)
.for循环({% for category in categories %})会依次在li标签里打印出每个目录的名字({{ category.name }}).
如果不存在categories,将会输出There are no categories present..
作为模板语言,所有的命令都包含在{%和%}标签里,所有的变量都在{{和}}里.
如果访问 http://127.0.0.1:8000/rango/ ,如下图所示.

效果图

3. 创建详细页面

1. URL设计与映射

通过Rango的详细描述,我们需要列出目录的每个页面.现在我们需要克服许多困难.我们需要创建一个新的视图作为参数.我们同事需要创建URL模式和URL字符串来对应每个目录的名字.
让我们着手解决URL问题.有一种方法是为我们的目录在URL中设立唯一的ID,我们可以创建像/rango/category/1/或者/rango/category/2/,这里的数字1和2就是它们的ID.但是这样做对我们来说不太好理解.尽管我们知道数字关联着目录,但我们怎么知道1和2代表哪个目录呢?用户不试一下就不会知道.

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

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.像下面一样修改模型.

from django.template.defaultfilters import slugify
class Category(models.Model):
        name = models.CharField(max_length=128, unique=True)
        views = models.IntegerField(default=0)
        likes = models.IntegerField(default=0)
        slug = models.SlugField(unique=True)
        def save(self, *args, **kwargs):
                self.slug = slugify(self.name)
                super(Category, self).save(*args, **kwargs)
        def __str__(self):
                return self.name

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

$ python3 manage.py makemigrations rango
$ python3 manage.py migrate

因为我们slug没有设置默认值,而且模型中已经加入进数据,所以migrate命令将会给你两个选项.选择提供默认值选项并输入默认值''.它会马上进行修改.现在重新运行population脚本.因为每个目录都会执行save方法,所以重写的save方法将会被执行修改slug字段.运行Django服务,你讲会在管理界面看到修改的数据.
注意:这里原书会有错误,原因见http://stackoverflow.com/questions/27788456/integrityerror-column-slug-is-not-unique ,修改见 https://github.com/leifos/tango_with_django/issues/19
j
解决方法:

  1. 删除db.sqlite3
  2. python manage.py makemigrations
    选择第一个,填一个默认值
  3. python3 manage.py migrate
示意图

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

from django.contrib import admin
from rango.models import Category, Page

# Add in this class to customized the Admin Interface
class CategoryAdmin(admin.ModelAdmin):
    prepopulated_fields = {'slug':('name',)}

# Update the registeration to include this customised interface
admin.site.register(Category, CategoryAdmin)
admin.site.register(Page)
效果图

在管理界面尝试增加新的目录.看到了吧!现在我们可以加入slug字段用作我们的url.

目录页面流程

1. 目录视图

在rango/views.py中,我们需要导入Page模型.如下.
from rango.models import Page
下面我们将会加入我们的category()视图:

def category(request, category_name_slug):
    context_dict = {}

    try:
        category = Category.objects.get(slug=category_name_slug)
        context_dict['category_name'] = category.name
        pages = Page.objects.filter(category=category)
        context_dict['pages'] = pages
        context_dict['category'] = category
    except Category.DoesNotExist:
        pass
    return render(request, 'rango/category.html', context_dict)

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

2. 目录模板

现在为我们的新视图创建模板.在<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.

3. 参数化的URL映射

现在让我们来看看如何把category_name_url参数值传递给category().我们需要修改rango的urls.py文件和urlpatterns元组.

urlpatterns = [
    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参数.

4. 修改index模板

<!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>
效果图

练习

练习

代码:

views
index.html
效果图
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,294评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,493评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,790评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,595评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,718评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,906评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,053评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,797评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,250评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,570评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,711评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,388评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,018评论 3 316
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,796评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,023评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,461评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,595评论 2 350

推荐阅读更多精彩内容