django book

一、安装配置

1、下载地址:

https://www.djangoproject.com/download/

 

2、安装:

tar zxvf Django-1.6.1.tar.gz && cd Django-1.6.1 && python setup.py install 

 

3、学习URL:

https://docs.djangoproject.com/en/1.6/

http://djangobook.py3k.cn/2.0/

http://django-chinese-docs.readthedocs.org/en/latest/

http://man.chinaunix.net/develop/python/mod_python/mod_python.html

http://www.cnblogs.com/holbrook/archive/2012/03/02/2357343.html#2779364

http://django-china.cn/

http://www.douban.com/group/django/

 

http://www.cnblogs.com/BeginMan/category/458761.html

http://www.cnblogs.com/holbrook/tag/django/default.html?page=2

过滤器:http://blog.csdn.net/chuncaijiayou/article/details/15026931 

 

二、入门

1、新建项目:

可以使用 django-admin.py 脚本来创建项目,该脚本还有更多功能,可以使用 django-admin.py help 来查看,如也可直接建一个应用: django-admin.py startapp appname。(也可以使用 manage.py 完成同样的功能,不同的是,manage.py 设置好了 DJANGO_SETTINGS_MODULE 环境变量,所以在使用其它命令时比较方便,比如 python manage.py sql app1,如果使用 django-admin.py sql app1 的话,就需要先配置环境变量。所以,尽可能使用 manage.py,但如果已经配置好环境变量,尽可能使用 django-admin.py)

django-admin.py startproject project1

即会在当前目录下新建一个名为 project1 的目录,此即可 web 项目名,目录结构为:

└── project1
    ├── manage.py
    └── project1
        ├── __init__.py
        ├── settings.py
        ├── urls.py
        └── wsgi.py

 

2、启动服务:

使用项目根目录下的 manage.py 脚本来启动服务,该脚本的其它功能,可以使用 python manage.py help 来查看。如 python manage.py shell 可以进入配置好 django 环境变量的 python shell 环境,也可以将 DJANGO_SETTINGS_MODULE 环境变量设置在 .bash_profile 文件中,就可以直接使用 python 交互界面了。

python manage.py runserver

这样启动,是以 8000 端口为服务端口,且只能本机访问。如果需要其它机器也可以访问,且自定义端口号,可以使用下面的方法:

python manage.py runserver 0.0.0.0:8000

django 自带的 web 服务器对于开发非常方便,但是不要正式部署的时候还使用它,因为同一时间,该服务器只能可靠地处理一次单个请求,并且没有进行任何类型的安全审计。需要正式部署的时候,还是参考后面在Apache下的配置吧。

 

三、视图和URL配置 

添加视图,在项目目录下新建一个 view.py:

from django.http import HttpResponse

def hellofun(request):
    return HttpResponse("Hello,World!")

 

配置URL,编辑 urls.py ,记得要引入 view.py 模块。

from project1.view import *

urlpatterns = patterns('',
    url(r'^hello/$', hellofun),
)

 

^ 与 $ 分别是正则表达式,如果不加这两个,则可能会匹配 /new/hello/old ,而用了 ^ 和 $ 限定的话,只能匹配 /hello/ ,不多也不少。r 表示是原始字符串,不把它当成转义字符。

这样在浏览器上访问 http://211.152.52.112:8000/hello/  可以看到显示 "Hello,World!" 的信息。但是 http://211.152.52.112:8000/ 会显示找不到了,如果要给此网站根目录的 URL 指定一个页面,则需要使用类似 url(r'^$', hellofun)。

 

通过 runserver 启动服务之后,脚本将于 manage.py 同目录下查找 settings.py 文件,其中有一个 ROOT_URLCONF 的字段指向了 urls.py 。当用户请求某一个URL时,django 根据 ROOT_URLCONF 的设置装备 URLconf ,然后按顺序匹配 URLconf 里的 URLpatterns,直到找到一个匹配的,当找匹配的,就调用关联的 view 函数,并把 HttpRequest 对象作为第一个参数,并返回一个 HttpResponse 对象,django 再将这个 HttpResponse 对象包装成HTTP协议格式返回给用户。

 

如果需要动态配置URL,即传一个参数给处理函数,可以使用下面的方法,并在配置时加上 (),如:

url(r'^now/(\d{1,2})/$',now),

 

则相应的 view.py 里应该如下:

from django.http import HttpResponse
import datetime

def now(request,offset):
    try:
        offset = int(offset)
    except ValueError:
        raise Http404()
    dt = datetime.datetime.now() + datetime.timedelta(hours=offset)
    html="%s hour(s),it will be %s" %(offset,dt)
    return HttpResponse(html)

则请求如 http://211.152.52.112:8000/now/2/ 就会有相应显示。

每个视图函数的第一个参数都是 HttpRequest 对象,offset 是可选参数,是从匹配的 URL 里提取出来的,注意提取出来的值永远是字符串类型,所以可能需要转义(虽然此处在 urlconf 中已经能够保证传入进来的是 int 类型,但是为了松耦合,使此视图代码可以使用在其它的地方,建议统一在此处再进行校验)。

关于 django 调试,一般习惯使用 logging 模块,可以在 settings.py 中配置日志输出格式:

# 配置文志显示的格式
import logging
logging.basicConfig(
        #format = '\033[33m%(asctime)s \033[32m%(filename)s [line:%(lineno)d] \r\n\033[31m%(message)s\033[0m \r\n',  # linux 下的设置
        format = '%(asctime)s %(filename)s [line:%(lineno)d] \nlog: %(message)s \r\n',  # windows 下的设置
datefmt = '%Y-%m-%d %H:%M:%S', )

 

此外,还可以在需要调试的地方使用 assert False 来触发出错页面,查看局部变量和程序语句,不过这种方法我用得很少。这种方式在 debug 模式下有效,即在 settings.py 中设置 DEBUG = True 时,注意!正式上线的项目, DEBUG 一定要设置为 False,以防止暴露一些敏感信息。

 

四、模板

1、模板与上下文

两个大括号包围起来的文字,表示变量,如 {{ person_name }}、{{ ship_date | date:"F j,Y" }}

大括号和百分号包围起来的文字,表示标签,如 if 标签和 for 标签: {% if ordered_warranty %}、{% for item in item_list %}

先看一个 demo:

from django.template import *
# 如果不是通过 python manage.py shell开启解释器交互模式,则需要加上下面两句。另外也可以设置 DJANGO_SETTINGS_MODULE 变量,或直接在 .bash_profile 或 bashrc 文件中添加下面两句:
# export PYTHONPATH=/root/django/project1
# export DJANGO_SETTINGS_MODULE=project1.settings
from django.conf import settings
settings.configure()

str = """{% if sex %}His name is {{name}}.{% else %}Her name is {{name}}.{% endif %}"""
t = Template(str)
c = Context({'sex':1,'name':'tianya'})
print t.render(c)
c = Context({'sex':0,'name':'feng'})
print t.render(c)

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

Django 模板解析非常快捷,大部分解析工作都是在后台通过对简短正则表达式一次性调用来完成,比基于 XML 的模板引擎要快几个数量级。

除了字符串之外,Django 模板系统还可以处理更复杂的数据结构,一般用句点符号 (.) 来实现。如:

str = "pet'name is {{ pet.0.name.upper }}"
t = Template(str)
person = {'name':'tianya','pet':[{'name':'tiger','age':2},{'name':'rabbit','age':1}]}
c = Context(person)
print t.render(c)

通过句点符号不仅可以调用字典结构的键值,还可以调用数据的方法,如上面的 upper,但是由于没有使用圆括号,所以只能调用不需要参数的方法。此外,句点也可以访问列表索引,如上面的 pet.0 。

当模板系统在变量名中遇到句点符号时,会按以下顺序进行查找:

字典键值、属性、方法调用(只能调用不需要参数的方法)、列表索引(不允许使用负数),如果没有查找到,则会显示空字符串,而不会报错。

模板系统不会执行任何以 functionname.alters_data = True 方式进行标记的方法。

 

2、基本模板标签与过滤器

if 标签中,空列表、空元组、空字典、空字符串、零值、特殊对象None、False对象都表示为 False,其它均视为 True。if 标签可以与 and , or , not 组合进行判断,但不允许在同一标签中同时使用 and 和 or,也不支持圆括号来组合比较操作。if 标签必须使用 {% endif %} 来关闭每一个 {% if %} 标签。

ifequal/ifnotequal 标签,用于比较两个值是否相等,必须以 {% endifequal %} 或 {% endifnotequal %} 结束。该标签只能比较字符串类型,整数类型和小数,不能布尔类型和其它复杂类型。

for 标签中我们在一个序列上迭代,且必须以 {% endfor %} 结束,给该标签增加一个 reversed 可以使得此序列被反向迭代,如: {% for item in mylist reversed %} ... {% endfor %}。在执行循环之前一般会用 if 标签来检测一下序列是否为空,如果为空,可能要输出特定内容,由于此操作十分常见,所以 for 标签支持一个可选的 {% empty %} 分句,如:{% for item in mylist reversed %} ...{% empty %}There are no item. {% endfor %}。 for 标签 break 和 continue 功能。在 for 标签里,有一个 forloop 模板变量,它有一些提示循环进度信息的属性,如 forloop.counter 会记录当前循环的执行次数,从1开始,如果习惯从0开始,也可以使用 forloop.counter0;forloop.revconter 表示循环中剩余项的个数,包括当前执行项,所以此值一开始是序列长度,最后一次循环中被置为1,类似的还有 forloop.revcounter0,不包括当前执行项;此外还有 forloop.first 和 forloop.last ,分别表示,如果是否为循环中第一项和是否为循环中最后一项;forloop.parentloop 用于嵌套循环中,指向上一级循环的 forloop 对象的引用。

注释标签:{# This is a comment #},注释的内容不会在模板渲染时输出,但这种注释不能跨多行,如果要实现多行注释,可以使用 comment 标签,如 {% comment %} ... {% endcomment %}

过滤器是通过管道符号的,如果过滤器有参数,则参数跟随冒号之后,且以双引号包含。如 {{ str | truncatewords:"30" }} ,表示显示变量 str 的前30个词。

 

3、模板加载机制

建议将模板文件统一放到一个地方,如在应用文件夹 app1 下新建一个 templates 文件夹,然后配置 setting.py 文件,告知系统模板文件搜索路径:

TEMPLATE_DIRS = (
  os.path.join(os.path.dirname(__file__),'app1/templates').replace('\\','/'),
   )

在 templates 文件夹下新建一个模板文件 curtime.html:

<html><body>It is now {{ curtime }}.</body></html>

编辑 app1/views.py:

#coding:utf-8
"""
from django.shortcuts import render
from django.http import HttpResponse
from django.template.loader import get_template
from django.template import Context
import datetime

def now(request):
    now = datetime.datetime.now()
    t = get_template('curtime.html')
    html = t.render(Context({'curtime':now}))
    return HttpResponse(html)
"""
from django.shortcuts import render_to_response
import datetime

def now(request):
    """
    now = datetime.datetime.now()
    return render_to_response('curtime.html',{'curtime':now})
    """
    # 上面这种方法把模板加载、上下文创建、模板解析和HttpResponse创建工作均在 render_to_response() 的调用中完成了。而 render_to_response() 返回的 HttpResponse 对象正好可以做为 return 值。
    curtime = datetime.datetime.now()
    return render_to_response('curtime.html',locals())
    # locals() 返回的是当前函数执行到该点时,所有局部变量的名称与值的映射字典。比如这里还包括了 request。使用 locals() 注意变量名要起得跟模板文件中的变量名一致。是一种“偷懒”的写法,代码简洁,但是,它包括的变量可能比你想象的要多,比如 request 对象。个人不推荐使用。

在 project1/urls.py 里进行URL配置:

url(r'^admin/curtime$', now),

做好这一切之后,在浏览器中访问  http://211.152.52.112:8000/admin/curtime  即可显示当前时间。 至此,把前台HTML代码完全分离出来了,已基本符合MVC模式。

接下来,解决网页中的重复代码问题,如大致相同的导航栏和底部栏,可以在模板文件中通过 {% include 'header.html' %} 包含模板文件的方法。但是这样有很多不便之处,比如两个网页的 <head>标签中的<title>不一样,那么 head.html 可能需要这样:<html><head><tile> ,而 </title></head> 却需要另外再写出,更优雅的方式是使用模板继承。

先在 templates 目录下建一个基本模板文件 base.html:

<html>
    <head>
        <title>
            {% block title %}{% endblock %}
        </title>
    </head>
    <body>
        <h1>Hello!</h1>
        {% block content %}This is content.{% endblock %}
        {% block footer %}
        <hr>
        <p>Bye!</p>
        {% endblock %}
    </body>
</html>

block 标签用于告诉模板引擎,子模板可以重载这些部分,另block 标签名不能重复。然后建一个模板文件 curtime1.html 继承 base.html :

{% extends "base.html" %}
{% block title %}The current time{% endblock %}
{% block content %}
{{ block.super }}
<p>It is now {{ curtime }}.</p> {% endblock %}

这里注意 extends 标签必须位于最上方,更精确的说,是必须为模板中的第一个模板标记,否则继承将不起作用。如果子模板没有重载所有的 block 标签,则未重载部分将使用基模板中指定的内容。如果要在子模板里访问基模板中块的内容,可以使用 {{ block.super }} 标签

在浏览器中打开 http://211.152.52.112:8000/admin/curtime1 :

一般来说,基础模板中的 {% block %} 标签越多越好,因为子模板不必定义父模板中的所有代码块,也可以使用父模板中的缺省值,钩子自然是越多越好。

 

五、模型

默认 demo 是使用 sqlite3,改成连接MYSQL数据库,需要修改项目的 settings.py 文件:

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.mysql',
        'NAME': 'django',
        'USER': 'root',
        'PASSWORD': '123456',
        'HOST': '211.211.211.211',
        'PORT': '3306',
    }
}

然后进入 python manage.py shell 来测试数据库连接是否正常:

from django.db import connection
cursor = connection.cursor()

 

关于项目和应用:通常的做法是,project 是配置,而 app 是代码,一个 project 包含很多 app 以及对它们的配置,另外 django 本身内建了一些 app,如注释系统和自动管理界面,app 的优点是很容易移植到其它 project 复用。

一个项目,可以不创建应用,比如之前的所有的 demo 就是如此;但如果使用了模型,则必须创建一个 app,模型必须存放于 apps 中。

通过 manage.py 来新建一个应用:

python manage.py startapp app1

目录结构:

├── app1
│   ├── admin.py
│   ├── __init__.py
│   ├── __init__.pyc
│   ├── models.py
│   ├── models.pyc
│   ├── tests.py
│   └── views.py

django 使用MVC模式,首先来修改Model层,编辑 app1/models.py :

from django.db import models

class User(models.Model):
    name = models.CharField(max_length=30)
    password = models.CharField(max_length=30)
    email = models.EmailField()
    def __unicode__(self):
        return '%s %s %s'%(self.name,self.password,self.email)
    class Meta:
        ordering=['-name','password']

 

在工程的 settings.py 中的 INSTALLED_APPS 字段中增加 'app1' 来安装应用,可以使用 django-admin.py validate 命令来检查是否有问题,如果没有问题,则执行:django-admin.py sql app1 可以将 Model 层中的数据结构转成SQL建表语句:

该命令只会输出建表语句,而不会真正去更改数据库,如果想提交至数据库,可使用 django-admin.py syncdb 命令,但是该命令不会将模型的修改或删除同步到数据库。

如果数据库客户端命令在环境变量中,则使用 django-admin.py dbshell 可直接调用相应的数据库客户端登入命令行模式。

然后新建一个 test.py 文件测试一下:

#coding=utf-8
from project1.app1.models import *

#obj1 = User(name='tianya',password='123456',email='tianya@163.com',)
#obj1.save()

#User.objects.create(name='feng',password='123456',email='feng@163.com',)

user_list =User.objects.all().order_by('-name','password')  #从数据库中取出所有对象,列表形式.以name逆序,其次以password排序,若不指定 order_by 方法,则默认以 User类中 class Meta: ordering=['-name','password'] 规则排序。
print user_list     # 默认输出形如:[<User: User object>, <User: User object>] ,可以在 models.py 里数据表类里增加 __unicode__ 方法来改变输出形式

user_list = User.objects.filter(name='tianya')[0:2] # 过滤,相当于SQL中where,然后再
选出其中[0,2]项
User.objects.filter(name='tianya').update(name='TianYa')    # 找到相应对象,更新某一
字段
User.objects.all().update(password='654321')    # 将所有用户密码更新
user_list = User.objects.filter(name__contains='tian')  # 模糊查询,SQL中like
# __contains,包含
# __startswith,以...开头
# __endswith,以...结尾
# __range,两者之间,相当于SQL中between

try:
    str = 'tianya'
    user = User.objects.get(name=str)   # 返回单个对象,如果有多个对象,或者没有返回结
果,都会抛出异常
    print user
    User.objects.get(name='tianya').delete()    # 删除查到的对象
except User.MultipleObjectsReturned:    # 返回多个结果时的异常
    print "Error: user'name = '%s' has multiple result." %str
except User.DoesNotExist:   # 没有返回结果时的异常
    print "Error: user'name = '%s' isn't in the DB." %str

 

 

 

六、Django 站点管理

1、简介

Django自动管理工具是 django.contrib 工具包的一部分,后面我们还会接触到更多 django.contrib 包中的工具。

需要使用django自带的后台管理工具,首先要在 INSTALLED_APPS 里加入 django.contrib.admin,另外还需要加入 'django.contrib.auth','django.contrib.contenttypes'和'django.contrib.sessions' ,django.contrib.admin 需要这三个包(另外还有 'django.contrib.staticfiles' 是页面渲染,即CSS和JS)。确保 MIDDLEWARE_CLASSES 包含 'django.middleware.common.CommonMiddleware'、'django.contrib.sessions.middleware.SessionMiddleware' 和 'django.contrib.auth.middleware.AuthenticationMiddleware' 。

做好上面的操作之后,先 django-admin.py syncdb 来生成后台数据表到数据库,此时会提示你创建一个后台的超级用户帐号,如果跳过,则需要通过 django-admin.py createsuperuser 来创建(只有安装了 django.contrib.auth 应用之后再有些命令),然后配置URL规则,加上 url(r'^admin/', include(admin.site.urls)),然后浏览器中请求 http://127.0.0.1:8000/admin 即可访问到后台了。

 

2、加入自己的模块

在你的应用目录下创建一个 admin.py 文件,如下注册模块:

# coding=utf-8
from django.contrib import admin
from project1.app1.models import *

# Register your models here.
class UserAdmin(admin.ModelAdmin):
    list_display = ('email','id','name','password',)    # 设置依次显示哪些字段
    search_fields = ('id','name')   # 搜索框
    list_filter = ('email',)    # 筛选器
    ordering = ('id',)  # 排序方式
    fields = ('email','name','password')    # 编辑页面依次显示哪些字段

admin.site.register(User,UserAdmin) # 注册 User 模块,以 UserAdmin 为控制方案

 

通过后台修改某个User时,所有的字段都默认要求不为空,如果希望可以为空,可以在 models.py 中设置 blank=True ,如 email = models.EmailField(blank=True),类似的还有 null=True、verbose_name='显示名称'(也可以直接把别名写在第一个参数,如 email = models.EmailField("e-mail",blank=True)

django 自带的后台管理平台中,如果要使用本地语言,可以在 MIDDLEWARE_CLASSES 中加上(但必须位于 'django.contrib.sessions.middleware.SessionMiddleware', 之后):

'django.middleware.locale.LocaleMiddleware',

 

3、自定义 admin

在应用的目录下建立一个名为 templates 的文件夹来存放我们自己定义的模板文件。在 setting.py 里增加以下代码,告知模板载入器我们自定义的模板目录(manager 是应用名):

TEMPLATE_DIRS = (
        os.path.join(os.path.dirname(__file__),'manager/templates').replace('\\','/'),
        )

 

然后将jdango默认模板 django/contrib/admin/templates 中相应模板复制到自定义模板目录下,如 django/contrib/admin/templates/admin/base_site.html 复制到 manager/templates/admin/base_site.html ,然后编辑它:

{% extends "admin/base.html" %}
{% load i18n %}

{% block title %}{{ title }} | {% trans '宠物大战' %}{% endblock %}

{% block branding %}
<h1 id="site-name">{% trans '宠物大战管理后台' %}</h1>
{% endblock %}

{% block nav-global %}{% endblock %}

即可把默认模板的标题改成自己想要的。想要修改默认模板的内容,就重复上面的动作,复制相应模板文件到自定义模板目录,改写即可,既然仍然要copy-paste,但仍然是可接受的。

当要重定义某特定 model 相关的模板文件时,如 change_form.html 等,假如应用名为 PUser,则将 change_form.html 复制到 templates/admin/manager/puser/ 目录下修改即可(注意!!!这里使用应用名和model名的全小写形式!)。总结一下,模板搜索顺序是:

# 必须为全小写形式
templates/admin/app_name/model_name/change_form.html 
templates/admin/app_name/change_form.html 
templates/admin/change_form.html 

除此之外,还可以在 admin.py 文件里编辑 class PUserAdmin:

class PUserAdmin(admin.ModelAdmin):
     change_form_template = "admin/my/puser/change_form.html"

其它类似的还有 change_list_template、delete_confirmation_template、object_history_template

关于模板载入器,可以查看 /django/template/loaders/app_directories.py 里的 load_template_source 方法,以及 django/contrib/admin/sites.py 中的 urls 配置。

django/contrib/admin/__init__.py 文件的 autodiscover() 方法迭代设置 INSTALLED_APPS 中的每个应用程序,并查找名为 admin.py 的文件

备注:我曾经遇到问题,为了方便重写模板,把  django/contrib/admin/ 做了名为 admin 的软链接放在应用目录下,结果在重新启动服务后,无论如何都无法在后台显示 admin.py 里注册的数据了,把 admin 软链接改名成 admin_source 后,(必须要再重启服务),就正常了。

 

 

 

第十二章  部署 Django

修改 setting.py 文件中的 DEBUG 和 TEMPLATE_DEBUG 字段值为 False,然后将 ALLOWED_HOSTS 字段设为 ['*'],在模板文件夹中新建 404.html 和 500.html 来替代之前在DEBUG模式下django提供的相应错误页面。

http://dist.modpython.org/dist/ 下载 mod_python 包,解压进入目录,执行:

./configure --with-apxs=/usr/local/apache2/bin/apxs --with-python=/usr/bin/python2.6 && make -j8 && make install

 

会在 /usr/local/apache/modules/ 目录下生成 mod_python.so 文件。

 

从 http://code.google.com/p/modwsgi/ 下载 mod_wsgi ,解压进入目录,执行:

./configure --with-apxs=/usr/local/apache2/bin/apxs --with-python=/usr/bin/python2.6 && make -j8 && make install

会在 /usr/local/apache/modules/ 目录下生成 mod_wsgi.so 文件。

在 /usr/local/apache2/htdocs/ 目录下新建一个 django 项目,django-admin.py startproject project2,在项目目录下会生动生成一个 wsgi.py 文件:

 

import os

os.environ.setdefault("DJANGO_SETTINGS_MODULE", "project2.settings")

from django.core.wsgi import get_wsgi_application
application = get_wsgi_application()

 

在文件里增加两行(否则当有多个项目时可能会有问题,所以加上比较好):

import sys
sys.path.append('/usr/local/apache2/htdocs/project2')

配置 apache,编辑 httpd.conf :

LoadModule wsgi_module modules/mod_wsgi.so
<VirtualHost *:80>
    WSGIScriptAlias /project2 "/usr/local/apache2/htdocs/project2/project2/wsgi.py"
    <Directory "/usr/local/apache2/htdocs/project2/project2">
        Order Deny,Allow
        Allow from all
    </Directory>
</VirtualHost>

 

 

 

 

 

 

 

django 调试:

使用 logging 模块输出日志到终端中:

import logging
logging.warning("this is error")

logging 日志模块的错误级别有 INFO,DEBUG,WARNING,ERROR,CRITICAL,默认级别是 WARING。如果需要配置 logging 默认配置,如默认级别,输出到文件等,可以编辑 setting.py:

logging.basicConfig(
    level = logging.DEBUG,
    format = '\033[33m%(asctime)s \033[32m%(filename)s [line:%(lineno)d]\r\n\033[31m%(message)s\033[0m\r\n',
    datefmt = '%Y-%m-%d %H:%M:%S',
    #filename = '/tmp/django.log',
    #filemode = 'w'
)

 

 

 

 

 

 

posted @ 2014-01-26 17:43  轻典  阅读(1247)  评论(0编辑  收藏  举报