The Django Book 2.0学习笔记
目录:
Chapter1
- 不使用框架设计 Python 网页应用程序的情形
- 使用CGI标准
- 首先做一个Python脚本,输出HTML代码
- 然后保存成.cgi扩展名的文件,通过浏览器访问此文件
connection = MySQLdb.connect(user='me', passwd='letmein', db='my_db')
cursor = connection.cursor()
cursor.execute("SELECT name FROM books ORDER BY pub_date DESC LIMIT 10")
for row in cursor.fetchall():
print "<li>%s</li>" % row[0]
print "</ul>"
print "</body></html>"
- MVC 是一种软件开发的方法,它把代码的定义和数据访问的方法(模型)与请求逻辑 (控制器)还有用户接口(视图)分开来
Chapter2
- 创建目录:django-admin startrproject XXXX
- init.py :让 Python 把该目录当成一个开发包 (即一组模块)所需的文件。 这是一个空文件,一般你不需要修改它。
- manage.py :一种命令行工具,允许你以多种方式与该 Django 项目进行交互。 键入python manage.py help,看一下它能做什么。 你应当不需要编辑这个文件;在这个目录下生成它纯是为了方便。
- settings.py :该 Django 项目的设置或配置。 查看并理解这个文件中可用的设置类型及其默认值。
- urls.py:Django项目的URL设置。 可视其为你的django网站的目录。 目前,它是空的。
- 尽管这些的文件很小,但这些文件已经构成了一个可运行的Django应用。
- 运行开发服务器:python manage.py runserver
Chapter3
-
每个视图函数至少要有一个参数,通常被叫作request这是一个触发这个视图、包含当前Web请求信息的对象,是类django.http.HttpRequest的一个实例
-
一个视图就是Python的一个函数,这个函数第一个参数的类型是HttpRequest;它返回一个HttpResponse实例。为了使一个Python的函数成为一个Django可识别的视图,它必须满足这两个条件
-
为了绑定视图函数和URL,我们使用URLconf
-
url(r'^hello/$', view.hello),
-
简单来说,我们只是告诉 Django,所有指向 URL /hello/ 的请求都应由 hello 这个视图函数来处理
-
**上箭头^**要求表达式对字符串的头部进行匹配,**美元符号$**则要求表达式对字符串的尾部进行匹配
-
from . import XXX ###相对引用包内的模块导入处于同一顶级包下的模块、包、命名空间用的
-
任何不匹配或尾部没有斜杠(/)的申请URL,将被重定向至尾部包含斜杠的相同字眼的URL
-
如果不喜欢URL以斜杠结尾或者根据每个URL来决定,那么需要设置**”APPEND_SLASH”为”False”**,并且根据你自己的意愿来添加结尾斜杠/在URL模式后
-
另外需要注意的是,我们把hello视图函数作为一个对象传递,而不是调用它。 这是 Python (及其它动态语言的) 的一个重要特性: 函数是一级对象(first-class objects), 也就是说你可以像传递其它变量一样传递它们
-
开发服务器会自动监测代码改动并自动重新载入,所以不需要手工重启
-
所有均开始于setting文件。当你运行manage.py runserver,脚本将在于manage.py同一个目录下查找名为setting.py的文件。这个文件包含了所有有关这个Django项目的配置信息
-
最重要的设置时ROOT_URLCONF,它将作为URLconf告诉Django在这个站点中那些Python的模块将被用到
-
ROOT_URLCONF = 'study_test1.urls'
-
当访问 URL /hello/ 时,Django 根据 ROOT_URLCONF 的设置装载 URLconf 。 然后按顺序逐个匹配URLconf里的URLpatterns,直到找到一个匹配的。 当找到这个匹配 的URLpatterns就调用相关联的view函数,并把 HttpRequest 对象作为第一个参数
-
内部流程:
- 进来的请求转入/hello/.
- Django通过在ROOT_URLCONF配置来决定根URLconf.
- Django在URLconf中的所有URL模式中,查找第一个匹配/hello/的条目。
- 如果找到匹配,将调用相应的视图函数
- 视图函数返回一个HttpResponse
- Django转换HttpResponse为一个适合的HTTP response, 以Web page显示出来
-
Django和URL配置背后的哲学: 松耦合 原则
- 松耦合是一个 重要的保证互换性的软件开发方法
-
正则
符号 | 匹配 |
---|---|
. (dot) | 任意单一字符 |
\d | 任意一位数字 |
[A-Z] | A 到 Z中任意一个字符(大写) |
[a-z] | a 到 z中任意一个字符(小写) |
[A-Za-z] | a 到 z中任意一个字符(不区分大小写) |
+ | 匹配一个或更多 (例如, \d+ 匹配一个或 多个数字字符) |
[^/]+ | 一个或多个不为‘/’的字符 |
***** | 零个或一个之前的表达式(例如:\d? 匹配零个或一个数字) |
***** | 匹配0个或更多 (例如, \d* 匹配0个 或更多数字字符) |
{1,3} | 介于一个和三个(包含)之前的表达式(例如,**\d{1,3}**匹配一个或两个或三个数字) |
-
**“r”**它告诉Python这是个原始字符串,不需要处理里面的反斜杠(转义字符)
-
offset 是从匹配的URL里提取出来的,请注意:捕获值永远都是字符串(string)类型,而不会是整数(integer)类型,即使这个字符串全由数字构成(如:“21”)
-
from datetime import datetime, timedelta now = datetime.now() tommorow = now + timedelta(days=1) ##下一天 next_hours = now + timedelta(hours=1) ##下1小时 next_min = now + timedelta(minutes=1) #下1分钟
-
可以写入 assert False 进入错误页面,进而查看局部变量和程序语句
Chapter4
-
用两个大括号括起来的文字(例如 {{ person_name }} )称为 变量(variable)
-
被大括号和百分号包围的文本(例如 {% if ordered_warranty %} )是 *模板标签(template tag)*即: 仅通知模板系统完成某些工作的标签。
-
{{ship_date|date:”F j, Y” }},我们将变量ship_date传递给date过滤器,同时指定参数”F j,Y”。date过滤器根据参数进行格式输出。 过滤器是用管道符(|)来调用的,具体可以参见Unix管道符。
-
模板系统是一个Python库,你可以在任何地方使用它,而不仅仅是在Django视图中
-
'''Error info: django.core.exceptions.ImproperlyConfigured: Requested setting DEFAULT_INDEX_TABLESPACE, but settings are not configured. You must either define the environment variable DJANGO_SETTINGS_MODULE or call settings.configure() before accessing settings.''' 解决方法: 在文件最上方添加如下代码 import os,django os.environ.setdefault("DJANGO_SETTINGS_MODULE", "project_name.settings")# project_name 项目名称 django.setup()
-
python manage.py shell 和Python都会启动交互解释器,但是manage.py shell命令有一个重要的不同: 在启动解释器之前,它告诉Django使用哪个设置文件。Django框架的大部分子系统,包括模板系统,都依赖于配置文件,如果Django不知道使用哪个配置文件,这些系统将不能工作。
-
当你运行命令:python manage.py shell,它将自动帮你处理DJANGO_SETTINGS_MODULE"
-
一旦你创建一个 Template 对象,你可以用 context 来传递数据给它。 一个context是一系列变量和它们值的集合。
-
from django.template import Context, Template t = Template('My name is {{ name }}.') c = Context({'name': 'Stephane'}) t.render(c) u'My name is Stephane.' #t.render(c)返回的值是一个Unicode对象,不是普通的Python字符串
-
-
class datetime.date(year, month, day): #year : 表示年,范围[MINYEAR, MAXYEAR],即[1, 9999] #month : 表示月,范围[1, 12] #day :一月中第几天,最大值根据给定的year,month参数来决定。例如闰年2月份有29天
-
调用 t.render© 返回字符串, 解释器缺省显示这些字符串的 真实内容呈现 ,而不是打印这个变量的值。 要显示换行而不是 ‘\n’ ,使用 print 语句: print t.render© 。
-
Django模板系统的基本规则
- 写模板
- 创建Template对象
- 创建context
- 调用render方法
-
写代码过程中发现书中例子中用了list.index但是并没有加括号,
-
t = Template('item 2 is {{item.0}}') #就是这里的item.0按Python语言明明是语法错误的,但如果在此将其改为item[0]则会报错 print t.render(Context({'item': ['qw', 'www']})) item 2 is qw
-
后来发现这是Django中模板获取list中指定索引的值的方式
-
示例: {{ goods.0 }}
-
在Django模板系统中很多时候,如果你用点号引用了一下不存在的变量或者方法,让系统深度查找不到的话,那么他就会在那里用空字符串代替,虽然没有引发明显的异常,但是这就已经代表 有错误了
-
默认情况下,如果一个变量不存在,模板系统会把它展示为空字符串,不做任何事情来表示失败。
-
>>> from django.template import Template, Context >>> t = Template('Your name is {{ name }}.') >>> t.render(Context()) u'Your name is .'
-
-
可以通过传递一个完全填充(full populated)的字典给 Context() 来初始化 上下文(Context)
-
在Python和Django模板系统中,以下这些对象相当于布尔值的False
- 空列表([] )
- 空元组(() )
- 空字典({} )
- 空字符串(’’ )
- 零值(0 )
- 特殊对象None
- 对象False(很明显)
-
{% if %} 标签不允许在同一个标签中同时使用 and 和 or\
- 系统不支持用圆括号来组合比较操作。
- 多次使用同一个逻辑操作符是没有问题的,但是我们不能把不同的操作符组合起来。
- 并没有 {% elif %} 标签, 请使用嵌套的
{% if %}
标签来达成同样的效果 - 一定要用 {% endif %} 关闭每一个 {% if %} 标签。
-
for操作:
- Django不支持退出循环操作
- Django也不支持continue语句
- forloop.counter0 类似于 forloop.counter ,但是它是从0计数的,forloop.counter 从计数
- forloop.revcounter 是表示循环中剩余项的整型变量。 在循环初次执行时 forloop.revcounter 将被设置为序列中项的总数。 最后一次循环执行中,这个变量将被置1
- forloop.revcounter0 类似于 forloop.revcounter ,但它以0做为结束索引。在第一次执行循环时,该变量会被置为序列的项的个数减1
- forloop.first 是一个布尔值,如果该迭代是第一次执行,那么它被置为[
](#id12)
(即true) - forloop.last 是一个布尔值;在最后一次执行循环时被置为True
- forloop.parentloop 是一个指向当前循环的上一级循环的 forloop 对象的引用(在嵌套循环的情况下)
stringg = Template('''
<ul>
{% for athlete in athlete_list %}
{%if forloop.first%}<"first">{%else%}<not first> {%endif%}
<li>{{forloop.counter}}:{{ athlete }}</li>
{% endfor %}
</ul>'''
)
c = Context({'athlete_list': [3,4,5,6,7]})
print stringg.render(c)
<ul>
<"first">
<li>1:3</li>
<not first>
<li>2:4</li>
<not first>
<li>3:5</li>
<not first>
<li>4:6</li>
<not first>
<li>5:7</li>
</ul>
- DJango模板不允许我们在模板中执行Python的语句,提供了 {% ifequal %} 标签供我们使用。 {% ifequal %} 支持可选的 {% else%} 标签
{% ifequal user currentuser %}
<h1>Welcome!</h1>
{% endifequal %}
- Python的字典类型、列表类型、布尔类型,不能用在 {% ifequal %} 中
- 可用##进行注释,但注释不能跨越多行。
- 如果要实现多行注释,可以使用’’{% comment %}’'模板标签
{% comment %}
This is a
multi-line comment.
{% endcomment %}
- 模板过滤器是在变量被显示前修改它的值的一个简单方法
- 过滤器总结
过滤器 | 描述 | 示例 |
---|---|---|
upper | 以大写方式输出 | {{ user.name | upper }} |
add | 给value加上一个数值 | {{ user.age | add:”5” }} |
addslashes | 单引号加上转义号 | |
capfirst | 第一个字母大写 | {{ ‘good’| capfirst }} 返回”Good” |
center | 输出指定长度的字符串,把变量居中 | {{ “abcd”| center:”50” }} |
cut | 删除指定字符串 | {{ “You are not a Englishman” | cut:”not” }} |
date | 格式化日期 | |
default | 如果值不存在,则使用默认值代替 | {{ value | default:”(N/A)” }} |
default_if_none | 如果值为None, 则使用默认值代替 | |
dictsort | 按某字段排序,变量必须是一个dictionary | {% for moment in moments | dictsort:”id” %} |
dictsortreversed | 按某字段倒序排序,变量必须是dictionary | |
divisibleby | 判断是否可以被数字整除 | {{ 224 | divisibleby:2 }} 返回 True |
escape | 按HTML转义,比如将”<”转换为”<” | |
filesizeformat | 增加数字的可读性,转换结果为13KB,89MB,3Bytes等 | {{ 1024 | filesizeformat }} 返回 1.0KB |
first | 返回列表的第1个元素,变量必须是一个列表 | |
floatformat | 转换为指定精度的小数,默认保留1位小数 | {{ 3.1415926 | floatformat:3 }} 返回 3.142 四舍五入 |
get_digit | 从个位数开始截取指定位置的数字 | {{ 123456 | get_digit:’1’}} |
join | 用指定分隔符连接列表 | {{ [‘abc’,’45’] | join:’’ }} 返回 abc45 |
length | 返回列表中元素的个数或字符串长度 | |
length_is | 检查列表,字符串长度是否符合指定的值 | {{ ‘hello’| length_is:’3’ }} |
linebreaks | 用 或 | {{ “Hi\n\nDavid”|linebreaks }} 返回 Hi David |
linebreaksbr | 用 标签代替换行符 | |
linenumbers | 为变量中的每一行加上行号 | |
ljust | 输出指定长度的字符串,变量左对齐 | {{‘ab’|ljust:5}}返回 ‘ab ’ |
lower | 字符串变小写 | |
make_list | 将字符串转换为列表 | |
pluralize | 根据数字确定是否输出英文复数符号 | |
random | 返回列表的随机一项 | |
removetags | 删除字符串中指定的HTML标记 | {{value | removetags: “h1 h2”}} |
rjust | 输出指定长度的字符串,变量右对齐 | |
slice | 切片操作, 返回列表 | {{[3,9,1] | slice:’:2’}} 返回 [3,9] {{ 'asdikfjhihgie' | slice:':5' }} 返回 ‘asdik’ |
slugify | 在字符串中留下减号和下划线,其它符号删除,空格用减号替换 | {{ '5-2=3and5 2=3' | slugify }} 返回 5-23and5-23 |
stringformat | 字符串格式化,语法同python | |
time | 返回日期的时间部分 | |
timesince | 以“到现在为止过了多长时间”显示时间变量 | 结果可能为 45days, 3 hours |
timeuntil | 以“从现在开始到时间变量”还有多长时间显示时间变量 | |
title | 每个单词首字母大写 | |
truncatewords | 将字符串转换为省略表达方式 | {{ 'This is a pen' | truncatewords:2 }}返回``This is ... |
truncatewords_html | 同上,但保留其中的HTML标签 | {{ '<p>This is a pen</p>' | truncatewords:2 }}返回``<p>This is ...</p> |
urlencode | 将字符串中的特殊字符转换为url兼容表达方式 | {{ ‘http://www.aaa.com/foo?a=b&b=c’ | urlencode}} |
urlize | 将变量字符串中的url由纯文本变为链接 | |
wordcount | 返回变量字符串中的单词数 | |
yesno | 将布尔变量转换为字符串yes, no 或maybe | {{ True | yesno }}{{ False | yesno }}{{ None | yesno }} ``返回 ``yes``no ``maybe |
- Python 要求单元素元组中必须使用逗号,以此消除与圆括号表达式之间的歧义。
import os.path
TEMPLATE_DIRS = (
os.path.join(os.path.dirname(__file__), 'templates').replace('\\','/'),
)
## Django1.9因为已经设置了BASE_DIR,故写成os.path.join(BASE_DIR, 'templates').replace('\\','/'),即可
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()
t = get_template('current_datetime.html')
html = t.render(Context({'current_date': now}))
return HttpResponse(html)
- 如果 get_template() 找不到给定名称的模板,将会引发一个 TemplateDoesNotExist 异常
from django.shortcuts import render_to_response
.......
return render_to_response('current_datetime.html', {'current_date':now})
#简化上述的模型
#模板加载、上下文创建、模板解析和 HttpResponse 创建工作均在对render_to_response() 的调用中完成
-
由于 render_to_response() 返回 HttpResponse 对象,因此我们仅需在视图中 return 该值。
-
render_to_response() 的第一个参数必须是要使用的模板名称。 如果要给定第二个参数,那么该参数必须是为该模板创建 Context 时所使用的字典。如果不提供第二个参数, render_to_response() 使用一个空字典
-
进一步简化:
def current_datetime(request): current_date = datetime.datetime.now() return render_to_response('current_datetime.html', locals())
-
locals() 的值,它囊括了函数执行到该时间点时所定义的一切变量------包括 所有 的局部变量。将 now 变量重命名为 current_date ,是因为那才是模板所预期的变量名称。
-
当你把模板放入模板目录的子目录中时,get_template()中使用子目录
t = get_template('dateapp/current_datetime.html') return render_to_response('dateapp/current_datetime.html', {'current_date': now})
-
内建模板标签: {% include %} 标签允许在(模板中)包含其它的模板的内容。
{% include 'nav.html' %}
-
在整个网站中,如何减少共用页面区域(比如站点导航)所引起的重复和冗余代码?----------使用 服务器端的 includes
-
模板继承就是先构造一个基础框架模板,而后在其子模板中对它所包含站点公用部分和定义块进行重载。
#base.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<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>
#current_time.html
{%extends "base.html"%} #模板引擎发现了 {% extends %} 标签, 注意到该模板是一个子模板。
{%block title%}The current time{%endblock%}
{%block content%}
<p>It is now {{ current_date }}.</p>
{%endblock%}
{%block footer%}
<hr>current_time
{%endblock%}
#future_time.html
{%extends "base.html"%}
{%block title%}The future time{%endblock%}
{%block content%}
<p>In {{ hour_offset }} hour(s), it will be {{ next_time }}.</p>
{%endblock%}
{%block footer%}
<hr>The future time
{%endblock%}
#简言来说就是用block形式分割BaseHTML,在其他HTML中调用他
- 在加载 current_datetime.html 模板时
- 模板引擎发现了 {% extends %} 标签, 注意到该模板是一个子模板
- 模板引擎立即装载其父模板,即本例中的 base.html
- 模板引擎注意到 base.html 中的三个 {% block %} 标签,并用子模板的内容替换这些 block
- 继承并不会影响到模板的上下文。 换句话说,任何处在继承树上的模板都可以访问到你传到模板中的每一个模板变量。
- 如果需要获取父模板中的 block 的内容,可以使用
{{ block.super }}
变量。如果你想要在父模板 block 中新增内容而不是完全覆盖它,它将非常有用。
Chapter5
- DATABASE_ENGINE 告诉Django使用哪个数据库引擎。 如果你在 Django 中使用数据库, DATABASE_ENGINE 必须是以下中所列出的值。
数据库引擎设置 | ||
---|---|---|
设置 | 数据库 | 所需适配器 |
‘’ postgresql‘’ | PostgreSQL | psycopg 1.x版, http://www.djangoproject.com/r/python-pgsql/1/。 |
postgresql_psycopg2 | PostgreSQL | psycopg 2.x版, http://www.djangoproject.com/r/python-pgsql/。 |
mysql | MySQL | MySQLdb , http://www.djangoproject.com/r/python-mysql/. |
sqlite3 | SQLite | 如果使用Python 2.5+则不需要适配器。 否则就使用 pysqlite http://www.djangoproject.com/r/python-sqlite/。 |
oracle | Oracle | cx_Oracle , http://www.djangoproject.com/r/python-oracle/. |
-
将数据库设置为MySQL
-
'ENGINE': 'django.db.backends.mysql', 'NAME': 'Connection', 'USER': 'root', 'PASSWORD': '12345' 'HOST': 'localhost' 'PORT': 3306
-