Django Web开发【3】创建网络收藏夹
这一节我们将继续一个创建网络收藏夹应用,并学习视图、模型以及模板的处理过程。
Django是一个MVC开发框架,但是它的控制器对应的为view,而视图对应为模板(template),模型对应model,所以Django也成为MTV框架。
URLS和视图函数(Views)
view(视图函数)通过生成页面来响应某个用户请求,首先我们在项目中先创建一个应用,应用是包含视图与数据模型的容器,在django_boookmarks目录下运行下面的命令:
$ python manage.py startapp bookmarks
创建应用的语法与创建项目的语法类似。运行上述命令之后,Django会自动在bookmarks目录下生成下面的文件。
- __init__.py 表明这是一个包
- views.py 包含视图函数
- models.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中包含了一些用户的输入以及其他信息,如request.GET,request.POST,request.COOKIES等等。最后我们通过HttpResponse生成页面响应返回。
定义了视图函数之后,就需要再定义URL。
打开urls.py,在其中给主页视图添加URL配置。
from django.conf.urls.defaults import *
from bookmarks.views import * urlpatterns = patterns('',
(r'^$', main_page),
)
也来分下下这段代码,首先从django.conf.urls.defaults中导入定义URLS的相关函数,接着从bookmarks.views中导入所有的视图函数,最后定义URL表,将r'^$'映射到视图函数main_page。
r'^$'是一个正则表达式,r代表原始字符串,表示字符串中的特殊字符不会进行转义,^代表字符串的开头,$代表字符串的结尾。所以^$代表了空字符串。python中跟正则表达式相关的模块是re,具体用法可以查看官方文档。
接下来在浏览器中输入http://127.0.0.1:8000/即可看到创建的主页。
Django的工作流程如下所示:
- 当用户请求http://127.0.0.1:8000/时,Django会在urls.py中查找匹配的URL,匹配通过正则表达式完成。
- 如果Django找到匹配的URL,就会调用相应的视图函数,视图函数就收用户浏览器提交的数据信息,然后生成响应页面返回给用户。
- 如果Django没有找到匹配的URL,Django将抛出404异常,同时展示Page Not Found页面。在调试模式下,Django会打印丰富的帮助信息,当然,在部署环境中饭可以关闭调试模式。
数据模型
现在几乎所有的Web站点都会使用数据库管理保存数据,数据库现在已经是网站的重要组成部分。接下里,我们将使用数据库管理用户账号与网络收藏夹。如果你习惯了使用SQL语句对处理数据库,那么你将发现Django处理数据库的方式不太一样,Django是通过Python类对数据库进行管理的。
下面通过例子来讲解,对于我们的网路收藏夹,我们需要在数据库中保存如下信息:
- User(ID,username,password,email)
- Links(ID,URL)
- Bookmarks(ID,title,user_id,link_id)
为了将上面的数据表设计转换成Python代码,需要再bookmarks目录下的models.py进行编辑,models.py用来保存数据模型。
♥Link数据模型
打开bookmarks/models.py,输入以下代码:
from django.db import models
class Link(models.Model):
url = models.URLField(unique=True
models模块包含了一些用来定义数据模型的类,我们定义了一个Link类,它继承自models.Model,Model是所有模型类的基类,Link类定义了一个url字段,这个字段必须是唯一的。
models.URLField只是Django提供的众多数据字段类型之一,下面是其中一些常用的字段类型。
字段类型 描述
IntegerField 整型
TextField 文本类型
DateTimeField 日期时间类型
EmailField 电子邮件类型
URLField URL类型
FielField 文件类型
为了使用这个模型,需要现在settings.py中的INSTALLED_APPS中添加刚刚创建的应用名:
INSTALLED_APPS = (
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.sites',
'django_bookmarks.bookmarks',
)
接下来使用下面的命令在数据库中创建相应的数据表:
$ python manage.py syncdb
注意,每当我们添加一个数据模型,都需要执行上面的命令。Django会自动分析Link模型,然后生成相应的SQL语句,并执行这些语句生成对应的数据表,Django会自动给每个模型添加id字段。这个字段是整个数据表的主键。
Django的数据库API不仅仅能够生成数据表,还可以对数据表进行增删改操作,接下来,我们将通过python交互窗口来探索这些功能,通过下面这条命令打开交互窗口:
$ python manage.py shell
这个命令窗口与标准的窗口不太一样,首先,打开这个窗口之前,Django会将当前项目的路径加入到sys.path中,这样就可以自动导入当前项目中的模块,其次有个特殊的环境变量可以保存我们当前使用的settings.py的路径。所以,每当我们需要使用命令窗口与当前项目交互时,使用上面的命令即可。
接下来,导入models模块中的所有内容:
>>> from bookmarks.models import *
添加一条新的URL,并保存到数据库中:
>>> link1 = Link(url='http://www.packtpub.com/')
>>> link1.save()
>>> link2 = Link(url='http://www.example.com/')
>>> link2.save()
只有当调用save方法的时候,数据才会保存到数据库中,没调用之前,数据都只是缓存在内存中,如果关闭命令窗口,数据将会丢失。
数据表中的字段都会转换成对象的属性,通过下面的方法可修改Link的URL。
>>> link2.url
'http://www.example.com/'
>>> link2.url = 'http://www.google.com/'
>>> link2.save()
通过下面的方法可以获取所有的Link对象。
>>> links = Link.objects.all()
>>> for link in links:
... print link.url
...
http://www.packtpub.com/
http://www.google.com/
通过下面的方法获取指定ID的Link
>>> Link.objects.get(id=1)
<Link: Link object>
最后使用下面方法删除一条Link:
>>> link2.delete()
>>> Link.objects.count()
1
输出结果1表明现在只剩一条Link,注意上面我们所有的操所都不是通过SQL来执行的,Django提供了几乎所有的数据接口,实际上上面的所有命令都是先转换成SQL再执行的。这样做的好处是非常明显的:
- 不需要非常了解SQL语句
- Django透明的处理Python对象与数据表的转换,你只需要与Python打交道。
- 开发者不需要担心不同数据库而导致的SQL差异。不管使用哪种数据库,Django提供的接口都是一样的。
♥User数据模型
接下来创建用户数据模型,幸运的是,Django已经给开发者提供了一个内置的用户数据模型,它位于django.contrib.auth.models中,模型名为User。
>>> from django.contrib.auth.models import User
>>> User.objects.all()
[<User: root>]
可以发现数据表中已经包含了一个用户,这个用户是我们第一次执行syncdb时生成的用户。
使用dir()函数可以查看User模型的字段。
>>> user = User.objects.get(id=1)
>>> dir(user)
结果得到一个属性列表,其中包含了username,email以及password属性,这些刚好满足我们的要求,所以直接使用就行了。
♥Bookmark数据模型
最后我们定义Bookmark数据模型,User与Bookmark以及Link与Bookmark之间的关系都是一对多的关系。在数据表中的表现就是外键,所以在Bookmark数据模型中我们定义两个外键:
from django.contrib.auth.models import User
class Bookmark(models.Model):
title = models.CharField(maxlength=200)
user = models.ForeignKey(User)
link = models.ForeignKey(Link
接着执行python manage.py syncdb即可。
通过下面的命令可以得到Django实际上是如何处理外键的SQL语句:
$ python manage.py sql bookmarks
结果为:
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也自动给Bookmark添加了id属性。
主页模板
在前面的部分,我们通过将HTML硬编码到代码中,创建了一个简单的应用主页,这样有很多缺点:
- 优秀的软件工程实践一直强调UI与业务逻辑的分离,因为这样才会增强代码的重用性。而在Python代码中编辑HTML违反了这一原则。
- 修改嵌套在Python中的HTML代码需要了解Python知识,但是作为前端开发者,很多都不了解Python,所以这样做也不实际。
- 在Python中处理HTML代码是非常冗长乏味的工作。
因此,最好将Django视图与HTML代码分离开来,幸运的是,Django提供了这样一个机制,那就是模板系统。
模板系统的机制很简单,它将HTML代码保存在模板中,在这个模板中有一些占位符,占位符的内容可以被视图所产生的动态内容所替换,当生成一个页面时,视图函数加载模板,然后将动态产生的值传递给它,然后模板将占位符替换成对应的内容,最终生成页面返回。
为了更好的理解这一机制,我们修来之前创建的main_page视图,首先在当前项目中创建一个templates目录,然后打开settings.py文件,找到TEMPLATES_DIRS变量,将templates的路径加到这里,如果你想支持跨平台,那就使用下面的代码:
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>
模板的结构与HTML很相似,但是其中包含了一些特殊的语法,模板变量,例如{{ 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 bookmarks!'
})
output = template.render(variables)
return HttpResponse(output)
为了加载模板,我们使用了 get_template方法,它位于django.template.loader中,这个方法使用模板名作为参数,返回一个template对象。通过创建一个Context对象,来设置模板中的变量值,Context使用一个字典作为参数,字典使用模板变量为键,对应的值为变量的实际值。使用template对象的render方法替换模板中的变量值,最后通过HTTPResponse将得到输返回。
这样做的好处是非常明显的,我们不再需要在Python代码中处理HTML代码了,HTML部分可以直接交给前端工作者处理了。
生成用户页面
前面我们介绍了视图,模板以及数据模型,最后,我们将使用这些知识创建一个用户页面,这个页面将展示属于这个用户的所有Bookmarks。
1.设计URL
这个视图的URL格式为:user/username,username是书签所有者的用户名,这个URL与我们之前添加的URL不太一样,它包含了一个动态部分,我们需要使用正则表达式来表示这个URL,编辑urls.py,
urlpatterns = patterns('',
(r'^$', main_page),
(r'^user/(\w+)/$', user_page),
)
\w代表任意一个字母数字或者下划线,+代表一个或者多个。
2.创建视图函数
打开bookmarks/views.py视图,添加如下代码:
from django.http import HttpResponse, Http404
from django.contrib.auth.models import User
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)
跟之前的视图不太一样,这个视图提供了第二个参数,这个参数是从url中获取到的。通过User.object.get()函数获取用户名为username的用户,如果没找到或者找到多个同名用户,就抛出404异常。为了获取指定用户所拥有的bookmarks,我们使用user对象的bookmark_set属性,Django会自动检查不同模型之间的关系,然后生成这样的属性。
3.设计模板
在templates目录下创建user_page.html:
<html>
<head>
<title>Django Bookmarks - User: {{ username }}</title>
</head>
<body>
<h1>Bookmarks for {{ 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标签可以判断变量是否包含了数据,如果有,则输出下面的信息,如果没有,则输出else下面的语句。for标签用来循环一个列表。
最后在浏览器中输入http://127.0.0.1:8000/user/your_username,就得到了最后的结果。虽然模板成功展示了,但是现在用户还没有对应的bookmark数据。我们可以通过交互窗口创建一写bookmarks。
运行python manage.py shell
然后执行下面的命令:
>>> 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.all()
[]
>>> bookmark = Bookmark(
... title='Packt Publishing',
... user=user,
... link=link
... )
>>> bookmark.save()
>>> user.bookmark_set.all()
[<Bookmark: Bookmark object>]
这样,页面中就会展示bookmarks信息了。
Django Web开发【3】创建网络收藏夹的更多相关文章
- Django web开发【5】 实现标签功能
标签tag在很多web2.0应用中都很常见,标签其实就是关联某些信息的一个关键字.打标签实际上就是给内容分配标签的过程,它通常由作者或者用户实现.标签之所有这么流行是因为它允许用户对自己创建的博客.图 ...
- Django Web开发【1】Django简介
前言 看完<Django Book>之后, 总想找个实例来实战开发下,无奈国内Django的书籍相当少,只能从英文书籍中吸取养料,偶然之后得到Learning Website Develo ...
- Django Web开发指南笔记
Django Web开发指南笔记 语句VS表达式 python代码由表达式和语句组成,由解释器负责执行. 主要区别:表达式是一个值,它的结果一定是一个python对象:如:12,1+2,int('12 ...
- Django web 开发指南 no such table:
在学习django web开发指南时,发布新博客点击save后会有error提示:no such table balabalabala... 百度了一下说重新运行manage.py syncdb 就可 ...
- Django Web开发学习笔记(1)
一.Python的标准类型 (1)bool型 >>> bool("") False >>> bool(None) False >>& ...
- Django Web开发【4】 用户注册与管理
几乎所有的网站都提供了用户注册与管理功能,这一节,我们将讲解如何利用Django自身提供的用户认证系统实现用户注册与管理功能. 会话认证 在上一节中,我们学习了User数据模型,并用它来保存用户信息, ...
- Django web编程1 -- 创建项目和应用
python:3.7.2 Django:2.1.7 1.创建虚拟环境 虚拟环境是系统的一个位置,可以在其中安装包,并将其与其他python包隔离. 创建目录,命名为learning_log,并切换到这 ...
- [python] python django web 开发 —— 15分钟送到会用(只能送你到这了)
1.安装python环境 1.1 安装python包管理器: wget https://bootstrap.pypa.io/get-pip.py sudo python get-pip.py 1. ...
- Django Web开发【2】Django入门
配置开发环境 1.安装Python,我使用的是centos 6.0,python版本为2.6.6 2.安装Django,Django版本为1.3.5 在Django官网下载对应版本之后,解压压缩包,进 ...
随机推荐
- oracle&&Sqlserver获取表名列名主键及数据类型
SQlserver获得列名,列类型,列类型长度,scale,prec等数据类型(syscolumns,systypes,sysobjects均为视图) select a.name as colname ...
- html系列教程--ol ul li
<li> 标签:配合ol,ul实现有序,无序列表以及导航实现. demo: <ol> <li>Coffee</li> <li>T ...
- Android API Level在11前后及16之后时Notification的不同用法
作为刚入门Android的小白,最近在按照郭大神的<第一行代码>在练习,在用到Notification时遇到了一些问题,网上资料比较零散,我这里做了一个总结分析给各位,若有错误,恳请指正~ ...
- ora-06502
执行一个存储过程时报这个错误 ORA-06502: PL/SQL: 数字或值错误 发现是定义的字符串的缓冲区太小,赋给字符串的值又太大 修改varchar2(20) → varchar2(200 ...
- c#导出文件,文件名中文乱码解决方法。
public string clFielName(string fileName) { System.Web.HttpContext curContext = System.Web.HttpConte ...
- JAVA G1收集器 第11节
JAVA G1收集器 第11节 上两章我们讲了新生代和年老代的收集器,那么这一章的话我们就要讲一个收集范围涵盖整个堆的收集器——G1收集器. 先讲讲G1收集器的特点,他也是个多线程的收集器,能够充分利 ...
- 我本人一直以来犯的错误,在看了《Think In Java》后才抓了出来(转)
也许你是只老鸟,也许你的程序编的很精,但是,在你的程序生活,你也许没有注意到一些“常识性”的问题,因为有些时候我们不需要去注意,我们的程序 照样能够运行得飞快,但是如果那天有一个无聊的人问你一个像这样 ...
- 最近做OpenWrt的总结
用到了哪些东西 需要在OpenWrt上开发一个客户端,用C语言写还比较方便,最开始在linux上跑,后面移植到路由器上,做成ipk.除了稍微修改了下Makefile,其他的什么都没改. 因为需要做个配 ...
- Java提高学习之Object类详解(1)
转自:http://www.importnew.com/10304.html 问:什么是Object类? 答:Object类存储在java.lang包中,是所有java类(Object类除外)的终极父 ...
- js返回值
看下js变量.作用域.内存文档. 1. <script type="text/javascript"> function c(){ return 23; } var a ...