Django入门

1、安装python和Django

2、初始化项目:

`$django-admin.py startproject mysite`
生成文件:
    _init__.py(空文件):让Python把该目录当成一个开发包 (即一组模块)所需的文件
    manage.py :一种命令行工具,允许你以多种方式与该 Django 项目进行交互。
    settings.py :该 Django 项目的设置或配置。 查看并理解这个文件中可用的设置类型及其默认值。
    urls.py:Django项目的URL设置。可视其为你的django网站的目录。 目前,它是空的。
运行项目:
    `python manage.py runserver 8080`

在本地网络中的其它计算机就可以在浏览器中访问你的 IP 地址。比如:http://192.168.1.103:8000/

3、视图和URL配置

(1)创建一个views.py文件:

1
2
3
4
from django.http import HttpResponse
def hello(request):
return HttpResponse("Hello world")

一个视图就是Python的一个函数。这个函数第一个参数的类型是HttpRequest;它返回一个HttpResponse实例

(2)修改view.py:URLconf是 URL 模式以及要为该 URL 模式调用的视图函数之间的映射表。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
from django.conf.urls.defaults import *
# Uncomment the next two lines to enable the admin:
# from django.contrib import admin
# admin.autodiscover()
urlpatterns = patterns('',
('^hello/$', hello),
# Example:
# (r'^mysite/', include('mysite.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/', include(admin.site.urls)),
)
  • patterns函数并将返回结果保存到urlpatterns变量。patterns函数当前只有一个参数—一个空的字符串(表示一个视图函数的通用前缀)
  • (‘^hello/$’, hello), 这行被称作URLpattern,它是一个Python的元组。元组中第一个元素是模式匹配字符串(正则表达式);第二个元素是那个模式将使用的视图函数。

Ps:

(1) Python 搜索路径 就是使用 import 语句时,Python 所查找的系统目录清单。
假定你将 Python 路径设置为 [‘’,’/usr/lib/python2.4/site-packages’,’/home/username/djcode/‘] 。如果执行代码 from foo import bar ,Python 将会首先在当前目录查找 foo.py 模块( Python 路径第一项的空字符串表示当前目录)。 如果文件不存在,Python将查找 /usr/lib/python2.4/site-packages/foo.py 文件。

(2) URLpattern的语法

  • Django在检查URL模式前,移除每一个申请的URL开头的斜杠(/)。这意味着我们为/hello/写URL模式不用包含斜杠(/)。
  • 尖号(^)要求表达式对字符串的头部进行匹配,美元符号($)则要求表达式对字符串的尾部进行匹配。

(3) Django是怎么处理请求的:

  • ROOT_URLCONF(默认ROOT_URLCONF = ‘mysite.urls’)告诉Django在这个站点的url配置文件(urls.py)

(3)动态URL

1
2
3
4
5
urlpatterns = patterns('',
# ...
(r'^time/plus/\d+/$', hours_ahead),
# ...
)

一个URL模式就是一个正则表达式。因此,这里可以使用d+来匹配1个以上的数字。正则表达式字符串的开头字母“r”。 它告诉Python这是个原始字符串,不需要处理里面的反斜杠(转义字符)。
同时, 我们用一个视图函数就可以处理所有的时间段了。 我们使用圆括号把参数在URL模式里标识出来。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
## url.py
from django.conf.urls.defaults import *
from mysite.views import hello, current_datetime, hours_ahead
urlpatterns = patterns('',
(r'^hello/$', hello),
(r'^time/$', current_datetime),
(r'^time/plus/(\d{1,2})/$', hours_ahead),
)
## view.py
from django.http import Http404, HttpResponse
import datetime
def hours_ahead(request, offset):
try:
offset = int(offset)
except ValueError:
raise Http404()
dt = datetime.datetime.now() + datetime.timedelta(hours=offset)
html = "<html><body>In %s hour(s), it will be %s.</body></html>" % (offset, dt)
return HttpResponse(html)

offset 是从匹配的URL里提取出来的。 例如:如果请求URL是/time/plus/3/,那么offset将会是3;如果请求URL是/time/plus/21/,那么offset将会是21。

4、模板

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
<html>
<head><title>Ordering notice</title></head>
<body>
<h1>Ordering notice</h1>
<p>Dear {{ person_name }},</p>
<p>Thanks for placing an order from {{ company }}. It's scheduled to
<!-- 这个例子中的{{ship_date|date:”F j, Y” }},我们将变量ship_date传递给date过滤器,同时指定参数”F j,Y”。 -->
ship on {{ ship_date|date:"F j, Y" }}.</p>
<p>Here are the items you've ordered:</p>
<ul>
{% for item in item_list %}
<li>{{ item }}</li>
{% endfor %}
</ul>
{% if ordered_warranty %}
<p>Your warranty information will be included in the packaging.</p>
{% else %}
<p>You didn't order a warranty, so you're on your own when
the products inevitably stop working.</p>
{% endif %}
<p>Sincerely,<br />{{ company }}</p>
</body>
</html>

(1)Python代码中使用Django模板的最基本方式如下:

  • 可以用原始的模板代码字符串创建一个 Template 对象, Django同样支持用指定模板文件路径的方式来创建 Template 对象;
  • 调用模板对象的render方法,并且传入一套变量context。它将返回一个基于模板的展现字符串,模板中的变量和标签会被context值替换。
    1
    2
    3
    4
    5
    >>> from django import template
    >>> t = template.Template('My name is {{ name }}.')
    >>> c = template.Context({'name': 'Adrian'})
    >>> print t.render(c)
    My name is Adrian.

Ps:
1、输入命令 python manage.py shell 启动交互界面。在启动解释器之前,它告诉Django使用哪个设置文件。 Django框架的大部分子系统,包括模板系统,都依赖于配置文件。

(2)模板渲染

context在Django里表现为 Context 类,在 django.template 模块里。 她的构造函数带有一个可选的参数: 一个字典映射变量和它们的值。 调用 Template 对象 的 render() 方法并传递context来填充模板:

1
2
3
4
5
>>> from django.template import Context, Template
>>> t = Template('My name is {{ name }}.')
>>> c = Context({'name': 'Stephane'})
>>> t.render(c)
u'My name is Stephane.' #返回的值是一个Unicode对象

Ps:
假设你要向模板传递一个 Python 字典。 要通过字典键访问该字典的值,可使用一个句点

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
>>> from django.template import Template, Context
>>> person = {'name': 'Sally', 'age': '43'}
>>> t = Template('{{ person.name }} is {{ person.age }} years old.')
>>> c = Context({'person': person})
>>> t.render(c)
u'Sally is 43 years old.'
### 自定义类
>>> from django.template import Template, Context
>>> class Person(object):
... def __init__(self, first_name, last_name):
... self.first_name, self.last_name = first_name, last_name
>>> t = Template('Hello, {{ person.first_name }} {{ person.last_name }}.')
>>> c = Context({'person': Person('John', 'Smith')})
>>> t.render(c)
u'Hello, John Smith.'
### 引用对象的方法
>>> from django.template import Template, Context
>>> t = Template('{{ var }} -- {{ var.upper }} -- {{ var.isdigit }}')
>>> t.render(Context({'var': 'hello'}))
u'hello -- HELLO -- False'
>>> t.render(Context({'var': '123'}))
u'123 -- 123 -- True'

(3)标签

(4)过滤器

1
2
3
4
5
6
7
8
# 显示的内容是变量 {{ name }} 被过滤器 lower 处理后的结果
{{ name|lower }}
# 一个过滤器管道的输出又可以作为下一个管道的输入
{{ my_list|first|upper }}
# 过滤器的参数跟随冒号之后并且总是以双引号包含
{{ bio|truncatewords:"30" }} # 这个将显示变量 bio 的前30个词。

(5)在视图中使用模板

模板加载的路径: 要使用模板加载API,首先你必须将模板的保存位置.(在ROOT_URLCONF配置的settings.py做修改)

1
2
3
4
5
import os.path
TEMPLATE_DIRS = (
os.path.join(os.path.dirname(__file__), 'templates').replace('\\','/'),
)

Python 内部变量__file__,该变量被自动设置为代码所在的 Python 模块文件名。 os.path.dirname(__file__) 将会获取自身所在的文件,即settings.py 所在的目录,然后由os.path.join 这个方法将这目录与 templates 进行连接。

修改视图代码
1
2
3
4
5
6
7
8
9
10
11
from django.template.loader import get_template
from django.template import Context
from django.http import HttpResponse
import datetime
def current_datetime(request):
now = datetime.datetime.now()
# get_template() 函数以模板名称为参数,在文件系统中找出模块的位置,打开文件并返回一个编译好的 Template 对象。
t = get_template('current_datetime.html')
html = t.render(Context({'current_date': now}))
return HttpResponse(html)
render_to_response

载入一个模板文件,然后用 Context渲染它,最后返回这个处理好的HttpResponse对象给用户。我们使用get_template() 方法代替

1
2
3
4
5
6
from django.shortcuts import render_to_response
import datetime
def current_datetime(request):
now = datetime.datetime.now()
return render_to_response('current_datetime.html', {'current_date': now})

Python 的内建函数 locals() 。它返回的字典对所有局部变量的名称与值进行映射。

1
2
3
def current_datetime(request):
current_date = datetime.datetime.now()
return render_to_response('current_datetime.html', locals())

(6)include模板标签

该标签允许在(模板中)包含其它的模板的内容。 标签的参数是所要包含的模板名称,可以是一个变量,也可以是用单/双引号硬编码的字符串。和在 get_template() 中一样, 对模板的文件名进行判断时会在所调取的模板名称之前加上来自 TEMPLATE_DIRS 的模板目录。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# mypage.html
<html>
<body>
{% include "includes/nav.html" %}
<h1>{{ title }}</h1>
</body>
</html>
# includes/nav.html
<div id="nav">
You are in: {{ current_section }}
</div>

(7)模板继承

模板继承就是先构造一个基础框架模板,而后在其子模板中对它所包含站点公用部分和定义块进行重载。
第一步是定义基础模板

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN">
<html lang="en">
<head>
<title>{% block title %}{% endblock %}</title>
</head>
<body>
<h1>My helpful timestamp site</h1>
{% block content %}{% endblock %}
{% block footer %}
<hr>
<p>Thanks for visiting my site.</p>
{% endblock %}
</body>
</html>

所有的block标签告诉模板引擎,子模板可以重载这些部分。 每个block标签所要做的是告诉模板引擎,该模板下的这一块内容将有可能被子模板覆盖。
第二步是修改 current_datetime.html 模板来使用它

1
2
3
4
5
6
7
{% extends "base.html" %}
{% block title %}The current time{% endblock %}
{% block content %}
<p>It is now {{ current_date }}.</p>
{% endblock %}

5、模型

(1) MTV 开发模式
  • M ,数据存取部分,由django数据库层处理。
  • V ,选择显示哪些数据要显示以及怎样显示的部分,由视图和模板处理。
  • C ,根据用户输入委派视图的部分,由 Django 框架根据 URLconf 设置,对给定 URL 调用适当的 Python 函数。
(2) 数据库配置

TEMPLATE_DIRS 一样,数据库配置也是在Django的配置文件里,缺省是settings.py 。

  • DATABASE_ENGINE = ‘postgresql_psycopg2’ # DATABASE_ENGINE 告诉Django使用哪个数据库引擎
  • DATABASE_NAME = ‘mydb’ # DATABASE_NAME 将数据库名称告知 Django
  • DATABASE_NAME = ‘/home/django/mydata.db’ # 如果使用 SQLite,请对数据库文件指定完整的文件系统路径
  • DATABASE_USER 告诉 Django 用哪个用户连接数据库
  • DATABASE_PASSWORD 告诉Django连接用户的密码。 SQLite 用空密码即可。
  • DATABASE_HOST 告诉 Django 连接哪一台主机的数据库服务器。

#####Ps:
如果使用的是 MySQL 且该项设置值由斜杠( ‘/‘ )开头,MySQL 将通过 Unix socket 来连接指定的套接字,例如:
DATABASE_HOST = '/var/run/mysql'

我们可以在”mysite”项目目录下执行上章所提到的”python manage.py shell”来进行测试。

1
2
>>> from django.db import connection
>>> cursor = connection.cursor()

(3)project和app之间的区别

一个project包含很多个Djangoapp以及对它们的配置。一个app是一套Django功能的集合,通常包括模型和视图,按Python的包结构的方式存在。

1
2
3
4
5
6
7
8
$ python manage.py startapp books
# 在 mysite 的目录里创建了一个 books 目录
books/
__init__.py
models.py
tests.py
views.py

(4)第一个模型(书籍/作者/出版商 数据库结构)

模型定义
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
from django.db import models
class Publisher(models.Model):
name = models.CharField(max_length=30)
address = models.CharField(max_length=50)
city = models.CharField(max_length=60)
state_province = models.CharField(max_length=30)
country = models.CharField(max_length=50)
website = models.URLField()
class Author(models.Model):
first_name = models.CharField(max_length=30)
last_name = models.CharField(max_length=40)
email = models.EmailField()
class Book(models.Model):
title = models.CharField(max_length=100)
authors = models.ManyToManyField(Author)
publisher = models.ForeignKey(Publisher)
publication_date = models.DateField()

每个模型相当于单个数据库表,每个属性也是这个表中的一个字段。 属性名就是字段名,它的类型(例如 CharField )相当于数据库的字段类型 (例如 varchar )。

模型安装

(1)在 Django 项目中激活这些模型,编辑 settings.py 文件, 找到 INSTALLED_APPS 设置。 INSTALLED_APPS 告诉 Django 项目哪些 app 处于激活状态。

1
2
3
4
5
6
7
8
9
10
11
12
13
MIDDLEWARE_CLASSES = (
# 'django.middleware.common.CommonMiddleware',
# 'django.contrib.sessions.middleware.SessionMiddleware',
# 'django.contrib.auth.middleware.AuthenticationMiddleware',
)
INSTALLED_APPS = (
# 'django.contrib.auth',
# 'django.contrib.contenttypes',
# 'django.contrib.sessions',
# 'django.contrib.sites',
'mysite.books',
)

(2)验证模型的有效性

1
python manage.py validate

(3)生成 CREATE TABLE 语句(只是把SQL语句段打印出来)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
python manage.py sqlall books
# 输出
BEGIN;
CREATE TABLE "books_publisher" (
"id" serial NOT NULL PRIMARY KEY,
"name" varchar(30) NOT NULL,
"address" varchar(50) NOT NULL,
"city" varchar(60) NOT NULL,
"state_province" varchar(30) NOT NULL,
"country" varchar(50) NOT NULL,
"website" varchar(200) NOT NULL
)
;
CREATE TABLE "books_author" (
"id" serial NOT NULL PRIMARY KEY,
"first_name" varchar(30) NOT NULL,
"last_name" varchar(40) NOT NULL,
"email" varchar(75) NOT NULL
)
;
CREATE TABLE "books_book" (
"id" serial NOT NULL PRIMARY KEY,
"title" varchar(100) NOT NULL,
"publisher_id" integer NOT NULL REFERENCES "books_publisher" ("id") DEFERRABLE INITIALLY DEFERRED,
"publication_date" date NOT NULL
)
;
CREATE TABLE "books_book_authors" (
"id" serial NOT NULL PRIMARY KEY,
"book_id" integer NOT NULL REFERENCES "books_book" ("id") DEFERRABLE INITIALLY DEFERRED,
"author_id" integer NOT NULL REFERENCES "books_author" ("id") DEFERRABLE INITIALLY DEFERRED,
UNIQUE ("book_id", "author_id")
)
;
CREATE INDEX "books_book_publisher_id" ON "books_book" ("publisher_id");
COMMIT;

  • 自动生成的表名是app名称( books )和模型的小写名称 ( publisher , book , author )的组合。
  • Django为每个表格自动添加加了一个 id 主键, 你可以重新设置它。
  • 外键是用 REFERENCES 语句明确定义的。

提交SQL语句至数据库的方法

1
python manage.py syncdb

根据 INSTALLED_APPS 里设置的app来检查数据库, 如果表不存在,它就会创建它。 需要注意的是, syncdb 并 不能将模型的修改或删除同步到数据库;如果你修改或删除了一个模型,并想把它提交到数据库,syncdb并不会做出任何处理。

(5)基本数据访问

1
2
3
4
5
6
7
8
9
10
11
# 导入Publisher模型类, 通过这个类我们可以与包含 出版社 的数据表进行交互。
>>> from books.models import Publisher
# 创建一个`` Publisher`` 类的实例并设置了字段`` name, address`` 等的值。调用该对象的 save() 方法,将对象保存到数据库中。 Django 会在后台执行一条 INSERT 语句。
>>> p1 = Publisher(name='Apress', address='2855 Telegraph Avenue',
... city='Berkeley', state_province='CA', country='U.S.A.',
... website='http://www.apress.com/')
>>> p1.save()
# 调用`` Publisher.objects.all()`` 方法获取数据库中`` Publisher`` 类的所有对象。
>>> publisher_list = Publisher.objects.all()
>>> publisher_list
[<Publisher: Publisher object>, <Publisher: Publisher object>]
添加模块的字符串表现

Publisher对象添加一个方法__unicode__(),告诉Python如何将对象以unicode的方式显示出来。

1
2
3
4
5
6
7
8
9
10
11
12
from django.db import models
class Publisher(models.Model):
name = models.CharField(max_length=30)
address = models.CharField(max_length=50)
city = models.CharField(max_length=60)
state_province = models.CharField(max_length=30)
country = models.CharField(max_length=50)
website = models.URLField()
def __unicode__(self):
return self.name

插入和更新数据
1
2
3
4
5
6
7
# 更新一行里的所有列
>>> p = Publisher.objects.get(name='Apress')
>>> p.name = 'Apress Publishing'
>>> p.save()
# 更改某一指定的列
>>> Publisher.objects.filter(id=52).update(name='Apress Publishing')

update()方法对于任何结果集(QuerySet)均有效,这意味着你可以同时更新多条记录。

选择对象
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
# 查找整个表
>>> Publisher.objects.all()
[<Publisher: Apress>, <Publisher: O'Reilly>]
# objects属性称为管理器,管理着所有针对数据包含、还有最重要的数据查询的表格级操作。
# all()返回返回数据库中所有的记录,一个 QuerySet 对象
>>> Publisher.objects.filter(name='Apress')
# SELECT id, name, address, city, state_province, country, website
# FROM books_publisher
# WHERE name = 'Apress';
>>> Publisher.objects.filter(name__contains="press")
# 在 name 和 contains 之间有双下划线。Django也使用双下划线来表明会进行一些魔术般的操作。
# SELECT id, name, address, city, state_province, country, website
# FROM books_publisher
# WHERE name LIKE '%press%';
# 获取单个对象
>>> Publisher.objects.get(name="Apress")
# 就返回了单个对象(QuerySet)。如果结果是多个对象或没有返回结果,会导致抛出异常
# 改进处理
try:
p = Publisher.objects.get(name='Apress')
except Publisher.DoesNotExist:
print "Apress isn't in the database yet."
else:
print "Apress is in the database."
数据排序
1
2
3
4
5
6
>>> Publisher.objects.order_by("name")
# SELECT id, name, address, city, state_province, country, website
# FROM books_publisher
# ORDER BY name;
# 指定逆向排序,在前面加一个减号 - 前缀:
>>> Publisher.objects.order_by("-name")

指定模型的缺省排序方式

1
2
3
4
5
6
7
8
9
class Publisher(models.Model):
name = models.CharField(max_length=30)
...
def __unicode__(self):
return self.name
class Meta:
ordering = ['name']

在任意一个模型类中使用 Meta 类,来设置一些与特定模型相关的选项。

连锁查询
1
2
3
4
5
6
>>> Publisher.objects.filter(country="U.S.A.").order_by("-name")
# SELECT id, name, address, city, state_province, country, website
# FROM books_publisher
# WHERE country = 'U.S.A'
# ORDER BY name DESC;
删除对象
1
2
3
4
# 删除数据库中的对象
>>> Publisher.objects.get(name="O'Reilly").delete()
# 调用delete()方法同时删除多条记录
>>> Publisher.objects.filter(country='USA').delete()