2010年7月22日星期四

web framework - Django

Django

Intro.

http://www.djangoproject.com/
Django框架最初是被开发来用于管理劳伦斯出版集团旗下的一些以新闻内容为主的网站,
其原则是DRY(Don't Repeat Yourself),注重组件的重用性和“可插拔性”以方便敏捷开发。

教程和文档请参考:
http://docs.djangoproject.com/
http://www.djangobook.com/
http://www.ibm.com/developerworks/cn/linux/l-django/
http://blog.ericsk.org/archives/815
下面内容也仅是设法从中整理出若然片段,以供额外的参考。

这里使用的版本是 python 2.6 和 Django 1.2 。


Start

如果不考虑部署仅仅是安装一个开发环境的话,把Django作为一个标准的第三方模块来对待便可以,让"import django"能够成功的载入对应的模块。
执行"django-admin.py startproject mysite"创建一个名为"mysite"的项目目录。
其中有四个文件:
__init__.py 空文件,这里对应"mysite"这个包(可在其他文件中import)
manage.py 命令行工具,提供了若干项目相关的功能
settings.py 该项目的配置文件,可手工编辑
urls.py 用于定义URL的调度,是一个站点接口的组成

下面来在项目中创建一个应用,执行"manage.py startapp polls"。
这样则在项目目录中得到一个名为"polls"的目录,其中有四个文件是:
__init__.py,models.py,tests.py,views.py。
这个包以"import mysite.polls"的方式在项目中使用。

先暂且放开刚才创建的应用回到我们项目的根目录,
通过"manage.py runserver"便可以执行测试服务器。
这样在浏览器中访问"http://127.0.0.1:8000/",
就已经能看到这个Django的应用已经顺利运行了。
并且在测试模式下它会为每次请求重新载入代码,
这样我们就可以随即看到对代码的修改产生的效果。

Django自身的测试代码可以在"tests"目录下中找到。
可作为模块使用的参考,或者复制出来使用。


ORM

首先编辑"settings.py"中"DATABASES"和"INSTALLED_APPS"连接数据库并添加所创建的App,
比如这里的是"sqlite3"和'mysite.polls'。
这个准备工作可以让我们能立即试验接下来要为应用所编写的模型。
执行"manage.py syncdb"如果已安装应用的模型对应的数据库空缺的话,
会执行所需的SQL中的"CREATE"操作。
也提供有其他命令(如"manage.py sql"等)来只生成SQL然后手工执行,
以便于语句本身以及对数据库的调整。

使用对象关系映射模块可以通过声明的方式来使用数据库,
这会为我们自动定义对象的若干方法来方便操作数据并执行对应的SQL语句。
类似的模块,比如ROR中的ActiveRecord实现。


Models

模型声明在app的models.py文件中,例如:
class Category(models.Model):
name = models.CharField(max_length=32)
def __unicode__(self):
return self.name
class Article(models.Model):
title = models.CharField(max_length=64)
published_at = models.DateTimeField('date published')
content = models.TextField()
category = models.ForeignKey(Category)
def __unicode__(self):
return self.title

模型类型派生自django.db.models,并提供若干定义好的Field类型。
对每种类型有若干选项,有的不在调用构造方法时指定也提供了获得默认的值(如null=False,blank,choices)。
在未指定主键的情况下"id = models.AutoField(primary_key=True)"将被自动定义。

模型间的关系用ForeignKey,ManyToManyField以及OneToOneField,
分别用于表示
many-to-one|has_one|belongs_to,
has_and_belongs_to_many 以及
对模型的继承扩展。
虽然ManyToManyField表示的关系是相互的,
也只要在相关联的模型中指定一次。

为使用方便,通常重载模型的__unicode__方法。
还可以通过定义"class Meta"为模型提供定义字段之外的信息,
比如"ordering = ['-published_at']"定义获取对象列表时的默认排序。


QuerySets

在数据库被创建之后,可以执行"manage.py shell"以相互方式使用模型,
首先执行"from mysite.polls.models import Poll, Choice"导入。

除了自己在模型中定义方法,对于CRUD操作Django生成了:

INSERT
from mysite.blog.models import Blog
b = Blog(name='Beatles Blog', tagline='All the latest Beatles news.')
b.save()
save方法调用才会执行对应的SQL语句。

UPDATE
b.name = 'New name'
b.save()
与INSERT操作会自动区分。
ForeignKey也是使用赋值语句,而ManyToManyField用add等方法。

DELETE
e.delete()
也可对list类型操作。

SELECT操作通过类型的objects成员进行,例如
Entry.objects.all()
这是一个惰性类型,可以无多余性能消耗的Python切片运算。
其他提供的方法有 order_by ,filterexclude, get 以及 count ,可以链式使用。
由于参数是以Python中dict类型传入的,会以文本上"field__lookuptype=value"的形式解析。
例如
Entry.objects.filter(pub_date__lte='2006-01-01')
p = Poll.objects.get(pk=1)
关联类型如果非一个单独的属性(如ForeignKey类似CharField使用),
则提供实例的FOO_set成员(用法同模型的objects)进行操作。


MVC

在Django中称为MTV,
原理略。


URL

URL调度在"mysite/urls.py"中指定,修改其中的"urlpatterns"变量。
Django将根据模式匹配的结果调用对应的函数:
urlpatterns = patterns('',
(r'^polls/$', 'mysite.polls.views.index'),
(r'^polls/(?P\d+)/$', 'mysite.polls.views.detail'),
(r'^polls/(?P\d+)/results/$', 'mysite.polls.views.results'),
(r'^polls/(?P\d+)/vote/$', 'mysite.polls.views.vote'),
)
这里访问"/polls/23/"则会调用"detail(request=, poll_id='23')"。
patterns个第一的参数用于指定通用的前缀,
比如这里若是"mysite.polls.views"下面就可省略只写"index"了。
模式的格式是:
(regular expression, Python callback function [, optional dictionary [, optional name]])

也可以把urls.py复制到每个应用的目录下,
然后以类似"(r'^polls/', include('mysite.polls.urls')"的形式引入原urls.py文件中。
这样能够让URL调度的层次变得清晰。


Views

View函数传入一个HttpRequest并返回一个HttpResponse,例如:
from django.http import HttpResponse
def detail(request, poll_id):
return HttpResponse("You're looking at poll %s." % poll_id)
将提供给匹配"/polls/23/"时调用。

HttpRequest的实例通常命名为request,为View函数的第一个参数
if request.method == 'GET':
do_something()
elif request.method == 'POST':
do_something_else()
通过method获得HTTP方法。
为获得HTTP头,
还提供有GET,POST,REQUEST,COOKIES,FILES,META成员按照字典的方式来使用。

HttpResponse的实例被View函数作为返回值,包括其中的文本以及传送的HTTP头:
response = HttpResponse(my_data, mimetype='application/vnd.ms-excel')
response['Content-Disposition'] = 'attachment; filename=foo.xls'
需要时也可返回它的子类如HttpResponseNotFound的实例,另一种类似的写法是:
from django.http import Http404
def detail(request, poll_id):
try:
p = Poll.objects.get(pk=poll_id)
except Poll.DoesNotExist:
raise Http404
return render_to_response('polls/detail.html', {'poll': p})
通过raise抛出错误而没有用return。

代码执行错误是500错误,它们的默认行为是渲染模板目录下404.html或500.html文件。

HttpResponseRedirect则是302重定向。


Template

Django提供了一套自己的模板语言,它是站点前端和后端的交汇处。
虽然塔和Python并不一致,不过也是以这样的限制区分不同的职责。
它的长相如下:
from django.template import Context, loader
from mysite.polls.models import Poll
from django.http import HttpResponse
def index(request):
latest_poll_list = Poll.objects.all().order_by('-pub_date')[:5]
t = loader.get_template('polls/index.html')
c = Context({
'latest_poll_list': latest_poll_list,
})
return HttpResponse(t.render(c))

/polls/index.html
{% if latest_poll_list %}
<ul>
{% for poll in latest_poll_list %}
<li><a href="/polls/{{ poll.id }}/">{{ poll.question }}</a></li>
{% endfor %}
</ul>
{% else %}
<p>No polls are available.</p>
{% endif %
使用前,需要先去 settings.py 指定 TEMPLATE_DIRS 的值。

在模板中使用{{ variable }}嵌入其返回值,可以是变量或方法调用。
Filters以类似{{ bio|truncatewords:30 }}的形式使用,
用以处理变量的值,常用的例如default,length,striptags。
Tags以类似{% tag %}...{% endtag %}的形式使用,
用以生成输出的内用,例如for循环,if and else条件处理,block and extends继承和重写。
Comments以类似{# greeting #}的形式使用,用以书写注释或注释掉临时不需要的代码。

特殊符号默认会被自动转义,以增强安全性。载入其他库以{% load comments %}的形式。

模板的渲染则是调用Template的实例的render方法,并以Context的实例为参数。


Shortcut

在django.shortcuts定义了若干混合的MVC来方便使用的函数。
from django.shortcuts import render_to_response
def my_view(request):
# View code here...
return render_to_response('myapp/index.html', {"foo": "bar"},
mimetype="application/xhtml+xml")

等价于:

from django.http import HttpResponse
from django.template import Context, loader
def my_view(request):
# View code here...
t = loader.get_template('myapp/template.html')
c = Context({'foo': 'bar'})
return HttpResponse(t.render(c),
mimetype="application/xhtml+xml")
这是render_to_response(template[, dictionary][, context_instance][, mimetype])。

还有若干其他的:
redirect(to[, permanent=False], *args, **kwargs)
表示重定向。

get_object_or_404(klass, *args, **kwargs)
from django.shortcuts import get_object_or_404
def my_view(request):
my_object = get_object_or_404(MyModel, pk=1)

等价于

from django.http import Http404
def my_view(request):
try:
my_object = MyModel.objects.get(pk=1)
except MyModel.DoesNotExist:
raise Http404
类似的是get_list_or_404,使用filter()而不是get()。


Next

关于Django的可重用组件以后贴里再说。

----
Django的风格太自己了,在这点上有些别扭。

没有评论: