<The django book> & <Offical site basic tutorial> - 读书笔记

 

我的选择是Django,原因是我什么都不知道,没什么特别原因。

  1. Django有什么缺点呢? THIS.
  2. 这是我目前看得书《The django book》: THIS_CN(of course, u can chose THIS_EN),这是官网的
  3. 我看了一遍<The django book>,但是感觉不够,因为Django 1.5有变化,还因为,我感觉我对这Django这玩意很不熟悉啊!我没底啊!然后,我看了 官网

      

Chapter_1:

  快点看完前12章。 因为向下兼容的特性,我就继续看,继续做了。

$ python -c 'import django; print(django.get_version())'
1.5.1

 

Chapter_2:

  Command_0: python manage.py syncdb

  Each of these applications makes use of at least one database table, though, so we need to create the tables in the database before we can use them. To do that, above command.

  每一个app都至少利用一个 数据库表,所以,我们需要创建一个 表,在我们使用表之前。在做好了settings.py中的设置之后,运行上面的命令。这会参照INSTALLED_APPS 。

  数据库,我推荐 PostgreSQL(我没有使用数据库的经验,感性上的选择); SQLite是我选的数据库,它使用文件作为

 

project

A Python package – i.e. a directory of code – that contains all the settings for an instance of Django. This would include database configuration, Django-specific options and application-specific settings.

  Command_1: django-admin.py startproject mysite - 创建目录,并做项目初始化(将来开发需要的目录、配置文件 等。)

mysite/
    manage.py
    mysite/
        __init__.py
        settings.py
        urls.py
        wsgi.py

——————————————

These files are:

  • The outer mysite/ root directory is just a container for your project. Its name doesn’t matter to Django; you can rename it to anything you like.
  • manage.py: A command-line utility that lets you interact with this Django project in various ways. You can read all the details aboutmanage.py in django-admin.py and manage.py.
  • The inner mysite/ directory is the actual Python package for your project. Its name is the Python package name you’ll need to use to import anything inside it (e.g. mysite.urls).
  • mysite/__init__.py: An empty file that tells Python that this directory should be considered a Python package. (Read more about packagesin the official Python docs if you’re a Python beginner.)
  • mysite/settings.py: Settings/configuration for this Django project. Django settings will tell you all about how settings work.
  • mysite/urls.py: The URL declarations for this Django project; a “table of contents” of your Django-powered site. You can read more about URLs in URL dispatcher.
  • mysite/wsgi.py: An entry-point for WSGI-compatible webservers to serve your project. See How to deploy with WSGI for more details.

 

  Command_2: python manage.py runserver(注意:切换到你的项目目录里)

  开发服务器 - 真心好用的东西("开发服务器监测你的代码并自动加载它,这样你会很容易修改代码而不用重启动服务。")

  Read the django-admin.py documentation for full information on what the manage.py utility can do.

 

Chapter_3: 

  Python 搜索路径:    >>> import sys  >>> print sys.path

  如果你是喜欢所有URL都以’/’结尾的人(Django开发者的偏爱),那么你只需要在每个URL后添加斜杠,并且设置”APPEND_SLASH”为”True”.如果不喜欢URL以斜杠结尾或者根据每个URL来决定,那么需要设置”APPEND_SLASH”为”False”,并且根据你自己的意愿来添加结尾斜杠/在URL模式后.

  我们把hello视图函数作为一个对象传递,而不是调用它。 这是 Python (及其它动态语言的) 的一个重要特性: 函数是一级对象(first-class objects),也就是说你可以像传递其它变量一样传递它们。 很酷吧?

  re module

  网站根目录_结尾“,”不可忽略:  ('^$', my_homepage_view),

  最重要的设置时ROOT_URLCONF,它将作为URLconf告诉Django在这个站点中那些Python的模块将被用到: ROOT_URLCONF = 'mysite.urls'(相对应的文件是mysite/urls.py)

页面访问请求过程_总结一下:

  1. 进来的请求转入/hello/.

  1. Django通过在ROOT_URLCONF配置来决定根URLconf. 

  1. Django在URLconf中的所有URL模式中,查找第一个匹配/hello/的条目。

  1. 如果找到匹配,将调用相应的视图函数

  1. 视图函数返回一个HttpResponse

  1. Django转换HttpResponse为一个适合的HTTP response, 以Web page显示出来

  So,一个Django-powered网页 = 视图函数(in views.py) + ROOT_URLConfs(in settings.py) (URLConf(urls.py): view_func <--refer--> URL).

    注意: ROOT_URLConf 和 URLConf 的 是不同的。

        

  reNEW: 2013/5/26 : Chengdu, rent_apartment.

  Python - time function: >>> import datetime  >>> now = datetime.datetime.now()

遵循: So,一个Django-powered网页 = 视图函数(views.py) + ROOT_URLConfs(in settings.py)( URLConf(urls.py): view_func <--refer--> URL).

添加新的视图:

  1. 修改 views.py(视图文件)- 添加新的 视图函数

  2. 修改 urls.py +- 注意, import new_view_function

           +- 注意, URLConfs( urls.py: view_func <--refer--> URL).

 

  Django时区 - "Django是有时区意识的" - settings.py - search: "TIME_ZONE" - Asia/Chongqing

  Core_design_1: 松耦合  - 保证互换性。

  Core_design_2: URL 看起来必须漂亮。 通配符(wildcard URLpatterns)。 正则表达式 设计的 URL。 正则表达式字符串的开头字母要加“r”。“r"代表 自然字符串(原始字符串)。

    reason: 由于反斜杠在Python代码和正则表达式中有冲突,因此建议你在Python定义正则表达式时都使用原始字符串。

  正则表达式(regexes):

符号匹配
. (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}匹配一个或两个或三个数字)

         

  视图函数(views.py),首先,可以从URL传入 值 到 视图函数 中 做操作,姑且认为是参数吧,也就是后面提到的“捕获值”, 请注意: 捕获值永远都是字符串(string)类型,而不会是整数(integer)类型,即使这个字符串全由数字构成(如:“21”)。

  视图函数(views.py),参数名无所谓, 参数位置 代表了 不同 的意义:

    viewFunction( [HttpRequest对象 作为 第一个参数], [String类型 捕获值], ...未知)

    “你还可以使用关键字来定义它,而不是用 位置。” —— 文章并没有说怎么做 —— ?? —— 猜测是python的特性

  ValueError: 如果你在一个不能转换成整数类型的值上调用int(),Python将抛出一个ValueError异常。

  写成 from mysite.views import hello, current_datetime是常常容易忽视的地方,这样会引起 NameError 导致出错, 如果写成,from mysite.views import * 可能只能用在现在这个学习的阶段,不过,可能不是一个好的习惯,可能会包括多余的、不想被别人看到的视图。

    (r'^time/plus/\d{1,2}/$', hours_ahead),  改写成 , (r'^time/plus/(\d{1,2})/$', hours_ahead), —— ?? ——

 

  assert False 是 类似等价于 print 的调试方法。,可以插入在 视图函数中,帮助调试、分析。

 

Chapter_4: Template System 模板系统 (怎么就想到了C++呢。。。

  模板concept: 是一个文本,用于分离文档的表现形式和内容。 模板定义了 占位符 以及各种用于规范文档该如何显示的各部分 基本逻辑 (模板标签)。 模板通常用于产生HTML,但是Django的模板也能产生任何基于文本格式的文档。

  变量(variable): 用两个大括号括起来的文字(例如 {{ person_name }} )称为 变量(variable) 。这意味着在此处插入指定变量的值。 —— 如何指定变量的值?? —— 你可以用 context 来传递数据给它。 一个context是一系列变量和它们值的集合。

  模板标签(template tag): 被大括号和百分号包围的文本(例如 {% if ordered_warranty %} )是 模板标签(template tag) 。标签(tag)定义比较明确,即: 仅通知模板系统完成某些工作的标签。

  filter过滤器 —— 它是一种最便捷的转换变量输出格式的方式 —— 还是不清楚具体做什么?? —— Django 模板含有很多内置的tags和filters.

  “模板系统是一个Python库,你可以在任何地方使用它,而不仅仅是在Django视图中。 ” —— 额,我突然明白了,利用模板系统,就可以实现“设计 与 实现 分离”。 —— 就是下面的摘要。

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

  1. 可以用原始的模板代码字符串创建一个 Template 对象, Django同样支持用指定模板文件路径的方式来创建Template 对象; 

  1. 调用模板对象的render方法,并且传入一套变量context。它将返回一个基于模板的展现字符串,模板中的变量和标签会被context值替换。

  这里的使用有一个最严重的问题就是: 你要明确将 Django 配置到 python 中,我放弃了这一点了。

  Command_3: python manage.py shell,  ~ "manage.py shell命令有一个重要的不同: 在启动解释器之前,它告诉Django使用哪个配置文件。 Django框架的大部分子系统,包括模板系统,都依赖于配置文件;如果Django不知道使用哪个配置文件,这些系统将不能工作。"

系统会在下面的情形抛出 TemplateSyntaxError 异常: 

  • 无效的tags 

  • 标签的参数无效 

  • 无效的过滤器

  • 过滤器的参数无效 

  • 无效的模板语法 

  • 未封闭的块标签 (针对需要封闭的块标签)

 

  Context 构造的参数是Python 字典数据类型。

  使用Django模板系统的基本顺序: 写模板,创建 Template 对象,创建 Context , 调用 render() 方法。 

  模板系统 的 (.)dot 操作符: 

    “非常简洁地处理更加复杂的数据结构,例如list、dictionary和自定义的对象。在 Django 模板中遍历复杂数据结构的关键是句点字符 (.)。”

    1. 要通过 字典键 访问 字典 的值,

    2. 访问 对象属性。 同样可以 创建 自定义的类,用(.)dot访问 自定义类的属性。

    3. 点语法也可以用来引用 对象方法(注意这里调用方法时并* 没有* 使用圆括号 而且也无法给该方法传递参数;你只能调用不需参数的方法。)

    4. 句点也可用于访问 列表 索引不允许使用负数列表索引。——TemplateSyntaxError)

    句点查找可以多级深度嵌套。 例如在下面这个例子中 {{person.name.upper}} 会转换成字典类型查找(person['name'] ) 然后是方法调用( upper() ):

        

  方法调用行为: 
    silent_variable_failure 属性 -- ??(是函数的 隐藏 固有 属性 吗?)

    alters_data 函数属性 -- ??(是函数的 隐藏 固有 属性 吗?)

          

  如何处理无效变量:

    默认情况下,如果一个变量不存在,模板系统会把它展示为空字符串,不做任何事情来表示失败。

 

  标签( if-else ):

{% if  today_with_her %}
    <p>happy</p>
{% elif today_with_computer %}
    <p>everything</p>
{% else %}
    <p>do my best</p>
{% endif %}

 

  P.S:

    1. {% if %} 中接受 and\ or\ not 的关键字, 但是不接受 and 和 or 的混合使用,因为会造成逻辑歧义。

    2. 不支持 圆括号 组合比较操作。

    3. 书中说没有 {% elif %} 标签,但是,现在已经添加了这样的标签。

    4. {% ifequal argv1 argv2 %} hello {% endifequal %} : 比较argv1 和 argv2 是否相等; argv 只可以是: 模板变量、字符串、整数、小数.

      同样还有,{% ifnotequal %}标签。

      如果你需要判断变量是真还是假,请使用 {% if %} 来替代 {% ifequal %} 。

 

  标签( for ):

<p>
    {% for day in week %}
        <li>{{ day.name }}</li>
    {% endfor %}
</p>    

 

  P.S:

    1. {% for day in week reversed %}, 反向迭代 列表,添加 reversed

    2. for循环之前,先检查 列表 是否为空,如果为空,对 空列表 做 特殊处理。 由于这样的检查十分常见,可以选择使用 for循环 特有的 {% empty %}标签。

    3. Django不支持退出循环操作,就是不支持 break 和 continue。 —— 这样的 设计思想是?? ——

    4. {% for %} 循环有 模板变量 “forloop” , 她的属性 可以 提示一些循环的进度。

VariableDescription
forloop.counterThe current iteration of the loop (1-indexed)
forloop.counter0The current iteration of the loop (0-indexed)
forloop.revcounterThe number of iterations from the end of the loop (1-indexed)
forloop.revcounter0The number of iterations from the end of the loop (0-indexed)
forloop.firstTrue if this is the first time through the loop
forloop.lastTrue if this is the last time through the loop
forloop.parentloopFor nested loops, this is the loop “above” the current one

摘自: THIS 

P.S: 

1. forloop.counter0 类似于 forloop.counter ,但是它是从0计数的。 第一次执行循环时这个变量会被设置为0。

 2. forloop.revcounter 是表示循环中剩余项的整型变量。 在循环初次执行时 forloop.revcounter 将被设置为序列中项的总数。 最后一次循环执行中,这个变量将被置1。 

 3. forloop.revcounter0 类似于 forloop.revcounter ,但它以0做为结束索引。 在第一次执行循环时,该变量会被置为序列的项的个数减1。

4. forloop.parentloop 是一个指向当前循环的上一级循环的 forloop 对象的引用(在嵌套循环的情况下)。

例:

{% for country in countries %}

    <table>
    {% for city in country.city_list %}
        <tr>
        <td>Country #{{ forloop.parentloop.counter }}</td>
        <td>City #{{ forloop.counter }}</td>
        <td>{{ city }}</td>
        </tr>
    {% endfor %}
    </table>
{% endfor %}

 

  注释:         

{# This is a comment #}     ----------     不可以用作 多行注释

{% comment %}

  I am a muilt-comments.

{% endcomment %}        ----------     可以用作多行注释

 

 

  过滤器:

    解释: 变量 被显示之前,修改其值 的最简单方法。 BTW, 过滤器 使用 管道字符。

    Try: 试着解释一下呗 ^ ^,filter目录:                    

{{ name|upper }}

{{ name|first|upper }}

{{ fiftyChars|truncatwords:"2" }}

 

 

  理念 和 局限: 

    1. 是否 写 自己的模板语言?

    2. 什么是 full-stack 的 web框架?

    3. 了解 甚至 熟记 了 Django 的 设计哲学 了吗?

 

  在视图中使用模板:

    1. 数据 和 表现 分离。

    2. 大部分实现,依赖 配置文件。

      settings.py - TEMPLATE_DIRS - 可以很容易找到需要加载的html文件 -  Python 要求单元素元组中必须使用逗号,以此消除与圆括号表达式之间的歧义。

      为创建单元素元组,需要在值之后加上一个逗号。没有逗号,Python 会假定这只是一对额外的圆括号,虽然没有害处,但并不创建元组。THIS

    *2. 作为 NO.2 的补充, 如果在 配置文件 中引入 语法错误 或 运行错误,很容易让 django-powered 站点崩溃。这一点要特别注意。

 

  render_to_response():

    一次性载入模板文件,渲染它,然后将次作为 HttpResponse 返回。

    1. 优点: (from django.template.loader import get_template 和 from django.template import Context ) 被 from django.shortcuts import render_to_response 代替。

    2. 更简洁了。 render_to_response() 只是对 get_template() 的一个简单的封装。

    3. render_to_response() 的第一个参数必须是要使用的模板名称。 如果要给定第二个参数,那么该参数必须是为该模板创建 Context 时所使用的字典

  python内建函数 locals():

    locals() 返回 [ 涵盖了] [程序执行到 locals() 处] [ 所有 局部变量 的 名称 与 值 的映射] 的 字典。

    例:                 

now = datetime.datetime.now(); func( {'current_time': now})

  等价于:

current_time = datetime.datetime.now(); func( locals())

 

  P.S:

    第一反应 是 这个函数很特别,好像没有什么作用。 其中一个用法就是在render_to_response(,)的第二个参数,需要一个context字典。如果不像例子中的,前面只有一个临时变量,而是有5个临时变量的赋值,那么,这个时候,你就需要创建5个映射在字典中,这样很麻烦,那么,我们就能用locals() 这个函数,一次性的返回一个符合要求的 字典,然后传入render_to_response(,)的第二个参数。

    如果随便想一想就能相出不少的好处。

 

  get_template()中使用子目录:

    forward slash 分隔路径,在 模板目录 分隔 子目录。

    注意,windows用户必须使用forward slash而不是反斜杠。

 

  include 模板标签:

    1. include 标签 允许 在模板中包含其他的模板的内容。 感觉有点想“继承”。

    2. 每当多个模板中出现相同的代码的时候,就应该考虑是否用{% include %}减少重复。

    3. {% include argv %}:argv 是所要包含的模板名称,可以是 1.变量。 2.单引号\双引号 硬编码 的 字符串。

    4. 和在 get_template() 中一样, 对模板的文件名进行判断时会在所调取的模板名称之前加上来自 TEMPLATE_DIRS的模板目录。

 

  模板继承:

    模板继承 是比 {% include %} 标签更优雅的 网页编写方式。

    1. 抽象公共的部分,建立“基础模板”。定义不同的部分,方便以后填充。以后,子模板 会继承 基础模板。

    2. {% block %} 标签 告诉 模板引擎,子模板可以重载这一部分。

你可以根据需要使用任意多的继承次数。 使用继承的一种常见方式是下面的三层法: 

  1. 创建 base.html 模板,在其中定义站点的主要外观感受。 这些都是不常修改甚至从不修改的部分。 

  1. 为网站的每个区域创建 base_SECTION.html 模板(例如, base_photos.html 和 base_forum.html )。这些模板对 base.html 进行拓展,并包含区域特定的风格与设计。 

  1. 为每种类型的页面创建独立的模板,例如论坛页面或者图片库。 这些模板拓展相应的区域模板。 

 

 下是使用模板继承的一些诀窍: 

  • 如果在模板中使用 {% extends %} ,必须保证其为模板中的第一个模板标记。 否则,模板继承将不起作用。 

  • 一般来说,基础模板中的 {% block %} 标签越多越好。 记住,子模板不必定义父模板中所有的代码块,因此你可以用合理的缺省值对一些代码块进行填充,然后只对子模板所需的代码块进行(重)定义。 俗话说,钩子越多越好。 

  • 如果发觉自己在多个模板之间拷贝代码,你应该考虑将该代码段放置到父模板的某个 {% block %} 中。 

  • 如果你需要访问父模板中的块的内容,使用 {{ block.super }}这个标签吧,这一个魔法变量将会表现出父模板中的内容。 如果只想在上级代码块基础上添加内容,而不是全部重载,该变量就显得非常有用了。 

  • 不允许在同一个模板中定义多个同名的 {% block %} 。 存在这样的限制是因为block 标签的工作方式是双向的。 也就是说,block 标签不仅挖了一个要填的坑,也定义了在模板中这个坑所填充的内容。如果模板中出现了两个相同名称的 {% block %} 标签,父模板将无从得知要使用哪个块的内容。 

  • {% extends %} 对所传入模板名称使用的加载方法和 get_template() 相同。 也就是说,会将模板名称被添加到 TEMPLATE_DIRS 设置之后。 

  • 多数情况下, {% extends %} 的参数应该是字符串,但是如果直到运行时方能确定父模板名,这个参数也可以是个变量。 这使得你能够实现一些很酷的动态功能。

 

 

  

Chapter_5 模型 - Django 数据库层:
                                                                                         1. 视图函数(views.py) 依靠 模板 分隔成 表现逻辑 和 业务逻辑。
  2. 基于 NO.1 中,"分隔"的思想,对数据库的访问,也应该遵循相同的思想。
  3. MVC = M(model 数据存取) + V(view 系统选择显示什么 和 怎么显示) + C(control 根据用户输入去访问 model)
  4. Django_MVC = M(Django数据库层处理)
            + V(系统选择显示什么 和 怎么显示)
            + C(Django根据 URLConf(urls.py) 对 用户给定的URL 调用适当的 python函数,Django自行处理!!)
  5. 基于NO.4,Django自身的框架为 MTV 模式。
  MTV = M(数据存取层,该层处理与数据相关的所有事务)
      + T(Template,表现层,该层处理与表现相关的决定: 如何在页面或其他类型文档中进行显示。)
      + V(view, 该层包含 model存取模型 及 调取恰当模板 的相关逻辑。 你可以把它看作 M模型 与 T模板 之间桥梁。)
  P.S:
  我一开始很迷惑,如果耐心梳理,就会明白:MVC中的C层,是有Django自行负责处理的。在MTV中,同样存在着C层,只是不用你负责处理而已。那么我们就在我们的公式中省略掉C好了。
在Django_MVC中,明确在 V层 依靠 Template模板 实现了分隔: 那么就容易明白,MTV中T层的出现,而T层仅仅决定了web页面是怎么表现的,并没有决定web页面是怎么取得这些数据的。V层 是 赋值了 T层中模板标签的值,V层从M层取得数据再赋值给T层。
  综上所述,1. 在MTV中,我们忽略C层,但是C层真实存在。2. 在MVC中, Django又对V层进行了分隔: 表现逻辑(MTV,T层) 和 业务逻辑(MTV,V层)。

很经典的解释:

如果你熟悉其它的 MVC Web开发框架,比方说 Ruby on Rails,你可能会认为 Django 视图V层 是 控制器,而 Django 模板T层 是 视图。 很不幸,这是对 MVC 不同诠释所引起的错误认识。 在 Django 对 MVC 的诠释中,视图V层 用来描述要展现给用户的数据;不是数据 如何展现 ,展现 哪些 数据。 P.S: Django中,C层是框架自身处理的。 相比之下,Ruby on Rails 及一些同类框架提倡 控制器 负责决定向用户展现哪些数据,而视图则仅决定 如何 展现数据,而不是展现 哪些 数据。

两种诠释中没有哪个更加正确一些。 重要的是要理解底层概念。

                

  6.  安装数据库,THIS. (依然还是先忽略数据库)

  7. 再次明确 python manage.py shell 的作用:

`` manager.py shell`` 命令是以 正确Django配置 启用Python交互解释器 的一种方法。 这个方法在这里是很有必要的,因为Django需要知道加载哪个配置文件来获取数据库连接信息。

  8. 一个project(提供配置文件) = 很多个Django app(Django功能的集合,包括 模型 和 视图,按python的package结构存在) + 许多配置文件

  9. 系统对app有一个约定: 如果你使用了Django的数据库层(模型),你 必须创建一个Django app。 模型M层 必须存放在apps中。 因此,为了开始建造 我们的模型,我们必须创建一个新的app。

  10. Command_4: python manage.py startapp App_name ---- 我的感觉是,命令帮助你创捷了文件目录结构并没有配置什么因为后面我移动 所创建的 App_name 这个目录,没有什么影响。

  11. 最后需要注意的是,我们并没有显式地为这些模型定义任何主键。 除非你单独指明,否则Django会自动为每个模型生成一个自增长的整数主键字段每个Django模型都要求有单独的主键。id

  12. 配置文件中,Django是用"."来分隔路径的,相当于我们平时用的 forward slash

  13. Command_5: python manage.py validate ---- 一旦你觉得你的模型可能有问题,运行 python manage.py validate 。 它可以帮助你捕获一些常见的模型定义错误。

  14.book. Command_6: python manage.py sqlall App_name ----  这个是依赖settings.执行的命令,所以,如果你能通过NO.13,就别纠结 app 的路径了。 注意的是:sqlall 命令并没有在数据库中真正创建数据表,只是把SQL语句段打印出来,这样你可以看到Django究竟会做些什么。为此,我们有了下面的NO.15。

  14.offical. Command_6: python manage.py sql app_name

If you’re interested, also run the following commands:

  

  15. Command_7: python manage.py syncdb ---- 真正让Django提交SQL语句到数据库中。要注意的是:syncdb 并 不能将模型的修改或删除同步到数据库;如果你修改或删除了一个模型,并想把它提交到数据库,syncdb并不会做出任何处理。 但是从另一个角度来讲,运行syncdb总是安全的,因为不会重复执行SQL语句。

  16. 这里我不得不说一点:python ../manage.py shell,这个,是可以执行的啊!!尼嘛啊!!我是多么迟钝啊- -

  17. “ def __unicode__(self):", 这个方法,  __unicode__() 方法告诉Python如何将对象以unicode的方式显示出来。双下划线的命名方式说明:

    _XXX      不能用于from module import * 以单下划线开头的表示的是protected类型的变量。即保护类型只能允许其本身与子类进行访问。

    __XXX__     系统定义名字。定义的是特列方法。像__init__之类的

    __XXX      双下划线的表示的是私有类型的变量。只能是允许这个类本身进行访问了。连子类也不可以

  18. 我遇到了“IndentationError: unexpected inden”,这样的错误提示。

    vim中,默认情况是 tab就是tab,空格就是空格。嗯,这是句废话。

    设置:set list,这样可以显示出tab,你也就能看到tab了(是以“ ^I ”这样的标记显示的,结尾用" $ "表示,这跟vim 的键位 $ 代表 eof 是相一致的。 )。

    设置: set expandtab,可以让vim用 空格 代替 tab。值得强调的是,vim 默认 不是 noexpandtab,这个在任何一个vim文件中,都可以验证。 所以,将这些设置到自己的 ~ 中的 .vimrc 中,对于编写python代码还是有益的。       

    最后,我们建议使用: 空格。始终用4个空格来代替你的tab,这样可以保证跨平台。那为什么使用4个空格呢?因为PEP。这个,PEP 20,python之禅。我也不懂PEP,我也觉得等等看是一个借口。我不看了,我要继续Django了,已经走太远了。

  19. unicode对象就是一个python字符串,它可以处理成千上万的字符。Django 在其内部的各个方面都使用到了 Unicode 对象。 模型M层 对象中,检索匹配方面的操作使用的是 Unicode 对象,视图函数(views.py)之间的交互使用的是 Unicode 对象,模板T层 的渲染也是用的 Unicode 对象。 通常,我们不必担心编码是否正确,后台会处理的很好。 MORE THIS

__unicode__() 也是一个很好的例子来演示我们怎么添加 行为 到模型里。 Django的模型不只是为对象定义了数据库表的结构,还定义了对象的行为。 __unicode__() 就是一个例子来演示模型知道怎么显示它们自己。

  20. 从给定的 模型M层,取出所有数据: Publisher.objects.all() —— 这样取出的结果,也跟你自己如何定义的__unicode__函数是有很大关系的。

  21. 模型对象实例,save()操作相当于 INSERT(首次执行save()操作) 或 UPDATE(修改某个单个数据,然后执行save()操作)。

    Publisher.objects.filter(name='Apress') 会取出一个部分数据进行操作。 filter 相当于 WHERE. `` filter()`` 函数返回一个记录集,这个记录集是一个列表。

    Publisher.objects.filter(country="U.S.A.", state_province="CA") 多个条件的 filter 相当于 AND, WHERE country = 'U.S.A.' AND state_province = 'CA';

    Publisher.objects.filter(name__contains="press") 相当于 LIKE,

    还有很多查询操作,Django应该是定义了与SQL操作一一对应的操作。找一个附录出来。

  22. Publisher.objects.get(name="Apress"),获取单个对象,而不是列表。这是要注意:如果结果是多个对象,会导致抛出异常(MultipleObjectsReturned),就因为返回结果不是列表。如果查询没有返回结果也会抛出异常(DoesNotExist),这个异常可以被捕获并处理。

  23. 数据排序,Publisher.objects.order_by("name"),可以指定以其他单个字段的值进行排序。如果需要以多个字段为标准进行排序(第二个字段会在第一个字段的值相同的情况下被使用到),使用多个参数就可以了。Publisher.objects.order_by("-name"),指定逆向排序。

    Django让你可以指定模型的缺省排序方式:class Meta,内嵌于 Publisher 这个类的定义中,这样就可以指定默认排序方式了。

  24. 连锁查询 - Publisher.objects.filter(country="U.S.A.").order_by("-name")

  25. 限制返回的数据, Publisher.objects.order_by('name')[0],只返回第一条的数据内容,有点像数组,可以用index指定。也可以用切片[0:2]。不支持负索引。但是可以先逆向排序,再取第0个元素,这样就能相当于负索引了。

  26. 更新多个对象,结果集(QuerySet)对象的update()方法,Publisher.objects.filter(id=52).update(name='Apress Publishing')。就像是编程一样,可以连续调用函数。突然想到,所谓数据库,就是“增删改查”。

  27. 删除。直接调用delete()方法。

    P.S: 突然发现,我只能删除表中数据,不能删除表本身。 怎么删除表啊!?!?!!?

 

 

Chapter_6 :  Django 站点管理   QUICK_OFFICE  QUICK_BOOK

The admin isn’t intended to be used by site visitors. It’s for site managers.

  admin工作方法:它读取你模式中的元数据,然后提供给你一个强大而且可以使用的界面,网站管理者可以用它立即工作。

  1. django.contrib 包。Django自带很多优秀的附加组件,它们都存在于django.contrib包里。

  2. 激活管理界面。Django管理界面是可选的。

  3. Admin 是如何工作的?

  当服务启动时,Django从`` url.py`` 引导URLconf,然后执行`` admin.autodiscover()`` 语句。 这个函数遍历INSTALLED_APPS配置,并且寻找相关的 admin.py文件。 如果在指定的app目录下找到admin.py,它就执行其中的代码。

综上所述,管理工具其实就是一个Django应用程序,包含自己的模块、模板、视图和URLpatterns。 你要像添加自己的视图一样,把它添加到URLconf里面。 你可以在Django基本代码中的django/contrib/admin 目录下,检查它的模板、视图和URLpatterns,但你不要尝试直接修改其中的任何代码,因为里面有很多地方可以让你自定义管理工具的工作方式。 (如果你确实想浏览Django管理工具的代码,请谨记它在读取关于模块的元数据过程中做了些不简单的工作,因此最好花些时间阅读和理解那些代码。)

  4. 设置字段可选 : 为了指定email字段为可选,你只要编辑Book模块(回想第五章,它在mysite/books/models.py文件里),在email字段上加上blank=True。 Example: email = models.EmailField(**blank=True** )。这里说明,这个字段可以为空。这与后面NO.5提到的: null=True 是不同的意义。

  5. 在SQL中, NULL的值不同于空字符串,就像Python中None不同于空字符串("")一样。NULL是指定空值的方法。这意味着某个字符型字段(如VARCHAR)的值不可能同时包含NULL和空字符串。为了消除歧义,Django生成CREATE TABLE语句自动为每个字段显式加上NOT NULL

  6. null=True: 指定这个字段 可以用 NULL表示 空。(日期型(DateFieldTimeFieldDateTimeField)或数字型(IntegerFieldDecimalFieldFloatField)字段 他们不接受 Django使用 空字符串 填充, 只能用NULL表示空)

    blank=True: 指定 这个字段 可以为 空值(表示空值: 1. 空字符串; 2. NULL)。

    P.S: NO.5 and NO.6中说的特性,可能是存在与1.0的Django中,现在的Django好像不存在这样的问题。但是,我的Django还是这样的问题。 还有 我不会更新数据库,艹!!怎么能允许自己有不会的呢!?你丫的不是要更有力量吗!?你丫的不是要照顾家吗?!你丫的不是还要去见一个人吗?! 参见NO.7.

  7. 如果修改了: publication_date = models.DateField(blank=True, null=True ),但是,你只能手动修改数据库sqlite3。而数据库sqlite3是非常简单的数据库,ALTER TABLE的修改操作,只能支持 修改 和 新增 字段,这样也是一个思路。我是直接删除了表,因为没什么数据。如果希望只是修改一个字段,可以参考THIS,我觉得写得比我这blog好多了- -!

  下面是我的第一次的做法:

    A. python manage.py sqlall books, 先看看输出的 publication_date 字段,还有没有Django自动添加的NOT NULL 约束。应该是没有了。

    B. python manage.py dbshell,如果遇到错误:You appear not to have the 'sqlite3' program installed or on your path. 你可以参照THIS。 

    C. sqlite> DROP TABLE books_Book; 我一开始猜测 app_name 和 字段Book 之间是依靠“."分隔的,这就像是Django一样。但是不对。后来看了看书中,PostgreSQL 的SQL语句,发现是用"_“分隔的。然后,就删了表了。

    D. python manage.py syncdb,执行重新创建表。

    E. python manage.py runserver, 重启服务器,然后,就搞定了。                  

  8. 自定义字段标签

    然而,字段名称并不总是贴切的。有些情况下,你可能想自定义一个标签。 你只需在模块中指定verbose_name

    email = models.EmailField(blank=True, verbose_name='e-mail')

  9. 自定义ModelAdmin类

    Django还提供了大量选项让你针对特别的模块自定义管理工具。 这些选项都在ModelAdmin classes里面,这些类包含了管理工具中针对特别模块的配置。

    自定义列表 - 可以自定义显示 列表 的表现。                          

说明:
list_display(指定列表显示的数据,使用元组), list_filter(显示过滤器,可以过滤指定的字段,使用元组), date_hierarchy(过滤日期型字段,使用 字符串), ordering(指定默认排序方法,类似第五章中,使用class Meta,指定字段的默认排序)

 

 

  - Python 要求单元素元组中必须使用逗号,以此消除与圆括号表达式之间的歧义。

  为创建单元素元组,需要在值之后加上一个逗号。没有逗号,Python 会假定这只是一对额外的圆括号,虽然没有害处,但并不创建元组。THIS 

                   

  自定义编辑表单 - 可以自定义显示 编辑表单 的表现                     

a. fields(指定 编辑表单 中 字段的排列顺序。 并且 作为fields参数的字段 表明其可以被编辑。如果某个字段不在fields参数列表中,那表明不可以被编辑,这个字段会被 隐藏。 缺省fields时,编辑表单包括所有字段。)

b. filter_horizontal(针对 多对多字段,用 一个精巧的JavaScript过滤器 代替 HTML多选框)

c. filter_vertical(这个不解了)

d. raw_id_fields(它是一个包含外键字段名称的元组,它包含的字段将被展现成`` 文本框`` ,而不再是`` 下拉框``。说实话,我看了效果之后,觉得这个操作明显没有下拉框简单,而且输入的是ID,谁会记ID啊?但是这样能解决一个问题,就是如果有几千个数据要载入 下拉框时要花费大量时间来加载页面,如果用输入ID来代替,就可以解决这个问题。)

 

 

  用户、用户组和权限 - END

 

                            

Chapter_7  表单:

  从Request对象中获取数据 - 需要熟悉一些Request对象的属性和方法, 在view函数的执行过程中,你可以用这些属性来获取当前request的一些信息(比如,你正在加载这个页面的用户是谁,或者用的是什么浏览器)。

  1. URL相关信息

      request.path           除域名以外的请求路径,以正斜杠开头               "/hello/"

      request.get_host()       主机名(比如,通常所说的域名)                  "127.0.0.1:8000" or"www.example.com"

      request.get_full_path()      请求路径,可能包含查询字符串                  "/hello/?print=true"

      request.is_secure()      如果通过HTTPS访问,则此方法返回True, 否则返回False      True 或者 False

  P.S: HTTPS

  2. 有关request的其它信息

    request.META 是一个Python字典,包含了所有本次HTTP请求的Header信息,下面是一些有用的Key值

  • HTTP_REFERER ,进站前链接网页,如果有的话。 

  • HTTP_USER_AGENT,用户浏览器的user-agent字符串,如果有的话。 例如:"Mozilla/5.0 (X11; U; Linux i686; fr-FR; rv:1.8.1.17) Gecko/20080829 Firefox/2.0.0.17" . 

  • REMOTE_ADDR 客户端IP,如:"12.345.67.89" 。(如果申请是经过代理服务器的话,那么它可能是以逗号分割的多个IP地址,如:"12.345.67.89,23.456.78.90" 。) 

  我用模板是实现了这个 :

遵循  MTV : 1. 写Template,设计好如何在页面 或 其他类型文档中显示。 P.S: 考虑模板继承。 2. 写View, 从M层取数据,取什么样的数据,传给 Template。

<! template/base.html >

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN">
<html lang="en">
<head>
    <title>{% block title %}{% endblock %}</title>
</head>
<body>
    <h1>{% block h1_title %}{% endblock %}</h1>
    {% block content %}{% endblock %}
    {% block footer %}
    <hr\>
    <p>Thanks for visiting my site.</p>
    {% endblock %}
</body>
</html>
<! DO NOT COPY THIS COMMENT!!! template/httpReq.html >

{% extends 'base.html' %}

{% block title %}HttpRequest example{% endblock %}

{% block h1_title %}HttpRequest example{% endblock %}

{% block content %}
<table>
    <tr><td>Hello world</td></tr>
    {% for k, v in value %}
        <tr><td>{{ k }}</td><td>{{ v }}</td></tr>
    {% empty %}
        <tr><td>Did not get info from user.</td></tr>
    {% endfor %}
</table>
{% endblock %}
mysite/views.py

from django.template.loader import get_template                                 
from django.template import Context
from django.shortcuts import render_to_response

def hello(request):
    values = request.META.items()
    values.sort()

    '''
    # bad method for first test
    html = ["Hello world"]
    for k, v in values:
        html.append('<tr><td>%s</td><td>%s</td></tr>' % (k, v))
    return HttpResponse('<table>%s</table>' % ''.join(html))
    '''

    # good method for second thought, in Template
    t = get_template('httpReq.html')
    html = t.render(Context({'value': values}))
    return HttpResponse(html)

    # of course, u can implement a render_to_response()

  3. 提交的数据信息

  类字典对象

    - HttpRequest对象还有两个属性包含了用户所提交的信息: request.GET 和 request.POST。

    - THIS 更多关于 GET 和 POST 的介绍,还是得看一下,是英文,要不看后面的内容会迷惑。

    - request.GET和request.POST是类字典对象,类似 鸭子判别法。

    - POST数据是来自HTML中的〈form〉标签提交的,而GET数据可能来自〈form〉提交也可能是URL中的查询字符串(the query string)。

  4. 一个简单的表单处理示例

  通常,表单开发分为两个部分: 前端HTML页面用户接口和后台view函数对所提交数据的处理过程。

    - 我们创建一个view函数。新创建的文件可以是任意名字,只要方便自己辨识就好。并且只要在 python的搜索路径 就可以。

  P.S:

    1. 好吧,我不知道python的搜索路径是什么。我去复习第三章- -!

  Python 搜索路径 就是使用 import 语句时,Python 所查找的系统目录清单。 就好像C语言的 include "", include <>。

>>> '查看Python 搜索路径 '
>>> import sys
>>> print sys.path

    2. 查找view函数,是通过urls.py指定URLConf.而 找到urls.py是通过settings,py 的 ROOT_URLConf 指定,来让Django框架明确的。那我们为什么会提到 Python搜索路径 这个鬼东西呢?因为,你去看看views.py,里面用到了 import。这就是我的理解,应该是正确的。

  5. 查询字符串参数

    - POST与GET之间有什么不同?  - 以,会不会改变服务器数据,为判断标准。

      获取使用POST方法的数据与GET的相似,只是使用request.POST代替了request.GET。

      当我们提交表单仅仅需要获取数据时就可以用GET。

      当我们提交表单时需要更改服务器数据的状态,或者其他不仅仅是获取并显示数据的时候就使用POST。

    - Book.objects.filter(title__icontains=q), __icontains是一个数据库查询关键字,我们不推荐在一个包含大量产品的数据库中使用icontains查询,因为那会很慢。 (在真实的案例中,我们可以使用以某种分类的自定义查询系统。 在网上搜索“开源 全文搜索”看看是否有好的方法)

这句话说得很好,虽然简单:

同上一章一样,我们先从最为简单、有效的例子开始。

  6. 改进表单

    - 处理空字符串:在检测到空字符串时更好的解决方法是重新显示表单,并在表单上面给出错误提示以便用户立刻重新填写。 

  7. 简单的验证

    - 关于JavaScript验证,nnd,看!大学不好好看书学吧?现在还是不会JS吧?

    可以使用Javascript在客户端浏览器里对数据进行验证, 要注意: 即使在客户端已经做了验证,但是服务器端仍必须再验证一次。 JavaScript验证可以看作是额外的功能,但不能作为唯一的验证功能。除了在服务器端对用户提交的数据进行验证(例如在视图里验证),我们没有其他办法。 

     - 最简单的处理,就是在视图函数 views.py 中,处理验证逻辑。

  8. 编写Contact表单

  - 一个较为复杂的例子: 站点联系表单。

  - from django.core.mail import send_mail : 注意,若要使用send_mail()函数来发送邮件,那么服务器需要配置成能够对外发送邮件,并且在Django中设置出站服务器地址。 参见规范:http://docs.djangoproject.com/en/dev/topics/email/

  - 为何重定向至新的页面,而不是在模板中直接调用render_to_response()来输出?

原因就是: 若用户刷新一个包含POST表单的页面,那么请求将会重新发送造成重复。 这通常会造成非期望的结果,比如说重复的数据库记录;在我们的例子中,将导致发送两封同样的邮件。 如果用户在POST表单之后被重定向至另外的页面,就不会造成重复的请求了。

我们应每次都给成功的POST请求做重定向。 这就是web开发的最佳实践。

  - CSRF 是什么? Forbidden (403)又是什么? 我现在还是解决不了这个问题。

  Key word: django CSRF verification failed. Request aborted. 问题解决方法(问题虽然解决了,但是我还是没有完全明白其中的道理):

    1. 参考 THIS

    2. 我对《Django book》 - Chapter 7 的 处理代码:

<! template file contact_form.html - form main body >

<form action="/contact/" method="post">
{% csrf_token %}
    <p>Subject: <input type="text" name="subject" value="{{ subject }}"></p>
    <p>Your e-mail (optional): <input type="text" name="email" value="{{ email }}"></p>
    <p>Message: <textarea name="message" rows="10" cols="50">{{ message }}</textarea></p>
    <input type="submit" value="Submit">
</form> 
# contact/views.py

def
contact(request): errors = [] if request.method == 'POST': if not request.POST.get('subject', ''): errors.append('Enter a subject.') # The second argv is default if not request.POST.get('message', ''): errors.append('Enter a message.') if request.POST.get('email') and '@' not in request.POST['email']: errors.append('Enter a valid e-mail address.') if not errors: # topic, message, sender, addressee_list send_mail( request.POST['subject'], request.POST['message'], request.POST.get('email', 'noreply@example.com'), ['siteowner@example.com'], ) #return HttpResponseRedirect('thank_user.html',) return render_to_response('contact_form.html', {'errors': errors, 'subject': request.POST.get('subject', ''), 'message': request.POST.get('message', ''), 'email': request.POST.get('email', ''),}, context_instance=RequestContext(request) )
# configation file - settings.py

MIDDLEWARE_CLASSES = (
    'django.middleware.common.CommonMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    # Uncomment the next line for simple clickjacking protection:
    # 'django.middleware.clickjacking.XFrameOptionsMiddleware',
)

               

  9. 第一个Form类

    - 表单框架最主要的用法是,为每一个将要处理的HTML的`` <Form>`` 定义一个Form类。

    - 社区的惯例是把Form类都放到一个文件中:forms.py

    - 每一个字段都默认是必填。要使email成为可选项,我们需要指定required=False

    - Form类的第一件事情就是将自己显示成 html,尝试输出看一看,同时可以输出不同的格式:

>>> # The path depends on your file structure.
>>> from mysite.contact.forms import ContactForm
>>> print f
>>> print f.as_ul()
>>> print f.as_p()
>>>
>>> # show the specific part
>>> print f['subject']

    - Form对象做的第二件事是校验数据。

>>> # create new object for testing
>>> f = ContactForm({'subject': 'Hello', 'email': 'k@yan.com', 'message': "Nice site!'})

>>> # test if the object is specified or not, 这是个属性啊
>>> f.is_bound

>>> # test if the value of the object is illegal or not,这是个方法了,有些字段被设置为空
>>> f.is_valid()

>>> # 如果f.is_valid()返回值为false,下面可以察看出错信息,如果没有错,打印空
>>> # 察看指定字段的error信息
>>> f['message'].errors
>>> # 察看错误信息
>>> f.errors

>>> # 如果一个Form实体的数据是合法的,它会有一个cleaned_data属性。 这是一个包含干净的提交数据的字典。 Django的form框架不但校验数据,它还会把它们转换成相应的Python类型数据,这叫做干净的数据。
>>> f.cleaned_data
>>> # 我们的contact form只涉及字符串类型,它们会被清理成Unicode对象。如果我们使用整数型或日期型,form框架会确保方法使用合适的Python整数型或datetime.date型对象。

       

  10. 在视图中使用Form对象

    利用Django提供的 类forms,来处理html中的 表单。

    每传见一个表单,就对应地创建一个form。

    简单地说:利用forms类去生成html 然后render到template中。

    同样会产生错误:django CSRF verification failed. Request aborted.

    还会产生错误: [Errno 111] Connection refused - 但是这个错误,书中没有明确说明。至此也不再纠结。

 

  11. 改变字段显示

    利用form类直接输出的html中,大部分都是我们想要的,但是,也有部分是我们不喜欢的。这就是个更详细的定制。在 forms.py 中,传入参数去改变。

forms框架把每一个字段的显示逻辑分离到一组部件(widget)中。 每一个字段类型都拥有一个默认的部件,我们也可以容易地替换掉默认的部件,或者提供一个自定义的部件

 

  12. 设置最大长度

    与NO.11 是基本相同的想法。

  13. 设置初始值

    初始值的设定是在 views.py中的,这个是明显的不同。

请注意,传入* 初始值* 数据和传入数据以* 绑定* 表单是有区别的。 最大的区别是,如果仅传入* 初始值* 数据,表单是unbound的,那意味着它没有错误消息。

  14. 自定义校验规则

    在forms.py 的 类 中添加方法,

Django的form系统自动寻找匹配的函数方法,该方法名称以clean_开头,并以字段名称结束。 如果有这样的方法,它将在校验时被调用。

(为什么会有这样的设定!?感觉很无聊啊!! 不过,好像没有其他的解决办法。)

特别地,clean_message()方法将在指定字段的默认校验逻辑执行* 之后* 被调用。(比如,如果不设置required=False,默认就会进行验证空操作。)

——

在函数的末尾显式地返回字段的值非常重要。 我们可以在我们自定义的校验方法中修改它的值(或者把它转换成另一种Python类型)。 如果我们忘记了这一步,None值就会返回,原始的数据就丢失掉了。

  15. 指定标签

  16. 定制Form设计 (css/div)

 

 

Chapter_8:高级视图和URL配置

  URLconf 技巧

  1. 流线型化(Streamlining)函数导入

# linux shell
$ cat filename| sed '/^$/d'

# 为了处理这个的文本:THIS
# 我写出来了下面两个处理,区别就在于:print line,
# 就在于有没有','
# 我没想到,在表现上,有这样的差别(在linux终端,同样存在这样的差别)
# 并且,两种方法都删除了空白行。
# 我不知道其中的原因。
# result_1: blankLineFile = open('blankLineFile') try: for line in blankLineFile: if line.strip():    print line finally: blankLineFile.close() # result_2: blankLineFile = open('blankLineFile') try: for line in blankLineFile: if line.strip():    print line, finally: blankLineFile.close()

 

result_1:

字符串方法的好处如下:
更紧凑,因为不需要你导入视图函数。
如果你的视图函数存在于几个不同的 Python 模块的话,它可以使得 URLconf 更易读和管理。
函数对象方法的好处如下:
更容易对视图函数进行包装(wrap)。 参见本章后面的《包装视图函数》一节。
更 Pythonic,就是说,更符合 Python 的传统,如把函数当成对象传递。
两个方法都是有效的,甚至你可以在同一个 URLconf 中混用它们。 决定权在你。

 

result_2:

字符串方法的好处如下:

更紧凑,因为不需要你导入视图函数。

如果你的视图函数存在于几个不同的 Python 模块的话,它可以使得 URLconf 更易读和管理。

函数对象方法的好处如下:

更容易对视图函数进行包装(wrap)。 参见本章后面的《包装视图函数》一节。

更 Pythonic,就是说,更符合 Python 的传统,如把函数当成对象传递。

两个方法都是有效的,甚至你可以在同一个 URLconf 中混用它们。 决定权在你。

 

  2. 使用多个视图前缀

# from http://djangobook.py3k.cn/2.0/chapter08/

from django.conf.urls.defaults import *

urlpatterns = patterns('mysite.views',
    (r'^hello/$', 'hello'),
    (r'^time/$', 'current_datetime'),
    (r'^time/plus/(\d{1,2})/$', 'hours_ahead'),
)

urlpatterns += patterns('weblog.views',
    (r'^tag/(\w+)/$', 'tag'),
)

 

整个框架关注的是存在一个名为 urlpatterns 的模块级别的变量。如上例,这个变量可以动态生成。 这里我们要特别说明一下,patterns()返回的对象是可相加的,这个特性可能是大家没有想到的。 

 

  3. 调试模式中的特例

  利用 settings.DEBUG(True, debug开) 这个布尔值,可以在 Django 的debug模式开启的时候,现实某些特定网页,debug模式关闭的时候,不可以访问那些特定的网页。

  4. 使用命名组

    1. 关键字参数 vs 位置参数

为了使用位置参数来调用它,你要按照在函数定义中的顺序来指定参数。

为了使用关键字参数来调用它,你要指定参数名和值。 下面的语句是等价的:

最后,你可以混合关键字和位置参数,只要所有的位置参数列在关键字参数之前。 下面的语句与前面的例子是等价:

    2. 命名组:

      在 Python 正则表达式中,命名的正则表达式组的语法是 (?P<name>pattern) ,这里 name 是组的名字,而 pattern是匹配的某个模式。

# 无命名组

from django.conf.urls.defaults import *
from mysite import views

urlpatterns = patterns('',
    (r'^articles/(\d{4})/$', views.year_archive),
    (r'^articles/(\d{4})/(\d{2})/$', views.month_archive),
)

# equal to:
month_archive(request, '2006', '03')
# 命名组,这段代码和前面的功能完全一样,只有一个细微的差别: 取的值是以关键字参数的方式而不是以位置参数的方式传递给视图函数的。

from django.conf.urls.defaults import *
from mysite import views

urlpatterns = patterns('',
    (r'^articles/(?P<year>\d{4})/$', views.year_archive),
    (r'^articles/(?P<year>\d{4})/(?P<month>\d{2})/$', views.month_archive),
)
# equal to:
month_archive(request, year='2006', month='03') 

 当然,命名组的代价就是失去了简洁性: 一些开发者觉得命名组的语法丑陋和显得冗余。 命名组的另一个好处就是可读性强。

猜测:应该是有现有好用的IDE,可以在一处修改之后,自动修改多处。

   

  3. 理解匹配/分组算法

    注意:如果在URLconf中使用命名组,那么命名组和非命名组是不能同时存在于同一个URLconf的模式中的。

以下是URLconf解释器有关正则表达式中命名组和 非命名组所遵循的算法:
  如果有任何命名的组,Django会忽略非命名组而直接使用命名组。
  否则,Django会把所有非命名组以位置参数的形式传递。
  在以上的两种情况,Django同时会以关键字参数的方式传递一些额外参数。 

 

  4. 传递额外的参数到视图函数中

    1. (不是一个好办法,只是提出了一种方法而已)对两个URL都使用同样的视图,在URL中使用括号捕捉请求,然后在视图中检查并决定使用哪个模板来去除代码的冗余。 存在的问题:这种解决方案的问题还是老缺点,就是把你的URL耦合进你的代码里面了。 如果你打算把 /foo/ 改成 /fooey/ 的话,那么你就得记住要去改变视图里面的代码。

# from this site: http://djangobook.py3k.cn/2.0/chapter08/
# urls.py

from django.conf.urls.defaults import *
from mysite import views

urlpatterns = patterns('',
    (r'^(foo)/$', views.foobar_view),
    (r'^(bar)/$', views.foobar_view),
)

# views.py

from django.shortcuts import render_to_response
from mysite.models import MyModel

def foobar_view(request, url):
    m_list = MyModel.objects.filter(is_new=True)
    if url == 'foo':
        template_name = 'template1.html'
    elif url == 'bar':
        template_name = 'template2.html'
    return render_to_response(template_name, {'m_list': m_list})

 

    2. URLconf里面的每一个模式都可以包含第三个参数: 一个关键字参数的字典。

      其实就是 另一个地方也可以指定 关键字参数 了。

      更本质的是,另一种 向视图函数传递信息的 好方法。

 

  5. 伪造捕捉到的URLconf值

    如果一个 视图函数,没有参数,那么,也就不存在 使用命名组 的情况。

    这个特性,就是让你可以 更好的 重复利用某些 带惨的 视图函数。

    视图函数只会关心它 获得 了 参数,它不会去管这些参数到底是捕捉回来的还是被额外提供的。 

 

  6. 创建一个通用视图

    思想: 抽取出我们代码中共性的东西是一个很好的编程习惯。 

    通过使用额外的URLconf参数(URLconf的每一个模式都可以包含第三个参数),你可以把同样的思想应用到Django的视图中。

    每个Python的类都有一个 __name__ 属性返回类名。 这特性在当我们直到运行时刻才知道对象类型的这种情况下很有用。 比如, BlogEntry 类的 __name__ 就是字符串 'BlogEntry' 。

    因为数据库驱动的网站都有一些通用的模式,Django提供了一个通用视图的集合,使用它可以节省你的时间。 我们将会在下一章讲讲Django的内置通用视图。

 

  7. 提供视图配置选项

    1. 了解捕捉值和额外参数之间的优先级 额外的选项

    - 当冲突出现的时候,额外URLconf参数优先于捕捉值。 

# form this site: http://djangobook.py3k.cn/2.0/chapter08/
# id 始终都是3,因为优先级的问题。这是一种错误,请不要发生。

from django.conf.urls.defaults import *
from mysite import views

urlpatterns = patterns('',
    (r'^mydata/(?P<id>\d+)/$', views.my_view, {'id': 3}),
)

 

    2. 使用缺省视图参数

    - 另外一个方便的特性是你可以给一个视图指定默认的参数。

    - 注:我们已经注意到设置默认参数值是字符串 `` ‘1’`` ,不是整数`` 1`` 。为了保持一致,因为捕捉给`` num`` 的值总是字符串。

# from this site: http://djangobook.py3k.cn/2.0/chapter08/
# urls.py

from django.conf.urls.defaults import *
from mysite import views

urlpatterns = patterns('',
    (r'^blog/$', views.page),
    (r'^blog/page(?P<num>\d+)/$', views.page),
)

# views.py

def page(request, num='1'):
    # Output the appropriate page of blog entries, according to num.
    # ...

 

    3. 特殊情况下的视图

    -  更优雅的解决方法是,我们要利用URLconf从顶向下的解析顺序这个特点. (短路逻辑)

                        

    4. 从URL中捕获文本

    - 这是一个需要注意的点,从URL捕获的是 字符串. 很自然,我们会想到类型转换。

当你在写视图代码时记住这点很重要,许多Python内建的方法对于接受的对象的类型很讲究。 许多内置Python函数是挑剔的(这是理所当然的)只接受特定类型的对象。 一个典型的的错误就是用字符串值而不是整数值来创建datetime.date 对象。

    - 另一个需要注意的点,注意,当你传递了一个并不完全包含数字的字符串时, int() 会抛出 ValueError 的异常,不过我们已经避免了这个错误,因为在URLconf的正则表达式中已经确保只有包含数字的字符串才会传到这个视图函数中。

 

    5. 决定URLconf搜索的东西

    - 在解析URLconf时,请求方法(例如, POST , GET , HEAD )并 不会 被考虑。 换而言之,对于相同的URL的所有请求方法将被导向到相同的函数中。 因此根据请求方法来处理分支是视图函数的责任。

 

    6. 视图函数的高级概念

def method_splitter(request, *args, **kwargs):
    get_view = kwargs.pop('GET', None)
    post_view = kwargs.pop('POST', None)
    if request.method == 'GET' and get_view is not None:
        return get_view(request, *args, **kwargs)
    elif request.method == 'POST' and post_view is not None:
        return post_view(request, *args, **kwargs)
    raise Http404

 

支持使用*args和和**kwargs(注意*号) 这是一个Python特性,允许函数接受动态的、可变数量的、参数名只在运行时可知的参数。

如果你在函数定义时,只在参数前面加一个*号,所有传递给函数的参数要保存为一个元组.

如果你在函数定义时,在参数前面加两个*号,所有传递给函数的关键字参数要保存为一个字典。

 

    7. 包装视图函数

    - 抽象出几个函数中的公共部分,形成一个函数,参数是其它的视图函数。抽象出来的函数,包装其他的函数。

# 我不懂这样的好处。

def requires_login(view):
    def new_view(request, *args, **kwargs):
        if not request.user.is_authenticated():
            return HttpResponseRedirect('/accounts/login/')
        return view(request, *args, **kwargs)
    return new_view

 

    8. 包含其他URLconf

    在任何时候,你的URLconf都可以包含其他URLconf模块。 

    当你访问 ' http://127.0.0.1:8000/admin/‘,就可以直接访问到了

from django.conf.urls import include

urlpatterns = patterns('',
    url(r'^admin/', include(admin.site.urls)),
)

 

    9. 捕获的参数如何和include()协同工作

    - 注意,这个被捕获的参数 总是 传递到被包含的URLconf中的 每一 行,不管那些行对应的视图是否需要这些参数。 \

 

    10. 额外的URLconf如何和include()协同工作

    - 注意,这个被捕获的参数 总是 传递到被包含的URLconf中的 每一 行,不管那些行对应的视图是否需要这些参数。 \

    - 因为这个原因,这种技术仅当你确信在涉及到的接受到额外你给出的选项的每个URLconf都有用时,才奏效。

 

 

Chapter 9 模板高级进阶:

  希望了解 模板系统 或者 好奇模板系统的原理。

  1. 模板语言回顾

    (其实,在上面有更精确的定义,但是我就是想不起来。呵呵,算了,我就自己写了。)

    模版 - 纯文本文件,原本你可以随便叫任何名字,但是我都叫成了 xxx.html。

    这样的文件里面有 模板标签 和 模板变量。 这可以被 视图函数 中被替换。

    模板标签 - 一个在模板里面起 标记作用 的  类似{% if xxx %},用 {% %}包围的东西,通知模版系统完成特定动作。

    变量 - 用{{ }} 包围起来的东西,类似{{ xxx }},就是可以被赋值。

    context - 一个用来 给 变量{{ name }},映射值的东西。类似 template.Context({'name', 'Kevin'}),类似 字典。

    模版渲染 render -  从 Context中获取值,1.代替模板变量。 2.执行所有模板标签。

 

  2. RequestContext和Context处理器

    在解决csrf安全问题的时候,我遇到过,这里又看到了:

    django.template.Context 和 django.template.RequestContext 

RequestContext与Context的区别:

      1,RequestContext 的第一个参数需要传递一个 HttpRequest 对象,就是传递给视图函数的第一个参数(request )。

      2, RequestContext 有一个可选的参数 processors ,这是一个包含context处理器函数的列表或者元组。

    RequestContext 产生的原因:

    { '模板变量': 值} 的映射可能在多个视图函数中都使用,也就是说,这个映射关系不变,只是你要copy/paste好几处位置。

    Django提供的解决方案是 你可以提前就 建立一个这样的映射函数,像下面这样:

# from here: http://djangobook.py3k.cn/2.0/chapter09/

def custom_proc(request):
    "A context processor that provides 'app', 'user' and 'ip_address'."
    return {
        'app': 'My app',
        'user': request.user,
        'ip_address': request.META['REMOTE_ADDR']
    }

 

    然后把函数custom_proc,作为参数,传给RequestContext,这样你就省去很多麻烦了。想这样:

c = RequestContext(request, {'message': 'I am view 1.'},
            processors=[custom_proc])

 

    Django很够意思的是,在settings.py中,已经预先设定了 context processor,也就是TEMPLATE_CONTEXT_PROCESSORS. 根据我们的实际观察,Django 1.5的settings.py中,并没有TEMPLATE_CONTEXT_PROCESSORS。而是在Django的安装路径下,django/conf/global_settings.py。

# check django path in ubuntu

$ python
>>> import django
>>> django

               

    默认的context processor:

      1. django.core.context_processors.auth

  • user :一个 django.contrib.auth.models.User 实例,描述了当前登录用户(或者一个 AnonymousUser 实例,如果客户端没有登录)。
  • messages :一个当前登录用户的消息列表(字符串)。 在后台,对每一个请求,这个变量都调用request.user.get_and_delete_messages() 方法。 这个方法收集用户的消息然后把它们从数据库中删除。
  • perms : django.core.context_processors.PermWrapper 的一个实例,包含了当前登录用户有哪些权限。

      2. django.core.context_processors.debug

  • debug :你设置的 DEBUG 的值( True 或 False )。你可以在模板里面用这个变量测试是否处在debug模式下。

  • sql_queries :包含类似于 ``{‘sql’: …, ‘time’: `` 的字典的一个列表, 记录了这个请求期间的每个SQL查询以及查询所耗费的时间。 这个列表是按照请求顺序进行排列的。

        P.S: debug context processor的信息只有满足:1. DEBUG 参数设置为 True 。 2. 请求的ip应该包含在 INTERNAL_IPS 的设置里面。才会有效。

      3. django.core.context_processors.i18n

  • LANGUAGES : LANGUAGES 选项的值。

  • LANGUAGE_CODE :如果 request.LANGUAGE_CODE 存在,就等于它;否则,等同于 LANGUAGE_CODE 设置。

      4. django.core.context_processors.request

        这好像最有用的一个context processor,或者是显示内容最有意思的

如果启用这个处理器,每个 RequestContext 将包含变量 request , 也就是当前的 HttpRequest 对象。 注意这个处理器默认是不启用的,你需要激活它。

如果你发现你的模板需要访问当前的HttpRequest你就需要使用它:

{{ request.REMOTE_ADDR }}

 

  3. 写Context处理器的一些建议

    1. 逻辑模块 分开明确。

    2. 命名用大写字母是个好主意。

    3. 文件命名建议是context_processors.py。存放路径在 应用目录 或 工程目录下。

              

  4. html自动转意

    1. 用户输入不能轻易信任。不能轻易赋值给 模版变量。这类漏洞称为被跨域脚本 (XSS) 攻击。 

    2. 解决方法:

      1. 自己写保护,自己保证安全。

      2. 利用Django处理html转意。(默认开启) - 是对模版开发的任何部分。

          

  5. 如何关闭 Django 自动转义?

    可以在几个级别上实现关闭:1. 单独的变量。 2. 模板块

     

  6. 过滤器参数里的字符串常量的自动转义

    所有字符常量没有经过转义就被插入模板,就如同它们都经过了safe过滤。 这是由于字符常量完全由模板作者决定,因此编写模板的时候他们会确保文本的正确性。

 

  7. 模板加载的内幕

    Django有两种方法加载模板:

  • django.template.loader.get_template(template_name) : get_template 根据给定的模板名称返回一个已编译的模板(一个 Template 对象)。 如果模板不存在,就触发 TemplateDoesNotExist 的异常。 

  • django.template.loader.select_template(template_name_list) : select_template 很像 get_template ,不过它是以模板名称的列表作为参数的。 它会返回列表中存在的第一个模板。 如果模板都不存在,将会触发TemplateDoesNotExist异常。

    这两个函数是通过settings.py - TEMPLATE_DIR,查找,加载 模板 的。 但是,在内部(其实我不懂,这个是指什么),这两个函数,可以通过指定 一个 模板加载器 来加载模板。

  • django.template.loaders.filesystem.Loader - 这个加载器根据 TEMPLATE_DIRS 的设置从文件系统加载模板。默认启动。
  • django.template.loaders.app_directories.Loader - 这个加 载器从文件系统上的Django应用中加载模板。 对 INSTALLED_APPS 中的每个应用,这个加载器会查找templates 子目录。 如果这个目录存在,Django就在那里寻找模板。默认启动。
  • django.template.loaders.eggs.Loader - 这个加载器类似 app_directories ,只不过它从Python eggs而不是文件系统中加载模板。 这个加载器默认被禁用;如果你使用eggs来发布你的应用,那么你就需要启用它。 Python eggs可以将Python代码压缩到一个文件中。

    如果两个 模板加载器 都默认启动,那么 Django是怎么使用这两个 模板加载器 的?

    答: Django按照 TEMPLATE_LOADERS 设置中的顺序使用模板加载器。 它逐个使用每个加载器直至找到一个匹配的模板。

 

  8.  扩展模板系统

    1. 创建一个模板库(有许多注意点,请看书,使用时,请看书。)

books/
    __init__.py
    models.py
    templatetags/
        __init__.py (告诉Python这是 一个包含了Python代码的包)
         poll_extras.py (名字随意。一个用来存放你自定义的标签/过滤器定义的文件) views.py 

    需要在模板中写入如下内容:

{% load poll_extras %}

{% load %} 标签检查 INSTALLED_APPS 中的设置,仅允许加载已安装的Django应用程序中的模板库。 这是一个安全特性;它可以让你在一台电脑上部署很多的模板库的代码,而又不用把它们暴露给每一个Django安装。

 

    2. 自定义模板过滤器(skip)

    3. 自定义模板标签(两步:编译和呈现)(Did not try)

      1. 编写编译函数

      2. 编写模板节点

      3. 注册标签

                     --- 跳过了下面的很大一部分 ---

 

Chapter_10 数据模型高级进阶:

  1. 访问外键(Foreign Key)值

    对于用`` ForeignKey`` 来定义的关系来说,在关系的另一端也能反向的追溯回来,只不过由于不对称性的关系而稍有不同。

    通过一个`` publisher`` 对象,直接获取 books ,用 publisher.book_set.all() ,

    实际上,book_set 只是一个 QuerySet(参考第5章的介绍),所以它可以像QuerySet一样,能实现数据过滤和分切,

    属性名称book_set是由模型名称的小写(如book)加_set组成的。

              

  2. 访问多对多值(Many-to-Many Values)

  3. 更改数据库模式(Database Schema)

    Django的数据库层的工作流程.

某些哲学:

  • 如果模型包含一个未曾在数据库里建立的字段,Django会报出错信息。 当你第一次用Django的数据库API请求表中不存在的字段时会导致错误(就是说,它会在运行时出错,而不是编译时)。

  • Django关心数据库表中是否存在未在模型中定义的列。

  • Django关心数据库中是否存在未被模型表示的表格。

    改变模型的模式架构意味着需要按照顺序更改Python代码和数据库。

  4. 添加字段

    本质就是:保持 数据库 和 model 表示的模型一致。

    策略就是先在数据库里加入字段,然后同步Django的模型以包含新字段。

首先,进入开发环境(也就是说,不是在发布环境里):
  1. 在你的模型里添加字段。(models.py)
  2. 运行 manage.py sqlall [yourapp] 来测试模型新的 CREATE TABLE 语句。 注意为新字段的列定义。
  3. 开启你的数据库的交互命令界面(比如, psql 或mysql , 或者可以使用 manage.py dbshell )。 执行ALTER TABLE 语句来添加新列。
  4. 使用Python的manage.py shell,通过导入模型和选中表单(例如, MyModel.objects.all()[:5] )来验证新的字段是否被正确的添加 ,如果一切顺利,所有的语句都不会报错。

然后在你的产品服务器上再实施一遍这些步骤。
  1. 启动数据库的交互界面。
  2. 执行在开发环境步骤中,第三步的ALTER TABLE语句。
  3. 将新的字段加入到模型中。 如果你使用了某种版本控制工具,并且在第一步中,已经提交了你在开发环境上的修改,现在,可以在生产环境中更新你的代码了(例如,如果你使用Subversion,执行svn update。
  4. 重新启动Web server,使修改生效。

  5. 删除字段

删除字段,然后重新启动你的web服务器。

用以下命令从数据库中删除字段:         

ALTER TABLE books_book DROP COLUMN num_pages;

 

  6. 删除多对多关联字段

从你的模型中删除ManyToManyField,然后重启web服务器。

用下面的命令从数据库删除关联表:

DROP TABLE books_book_authors; 

 

  7. 删除模型

从文件中删除你想要删除的模型,然后重启web 服务器models.py

然后用以下命令从数据库中删除表:

DROP TABLE books_book; 

 

当你需要从数据库中删除任何有依赖的表时要注意(也就是任何与表books_book有外键的表 )。 

 

从你的模型中删除ManyToManyField,然后重启web服务器。

用下面的命令从数据库删除关联表:

DROP TABLE books_book_authors;


Chapter_11 通用视图:
  1. 使用通用视图
  2. 对象的通用视图
  3. 扩展通用视图
    制作友好的模板Context
    添加额外的Context
    显示对象的子集
    用函数包装来处理复杂的数据过滤


Chapter_12 部署Django
  END - Django book


——offical Django website——
1. generic_view?? 一个在Django book 前12章没有的东西...
  THIS - 这个是详细介绍generic_view
2. ListView and DetailView. Respectively, those two views abstract the concepts of “display a list of objects” and “display a detail page for a particular type of object.”

3. Django pass argument by URL - THIS
4. Django 的 数据库查询。 THIS & THIS




























END

转载于:https://www.cnblogs.com/kevin922/archive/2013/05/12/3073874.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值