Wednesday, December 10, 2008

创建一个社交书签分享应用程序




创建一个社交书签分享应用程序

介绍


前面的章节中我们我们创建了一个空的应用程序,并且学习了如何设置了数据库和启动开发服务器。接下来我们将开始创建我们的书签分析应用程序,并在这个过程中学习视图模型模板技术。

我们在这章中将介绍Django中的主要的组件。你将会学到如何在视图层创建动态页面,如何通过模型层将数据存储到数据库已经如何管理这些数据,并且还会学到如何通过模板技术简单的创建页面。在学习这些技术的过程中你将对Django这些主要的组件之间如何交互有一个更深的理解。后面的章节中我们会深入介绍这些组件,并且给我们的应用程序增加更多的功能。

本章讨论以下内容:

  • URLs和视图:创建主页
  • 模型:创建初始的数据结构
  • 模板:为主要创建一个模板
  • 结合以上内容创建一个用户页面



Django中的术语




Django 是一个MVC框架,但是在Django中控制器被称为“视图”,视图被称为“模板”。Django中的视图实际上是一个负责接收和维护数据的组件,而模板被用来向用户展示数据。因此Django也被称为MTV框架(MTV代表,模型 模板 视图)。虽然术语上不同,但是这并不改变Django是一个MVC框架,也不影响应用程序按照这一模式的开发过程。但是如果你以前使用过其他的MVC框架,最好还是把这些数据记下来以免造成混淆。




URL和视图:创建主页



当我们看到的主要程序的主页的时想到的第一件事是如何修改页面的内容。要创建我们自己的主页,第一件事通过URLs的方式在应用程序中增加一个入口,告诉Django在访问这个URLs的时候调用一个特定的Python函数。我们将写出这个Python函数让他显示我们自定义的主页。

创建主页

Django术语总的视图是一个负责响应页面请求并返回一个相应页面的Python函数。开始创建我们自己的主页之前,我们首先需要在我们的Django项目(project)中创建一个Django应用程序(appliaction)。你可以把应用程序想象成视图和数据模型的存储器。要创建一个应用程序请输入下面的命令:

$ python manage.py startapp bookmarks




创建应用程序的命令和创建项目的命令非常类似,用startapp 作为manage.py的第一个参数,第二个参数是应用程序的名称。

运行这个命令之后Django将在项目文件夹下创建一个新的文件夹名我bookmarks,这个文件夹下包含以下文件:

  • __init__.py:这个文件告诉Python,bookmarks是一个包
  • views.py:这个文件中将包含我们的视图逻辑
  • models.py:这个文件中将包含我们的数据模型

现在开始创建我们的主页的视图,打开bookmarks/views.py文件,输入以下内容:

from django.http import HttpResponse
def main_page(request):
output='''<html>
<head><title>%s</title></head>
<body>
<h1>%s</h1><p>%s</p>
</body>
</html> ''' %('Django Bookmarks',
'Welcome to Django Bookmarks',
'Where you can store and share bookmarks!')
return HttpResponse(output)


代码非常简短而且直白,让我们一行行的看看他们是什么意思:

  • 首先我们需要导入从django.http导入HttpResponse类,我们需要这个对象来完成页面输出的功能。
  • 我们定义了一个函数名我main_page,并且他只有一个参数名我request;这个参数中包含了用和输入和其他信息。比如:request.GET, request.POST和request.COOKIES,这些属性是Python中的字典对象,他们分别代表了request,response和cookie。
  • 接着我们创建了Html代码并把它们封装到HttpResponse对象中返回给客户端。

创建主页的URL

你应该还记得前面的章节中我们介绍如何创建一个项目时,曾经创建了一个urls.py文件。这个文件中包含了应用程序中所有的URL,并将每个URL映射到一个视图Python函数上。让我们来看看这个文件的内容并试着加入我们自己的内容:

from django.conf.urls.defaults import *

# Uncomment the next two lines to enable the admin:
# from django.contrib import admin
# admin.autodiscover()

urlpatterns = patterns('',
# Example:
# (r'^django_bookmarks/', include('django_bookmarks.foo.urls')),

# Uncomment the admin/doc line below and add 'django.contrib.admindocs'
# to INSTALLED_APPS to enable admin documentation:
# (r'^admin/doc/', include('django.contrib.admindocs.urls')),

# Uncomment the next line to enable the admin:
# (r'^admin/(.*)', admin.site.root),
)
正如你看到的那样,这个文件包含了从URL到Python视图函数映射的一个表,这个名为urlpatterns的表实际上是一个Python的元组,已经包含了一些被注释掉的例子代码,他们描述了URL和Django视图函数的映射关系。

这些URL语法你看起来应该很熟悉,因为它们实际上就是正则表达式,通过这种方式Django为你定义URL提供了最大的灵活性。我们将逐步学习如何使用这种URL语法,现在让我们把这些注释移调,并给我们的主页加一个URL入口:

from django.conf.urls.defaults import *
from bookmarks.views import *
urlpatterns = patterns('',
(r'^$',main_page),
)

现在,让我们再来看看这些代码的含义:

  • 首先将django.conf.urls.defaults下面的所有内容都导入进来,这个模块下包含了定义URL必须的函数。
  • 然后导入bookmarks.views下所有的内容,这里包含了我们的视图函数。
  • patterns用于定义URL表,现在我只有一个URL映射关系--从r'^$'到main_page。

在我们开始介绍视图的概念之前,最后一个需要解释的是正则表达式,如果你以前没有使用过正则表达式,那么这种语法会让你感觉很奇怪。在我们的代码中,这个正则表达式中包含一个原生的字符串,字符串中有两个字符^和$。r'' 是Python的语法结构,它用于定义一个原生字符串,如果Python解析器遇到这样的原生字符串的时候不会解析器中的反斜杠(/)和其他转码字符。这对于正则表达式是非常有用的,因为在这些表达式中经常包含反斜杠或者转码字符。

在正则表达式中^代表字符串的开始,$代表字符串的结束。所以$通常表示一个字符串不包含任何内容,是一个空字符串。这很符合我们主页URL的要求,因为主页通常是站点的跟节点,不包含任何内容。

Python针对re模块的有关文档相信介绍了正则表达式,如果你想深入了解正则表达式我建议你先阅读这些文档:

http://docs.python.org/lib/module-re.html

下面列表是对正则表达式语法的一个简单的索引:

符号/表达式匹配的字符串
.(点号)任意字符串
^(加字符号)字符串的开始
$字符串的结束
*重复0到多次
+重复1到多次
0或者1个重复
|A|B 表示A或者B
[a-z]任意的小写字符
\w任意字母或者下划线_
\d任意的数字

了,现在一切都准备好了,让我们看看最终的效果是什么样,启动服务器并打开浏览器输入:http://127.0.0.1:8000 你将会看到下面的页面。

恭喜你,你已经成功的场景了第一个Django视图。

在我们开始下一届内容之前,最好来了解一下这一切的背后是怎么回事:

  • 当用户向http://127.0.0.1:8000/发出请求时,Django会从urls.py文件中查找URL匹配的一个函数是什么,匹配的过程使用了正则表达式。
  • 当找到匹配的URL那么Django就调用它对于的那个Python函数,这个函数接收来自用户浏览器的请求,请求参数包含在request对象中,然后将返回页面封住如HttpResponse对象输出到浏览器。
  • 如果Django找不到URL,他会抛出一个404“页面错误”的异常。如果你输入下面的链接http://127.0.0.1:8000/does_not_exist/ 你就会看到上面提到的异常。值得一提的是Django提供了详细的调试信息,这在开发中是非常有帮助的,当然在你发布产品的时候你可以关闭调试选项来取消输出调试信息。
这种从URL到视图的映射方式为开发人员提供了极大的灵活性,它不像PHP中那样将URL限制为文件名,也不像mod_python那样将URL自动映射到一个Python函数上。在URL和函数之间如何映射这件事上开发人员有完全的控制权。尤其是在大型项目的开发中这非常有用,因为这些项目中URL和函数名经常会变更。

模型:创建一个初始数据模型

几乎每一个web2.0的应用程序都需要一个数据库来存储和管理数据。如今数据库引擎已经成为了web开发的基础。web应用程序为用户提供一个界面来输入和管理他们的数据,在程序后台通过数据库来存储这些数据。


在Django中你可以将视图当作是搜集和展示数据的组件,而模型用于存储和管理这些数据


在前面的章节中我们已经介绍了如何在我们的程序中配置数据库。本节我们将讲述如何将我们的用户帐号数据和标签信息存储到数据库中。如果你习惯于在数据库中直接使用SQL语句,你会发现Django中的数据访问方式稍有不同。简单的讲,Django将对数据库表的访问抽象为通过Python类来访问。开发人员将通过Python形式的API来存储访问和管理数据库中的数据。因此具备SQL知识有一定的帮助,但不是必须的。

我们最好是通过一个例子来讲解这部分内容,在我们的标签共享应用程序中,我们要在数据库中存储3中类型的数据:

  • Users (ID, username, password, email)
  • Links (ID, URL)
  • Bookmarks (ID, title, user_id, link_id)

每个用户的信息都要单独存储在Users表中。这个表中存储了用户的名词、密码和电子邮件。同理,每一个链接都要存储在Links表中,目前我们只存储链接的URL地址。

对于Bookmarks表,你可以把它当作是Users和Links表之间的连接表。当用户增加一个标签,那么首先要检查Links表中是否存在相同的URL,如果不存在就增加一个,同时User和Link之间的连接关系被保存在Bookmarks表中,并且还要保存用户输入的代表这个URL的标签名词。

要把以上设计转化为时间的Python代码,我们需要编辑bookmarks文件夹下的models.py文件,并在其中定义每一个类型。models.py文件用于描述每一个数据模型,在开始创建的时候它只有一条import语句。

链接表的数据模型

让我们从创建Links表的数据模型开始,因为它是最简单的一个。打开bookmarks/models.py文件,输入如下内容:

class Link(models.Model):
url=models.URLField(unique=True)

我们来看看这些代码是什么意思:

  • 首先导入models模块,它包含了定义模型必须的类。
  • 然后定义一个类Link,它继承自models.Model类,这个类是所有模型类的基类。并且这个类之包含一个字段url,它的类型是models.URLField,而且这个字段的值必须是唯一的。

models.URLField类型是Django提供的众多字段类型之一。下表是这些字段类型的一部分:

字段类型
描述
IntegerField
代表一个整数
TextField
一个大的文本字段
DateTimeField
日期时间格式的字段
EmailField
最大75个字符的email地址字段
URLField
最大200个字符的URL地址字段
FileField
一个文件上传字段
要使用这个字段我们首先需要在Django项目中将它激活。我们通过配置settings.py文件来完成,首先找到NSTALLED_APPS变量,然后将我们的应用程序名称(django_bookmarks.bookmarks)加入其中:

INSTALLED_APPS = (
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.sites',
'django_bookmarks.bookmarks',
)
然后执行下面的命令在数据库中创建Links表:

$ python manage.py syncdb

你应该记得我们在前面使用这个命令来创建Django自己的管理表。每次你增加新的数据模型的时候你都需要执行这个命令来向数据库添加新的表。

如果你熟悉SQL,你可能希望看看Django产生的SQL语句是什么,那么运行下面的命令:

$ python manage.py sql bookmarks

如果你使用的是不同的数据库引擎,输出的结果略有不同,对于SQLite3,输出的SQL是这样的:

BEGIN;
CREATE TABLE "bookmarks_link" (
"id" integer NOT NULL PRIMARY KEY,
"url" varchar(200) NOT NULL UNIQUE
);
COMMIT;

我们在执行上面的语句到底发生了什么?首先Django会分析我们的Link模型,就是那个我们定义的Python类,然后产生一个SQL CREATE 语句来创建一个名为bookmarks_link的表。这个表将存储Link类的实例。这里注意一点,Django自动给表增加了一个id字段,这个字段是Link表的主键,以便我们可以唯一的确定一个链接。

Django的Python数据库访问API不仅仅是创建数据库表这么简单,我们可以通过它向表中增加记录、修改记录、查询记录等等操作。我们可以通过Python交互命令控制台来看看这些API是如何使用的,请输入下面的命令:

$ python manage.py shell

这里和标准的Python交互控制台有两点不同,首先我们当前项目的路径被自动加入到Python的sys.path中,其次,它创建了一个特殊的环境变量为settings.py存储这个路径。所以,当你想通过一个命令行来与你的项目交互的话,请使用上面的命令。

接下来,我们导入要使用的模型模块:

>>> from bookmarks.models import *

要在数据库中增加一条link记录,我们需要实例化Link类,并调用它的save方法:

>>> link1 = Link(url='http://www.packtpub.com/')
>>> link1.save()
>>> link2 = Link(url='http://www.example.com/')
>>> link2.save()

要想将数据存储在数据库中,必须调用save方法,在调用这个方法之前你的数据实际上是在内存中,一但你关闭控制台刚才的数据就会丢失。在这里数据库表的字段变成了类的属性,如果你想看看刚才保存的数据或者修改数据,输入下面的命令:

>>> link2.url
'http://www.example.com/'
>>> link2.url = 'http://www.google.com/'
>>> link2.save()

如果想看看刚才保存的所有链接信息,输入下面的内容:

>>> links = Link.objects.all()
>>> for link in links:
... print link.url
...
http://www.packtpub.com/
http://www.google.com/

你可以可以通过Id来得到一个保存的链接信息:

>>> Link.objects.get(id=1)
<Link: Link object>

最后,如果你想删除一条数据,输入下面的内容:

>>> link2.delete()
>>> Link.objects.count()
1

输出结果为1,表示我们已经成功的删除了一条记录,现在只剩下一条链接信息。请注意以上的代码中我们没有使用一行SQL语句,所有这些操作都通过PythonAPI来完成,Django把执行SQL的这一过程封装成PythonAPI。这样做的好处是:

  • 你已经学会了Python,那么使用Django你不必学习另一门语言来处理数据库任务。
  • Django负责Python对象和数据库表之间的转换,你只要操作Python对象就可以,Django负责数据库的存储、查找和管理。
  • 你不必关心不同数据库中特殊的SQL语法,尤其是你需要从一个数据库切换到另一个数据库时。不管你用的是什么数据库,操作PythonAPI的方式是一样的。

用户数据模型

现在你已经熟悉了Django中的数据模型,是时候来创建用户对象了。幸运的是,Django为我们提供了一套通用的用户模型。这个模型包括了通常都会有的用户名、密码和电子邮件等等。这个名为User的模型位于django.contrib.auth.models包下面:

可以通过下面的命令来查看这个对象:

>>> from django.contrib.auth.models import User
>>> User.objects.all()
[<User: ayman>]

你一定还记得们前面章节中将数据库设置的时候,曾经创建了一个超级用户,Djangon把这个信息存储到了数据库中。你可以通过dir函数来查看User对象都有哪些属性和方法:

>>> user = User.objects.get(id=1)
>>> dir(user)

执行上面的语句后你会得到一长串信息,其中你一定会找到username, email 和 password属性。很不错,这个模型完全满足我们的需要,Django提供了我们所需的所有用户对象属性,我们直接使用这User模型不必再重新创建了。

标签数据模型

现在就剩下最后一个数据模型了,Bookmark模型。前面我们提到过这个模型,我们意识到这个对象用于连接User和Link模型。一个标签对应一个用户和一个链接,然而一个用户可以有多个标签,同时一个链接可能被多个用户设置为标签。从数据库的角度将,我们说user表和link表之间存在多对多的关系。但是,没有一个直接的方法来描述两个表之间的多对多关系,于是我们通过Bookmark与User和Link之间分别建立一对多的关系来解决这个问题。

首先,我们建立用户和书签之间的一对多关系,一个用户可以有多个标签,但是一个标签只能与一个用户关联。也就是对应一个具体的链接一个用户只能标记一次。

其次,我们建立连接和标签之间的一对多关系,一个链接可以有多个标签与之关联,比如有多个用户都标记了这个链接,但是反过来一个标签只对应一个链接。

现在我们有了两个单独的一对多关系,这样我们就可以在数据库中对其进行描述了。因此我们需要创建第三个表,bookmarks 表。这个表连接了user表和links表。bookmarks中的每一个表都包含一个指向user表的引用和一个指向links表的引用。在SQL中这种与外部表之间的引用字段成为“外键”。但是在Django中我们无需通过SQL创建这个中间表,我们通过创建bookmarks模型来实现。

下面的代码创建了Bookmark数据模型,你需要把它们加入到bookmarks/models.py文件中,对于以前没有接触过SQL的人,下面的代码看起来不是很清晰,随着不断的什么你会明白它的意义所在,下面是Bookmark数据模型的代码:

class Bookmark(models.Model):
title=models.CharField(maxlength=200)
user=models.ForeignKey(User)
link=models.ForeignKey(Link)

首先我们导入User模型,以便可以在Bookmark中建立引用。接着我们为Bookmark定义一个类。这个新的模型包含一个title字段,它的类型是文本型,然后是分别创建指向User和Link的引用。

按照Python的规约,所有的import语句都应该位于源文件的开始部分,当加入新的代码后,相关的import语句要位于新导入代码的前端,但是建议你最好把所有的import都放在源文件的前面。

加入上面的代码后需要执行manage.py syncdb命令来与数据库同步。让我们来看看Django输出的SQL语句有哪些:

$ python manage.py sql bookmarks

你将看到下面的输出信息,Django为我们创建了必要的表:

BEGIN;

CREATE TABLE "bookmarks_bookmark" (

"id" integer NOT NULL PRIMARY KEY,

"title" varchar(200) NOT NULL,

"user_id" integer NOT NULL REFERENCES

"auth_user" ("id"),

"link_id" integer NOT NULL REFERENCES

"bookmarks_link" ("id"),

);

CREATE TABLE "bookmarks_link" (

"id" integer NOT NULL PRIMARY KEY,

"url" varchar(200) NOT NULL UNIQUE

);

COMMIT;

注意,Django自动给每个外键的_id之前加了一个前缀,并创建了表之间的外键关联。

现在数据模型已经建立好了,我们可以方面的存储和控制我们的数据,Django提供了一套优雅而直白的Python API 来吧Python对象存储到数据库中,这确实把开发人员从编写复杂的SQL工作中解脱了出来。

接下来我们将学习Django中另一个主要的组件技术,模板系统。通过模板系统我们可以非常容易的创建页面,并且利用本章学到的知识为用户创建一个标签列表。

模板:为主要创建一个模板

在本章一开始的部分我们创建了一个简单的主要,主页的HTML代码嵌入到了视图层的代码中,这样做害处很多:

  • 好的软件工程总是强调要将用户界面和业务逻辑分离,因为这样做重用性更高。然而将HTML嵌入到Python代码中的做法违背了这一原则。

  • 修改这种嵌入的代码需要具备Python知识,但是在很多开发团队中,要求页面设计人员理解Python是不现实的。

  • 维护Python代码中的HTML相当麻烦。比如HTML中的引号在Python字符串中需要转移,而且一大堆代码看起来也不清晰易读。

因此解决的办法是将HTML从Python的视图层中分离出来。幸好,Django为我们提供了一个方便的组件来做这件事,这就是模板系统。

这套系统的思想非常简单,我们不在视图层中嵌入HTML而是把它们分离出来放在一个单独的文件中,称为模板。这个模板中可以包含很多占位符,以便展示视图层中的动态数据。当页面输出的时候视图层会加载这个模板文件并将动态值传给这个模板,接着模板系统会逐个的将占位符替换为动态值。为了更好的理解这个概念,让我们将它应用到main_page中。

首先我们要在项目文件夹下创建一个名为templates的文件夹。接下来我们要告诉Django我们的这个模板文件夹templates的位置。所以,打开settings.py,文件并找到TEMPLATE_DIRS变量,把模板文件夹的绝对路径加入其中,如果你不想将模板路径硬编码在settings.py文件中,你可以设置相对路径,请加入下面这对代码:

import os.path

TEMPLATE_DIRS = (

os.path.join(os.path.dirname(__file__), 'templates'),

)

然后在templates文件夹下创建一个main_page.html文件:


<html>

<head>


<title>{{head_title}}</title>

</head>

<body>

<h1>{{page_title}}</h1>

<p>{{page_body}}</p>

</body>

</html>

上面的代码和我们在main_page函数中嵌入的代码非常类似,稍有不同的是我们使用了一种特殊的语法结构来标明我们希望视图层改变的部分,比如{{ head_title }}定义了一个变量head_title,它可以被视图层动态的改变,模板中的变量使用双括号包含。

现在我们看看如何结合视图使用模板系统,编辑bookmarks/views.py文件并加入下面的代码:

from django.http import HttpResponse

from django.template import Context

from django.template.loader import get_template

def main_page(request):

template=get_template('main_page.html')

variables=Context({

'head_title':"Django Bookmarks",

'page_title':"Welcome to Django Bookmarks",

'page_body':"Where you can store and share you bookmark"})

output=template.render(variables)

return HttpResponse(output)

和往常一样让我们逐行解释这段代码:

  • 我们从django.template.loader中导入get_template方法,这个方法通过导入一个文件来返回一个模板对象。

  • 为了给模板中变量赋值,我们声明了一个Context类型的variables变量,这个Context对象包含一个Python的字典对象。在这个字典对象中的的内容是模板对象中的变量名,每一个键的值是模板中变量的值。

  • 为了将模板中的变量替换成我们想要的内容我们使用了模板对象的render方法,这个方法接收一个Context对象参数。所以这里我们把variables变量作为参数传递给这个方法。

  • 最后我们将封装好的包含Html的输出内容交给HttpResponse返回。

如你所见使用上述方法比原来的做法更加简单而且清晰。我们无需在Python代码中嵌入HTML,相反把HTML代码放到一个单独的文件中时的程序更加清晰,结合Django模板系统使这一切变得更加容易。

Django的模板系统还提供了很多其他变量子集,比如用于条件判断的"if"变量,和用于循环的"for"变量,我们将在下面一节中逐步学习这些内容,并创建我们的用户页面。

结合所学的知识:创建一个用户页面

本章已经介绍了不少内容,比如视图、模型和模板的概念。本章剩下的部分我们将结合以上所学的内容创建一个新的页面,这个页面将显示一个用户的所有书签列表。

创建URL

这个新创建页面视图的URL的形式为:user/username,username代表我们要查看这个用户的所有书签。这个URL和我们以前所创建的有所不同,其中的部分内容是动态的。我们将利用正则表达式提供的强大功能来描述这个URL。打开urls.py文件输入如下内容:

from django.conf.urls.defaults import *
from bookmarks.views import *
urlpatterns = patterns('',
(r'^$',main_page),
(r'^user/(\w+)/$',user_page)
)

上面新增的正则表达式比前面介绍的要复杂一点。\w代表这里是字母或者下划线,+代表有一个或多个值。所以实际上,\w+代表这里可以是一个或多个任意的字母或者下划线。这样Diango就会根据我们正则表达式中的内容匹配相应的URL并执行相应的视图函数。

创建和视图

现在我们已经为视图函数定义好了URL入口,是时候创建视图函数了,打开bookmarks/views.py文件并输入下面的内容:

from django.http import HttpResponse,Http404
from django.template import Context
from django.template.loader import get_template
from django.contrib.auth.models import User
def main_page(request):
template=get_template('main_page.html')
variables=Context({
'head_title':"Django Bookmarks",
'page_title':"Welcome to Django Bookmarks",
'page_body':"Where you can store and share you bookmark"})
output=template.render(variables)
return HttpResponse(output)
def user_page(request,username):
try:
user=User.objects.get(username=username)
except:
raise Http404("Requested user not found")
bookmarks=user.bookmark_set.all()
template=get_template("user_page.html")
variables=Context({
"username":username,
"bookmarks":bookmarks})
output=template.render(variables)
return HttpResponse(output)

所有的视图函数看起来都差不多,不过还是让我们一起来看看有什么新的内容:

  • 和我们以前创建的函数不同,user_page函数多了一个username参数,还记不记得我们前面定义URL的时候有+w是放在一个括号中的,这种放在括号总的内容会被当作参数传递给视图函数。这个参数就是这里的username。

  • 我们通过User.objects.get方法来查找用户名为username的用户对象。实际上我们可以使用类似的方法查找所有表,主要这个字段的值是唯一的。如果找不到相应的用户,或者有重名的用户对象,这个方法会抛出一个异常。

  • 如果找不到相应的用户对象,我们使用Http404对象抛出一个404异常。

  • 要查询一个用户所有的书签信息,我们可以通过user对象的bookmark_set属性来获得。你不必自己创建这个方法,Django会根据模型之间的关系自动识别并创建相应的属性,好处是,比如你必须再关系SQL 链接查询(JOIN)是否会出错。

设计模板

我们前面创建的视图函数需要一个user_page.html页面模板,并向其传递了参数username和bookmarks变量。现在我们来创建这个模板,在templates文件夹下创建 user_page.html文件,并输入下面内容:

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Django bookmarks --User {{username}}</title>
</head>
<body>
<h1>Bookmarks for User {{username}}</h1>
{%if bookmarks%}
<ul>
{%for bookmark in bookmarks%}
<li> <a href="{{bookmark.link.url}}">{{bookmark.title}}</a></li>
{%endfor%}
</ul>
{%else%}
<p>No bookmarks Found</p>
{%endif%}
</body>
</html>

这个文件的内容比以前的要复杂的多,你使用了“if”和"for" 变量来显示用户的书签信息。bookmarks对象是一个数组对象,所以我们不能直接在页面上显示它;首先我们要确定这个数组对象不为空,然后我们再迭代显示器中的内容。测试一个变量是否为空我们使用了下面的语法结构:

{% if variable %}
<p>variable 中包含数据.</p>
{% else %}
<p>variable是空的</p>
{% endif %}

“if”变量用于进行调解判断,如果判断值不为空则输出第一行内容,否认输出第二行内容。

在一个数组中迭代我们使用下面的语法:

{% for item in list %}
{{ item }}
{% endfor %}

如果要访问一个变量的属性,只要像访问pytohn对象属性那样就可以了:

{{ variable.attribute }}

结合上面的知识我们创建了user_page.html页面,首先我们判断bookmarks中是否为空,如果不为空,那么我们在其中迭代,并逐行显示用户的标签信息;如果为空,我们就打印一条提示信息。

现在打开浏览器并输入下面地址http://127.0.0.1:8000/user/your_username(把your_username替换成你数据库中实际的用户名),你将看到下面的页面:

我们的页面可以正常的现实,但是如你所见,现在没有任何书签数据,让我们动手加入一些,输入下面的命令:

$ python manage.py shell

为数据模型填充数据

首先创建user对象和link对象的实例:

>>> from django.contrib.auth.models import User
>>> from bookmarks.models import *
>>> user = User.objects.get(id=1)
>>> link = Link.objects.get(id=1)

注意现在user.bookmark_set是空的:

>>> user.bookmark_set.all()
[]

现在创建一个bookmark对象,让他关联上面的user和link:

>>> bookmark = Bookmark(
... title='Packt Publishing',
... user=user,
... link=link
... )
>>> bookmark.save()

现在再检查一下user.bookmark_set:

>>> user.bookmark_set.all()
[<Bookmark: Bookmark object>]

现在刷新一下原来的页面,你会看到下面的内容:

你可以自己增加一些数据试试。还有一个方法bookmark.user,你可以通过bookmark对象来获得user对象,这是Django自动创建的另一个方法,根据模型之间的对应关系,user和bookmark之间是一对多的关系,所以一个用户有多个书签,你可以通过user.bookmark_set获得一个用户的所有书签;而每一个书签只属于一个用户,所以你可以通过bookmark.user得到这个书签对应的用户是什么。

总结

在这一章中我们学习了Django中的3个主要组件:视图、模型和模板。我们创建了数据模型,以便可以通过它为我们的应用程序存储数据,然后创建视图和模板来展示这些数据。我们还学习了如何将URL映射到一个视图函数上,已经如何利用交互式命令行向数据库中增加数据一般检验我们的程序。

下面总结了本章中讲解的Django的知识:

  • 要在项目中创建一个应用程序,使用下面的命令:

    • $ python manage.py startapp <app-name>

  • 创建数据模型之后应该使用下面的命令来与数据库同步:

    • $ python manage.py syncdb

  • 要想查看Django输出的SQL内容,使用下面的命令:

    • $ python manage.py sql <app-name>

  • Django的数据模型提供了一系列的方法与数据库进行交互:

    • save将一个对象保存到数据库

    • objects.get方法获得一个唯一的数据对象。

    • objects.all方法获得所有的数据

    • delete方法从数据库中删除一条数据

  • 通过Http404对象抛出404“页面未找到”异常。

在下一章我们将继续扩展我们的应用程序,我们将增加用户管理功能,比如用户的注册和用户的登录等,下一章将讲述更多Django的功能,跟在我继续学习吧。


No comments: