您的位置:首页 > 编程语言 > Go语言

django系统学习笔记

2012-05-24 17:40 435 查看
转自:http://hi.baidu.com/derris/item/7ca6013e330563fede2221ab

2010-02-07 00:12

django系统学习笔记~~(1)hello world

强烈推荐 djangoz教程 中文版 http://djangobook.py3k.cn/2.0/
按照手册的指导(http://www.djangobook.com/en/2.0/chapter02/) 安装python和django

python :下载2.6就可以:http://www.python.org/download/ 直接下载windows版本。

django:下载1.1就可以:http://www.djangoproject.com/download/. 然后运行:python setup.py install

把python目录下面的:Lib\site-packages\django\bin加入到路径里面。

创建一个django的web框架,生成一堆文件。

django-admin.py startproject mysite

mysite/

__init__.py

manage.py

settings.py

urls.py

进入到mysite目录中,运行web测试服务器:

python manage.py runserver

提示在 http://127.0.0.1:8000/ 运行啦,可以访问一下看看。系统自动提示:It worked!

现在可以添加一些内容了:创建一个空的文件,起名为:views.py,里面加入内容:

from django.http import HttpResponse

def hello(request):

return HttpResponse("Hello mysite!")


更改urls.py的内容为:

from django.conf.urls.defaults import *

from mysite.views import hello


urlpatterns = patterns('',

('^$', hello)

)


#正则表达式参考:http://hi.baidu.com/derris/blog/item/fe5dea17ef90dd02c83d6df1.html

再访问:http://127.0.0.1:8000/ ,内容变了~~

当浏览器访问: http://127.0.0.1:8000/时,django访问settings文件.

当启动django的web服务器:python manage.py runserver时,django在manage.py所在的目录里面找到文件:settings.py。这个文件包括了所有项目需要的配置文件TEMPLATE_DIRS, DATABASE_NAME,等等。最重要的设置就是ROOT_URLCONF.(ROOT_URLCONF = 'mysite.urls')他告诉django那个模块用作网站文件。ROOT_URLCONF = 'mysite.urls'指向的就是mysite/urls.py文件。再按照urls.py里面的对应正则表达式找到对应的方法处理。具体步骤如下:

1 Django在网站端口得到一个请求/hello/。

2 Django根据ROOT_URLCONF的指向,找到配置文件。

3 Django搜索符合/hello/的patter选项。

4 找到符合选项对应的处理方法,运行该方法。

5 该方法返回HttpResponse。

6 Django将HttpResponse转换为HTTP文档发给请求方。

django系统学习笔记 ~~(2) 动态参数

http://hi.baidu.com/derris/blog/item/dceec6ddbaac2ae477c638c0.html

django系统学习笔记~~(2)动态参数

(1) http://hi.baidu.com/derris/blog/item/f6185a31ed2c1212eac4af05.html
(3) http://hi.baidu.com/derris/blog/item/635cca5007857d571138c2f2.html
显示动态变化的内容:

更改 views.py 文件:

from django.http import HttpResponse

import datetime


def hello(request):

return HttpResponse("Hello world")


def current_datetime(request):

now = datetime.datetime.now()

html = "<html><body>It is now %s.</body></html>" % now

return HttpResponse(html)


urls.py 文件如下:

from django.conf.urls.defaults import *

from mysite.views import hello, current_datetime

urlpatterns = patterns('',

('^hello/$', hello),

('^time/$', current_datetime),

)


再访问 http://127.0.0.1:8000/time/,就会显示当前的时间。
假设我们想根据1个参数返回一个时差,比如东京和北京的时间就不同。比如我们这样

urlpatterns = patterns('',

('^time/$', current_datetime),

('^time/plus/1/$', one_hour_ahead),

('^time/plus/2/$', two_hours_ahead),

('^time/plus/3/$', three_hours_ahead),

('^time/plus/4/$', four_hours_ahead),

)

太多了,最好有个参数。

urls.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),

)

更改 views.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)

def hello(request):

return HttpResponse("Hello mysite!")


def current_datetime(request):

now = datetime.datetime.now()

html = "<html><body>It is now %s.</body></html>" % now

return HttpResponse(html)



访问:http://127.0.0.1:8000/time/plus/4/ 发现可以按照接收的参数进行动态的调整了。

2010-02-19 14:53

django系统学习笔记~~(3)模板

(2)http://hi.baidu.com/derris/blog/item/dceec6ddbaac2ae477c638c0.html

(4)http://hi.baidu.com/derris/blog/item/8cb9a635bf795b1a91ef39ef.html

每次更改显示的内容,就需要重新编码,最好通过模板将内容和表现分开,这样可以有人专门做程序,有人专门做设计。

在当前目录里面增加一个文件:current_datetime.html,内容如下:

<html>

<body>It is now {{ current_date }}. and i can change the content freely.

<p> 随便加什么乱七八糟的都行</p>

</body>

</html>


{{ current_date }}是一个等待传递过来内容的变量。还有可以用的语句后面再说。

更改view.py如下:

from django.template.loader import get_template

from django.template import Context

from django.http import 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)


def hello(request):

return HttpResponse("Hello mysite!")


from django.shortcuts import render_to_response

def current_datetime(request):

now = datetime.datetime.now()

return render_to_response('current_datetime.html', {'current_date': now})


再更改setting.py中的TEMPLATE_DIRS项目,指定模板所在的目录。我们在根目录下,就可以改为:

TEMPLATE_DIRS = (

unicode(os.path.dirname(__file__), 'gbk'),

)


unicode的问题是因为我把他放在中文目录下面了,必须要转一下,否则utf8的编码解码不了中文

然后访问:http://127.0.0.1:8000/time/ 就可以显示了~~

render_to_response是快捷的实现方法,也相当于:

def current_datetime(request):

now = datetime.datetime.now()

t = get_template('current_datetime.html')

html = t.render(Context({'current_date': now}))

return HttpResponse(html)

比这个写法简单多了,还有一个简单的代替上下文参数的方法,就是用locals(),自动将当前本地范围变量封装为上下文参数。下面locals就代替now了,不过一定要记住,变量名字和上下文字典的主键要一致。还有locals也会包含参数request,所以会造成一定的数据膨胀~

def current_datetime(request):

current_date = datetime.datetime.now()

return render_to_response('current_datetime.html', locals())

关于模板的一些说明:

模板文件可以使用 {% include 'nav.html' %} 来包含一些通用的东东。

创建一个文件:base.html内容如下:

<html><head><title>{% block title %}{% endblock %}</title></head>

<body>

<h1>My test base template</h1>

{% block content %}{% endblock %}

{% block footer %}

<hr>

<p>Thanks for visiting my site.</p>

{% endblock %}

</body></html>


还可以用 {% block name %} {% endblock %} 在定义基类的块,通过{% extends "base.html" %} 来继承 base.html 的内容,然后系统会根据子网页的数据内容来替换base.html中定义的块,达到继承扩展的效果。:) 如果子网页对于某些块没有定义,那么会沿用base.html中的内容。子模板如下:

{% extends "base.html" %}

{% block title %}The current time{% endblock %}

{% block content %}

<p>It is now {{ current_date }}.</p>

{% endblock %}

模板中尽量不要包括什么逻辑,逻辑应该做到外面去,主要模板的语句是

{{变量、类、方法都可以}}

{% 语句 %} :if , else, endif, for, empty, endfor, ifequal, else, endifequal, comment, endcomment

{{变量}}:forloop.counter(当前是第几个), forloop.first(是否是第一个), forloop.revcounter(还剩几个), forloop.revcounter0, forloop.last(是否是最后一个), forloop.parentloop,

{# line comment #}

过滤器:{{ my_list|first|upper }} mylist里面的第一个,大写

{{ astring | truncatewords:"30" }} 还可以给方法带参数,范围前30个字符。

{{ adate | date:"F j, Y"}} 给日期指定格式。

详细教程地址:http://www.djangobook.com/en/2.0/chapter04/

2010-02-19 21:47

django系统学习笔记~~(4)模型和数据操作

(3)http://hi.baidu.com/derris/blog/item/635cca5007857d571138c2f2.html

(5)http://hi.baidu.com/derris/blog/item/80e8eb956b0b1240d0135e4b.html

mvc或者说是mtv模式,主要为了让数据模型、业务逻辑、表现逻辑尽量的分离,实现松散耦合。

这次学习是一个新的例子,在以前的mysite目录里面增加一个books的应用,进入mysite目录,执行:

python manage.py startapp books

创建了一个目录,books,里面有一些空文件:)

books/

__init__.py

models.py

tests.py

views.py

首先编辑models.py

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

class Meta:

ordering = ['name']

class Author(models.Model):

first_name = models.CharField(max_length=30)

last_name = models.CharField(max_length=40)

email = models.EmailField()

def __unicode__(self):

return u'%s %s' % (self.first_name, self.last_name)

class Book(models.Model):

title = models.CharField(max_length=100)

authors = models.ManyToManyField(Author)

publisher = models.ForeignKey(Publisher)

publication_date = models.DateField()

def __unicode__(self):

return self.title



再编辑mysite下面的文件:settings.py:

找到INSTALLED_APPS 这里,更改为:

INSTALLED_APPS = (

# 'django.contrib.auth',

# 'django.contrib.contenttypes',

# 'django.contrib.sessions',

# 'django.contrib.sites',

'mysite.books',

)


在mysite目录下运行:python manage.py validate

0 errors found 就可以了。

下面要配置数据库了,在setting.py文件里面。找到对应的地方更改如下:

DATABASE_ENGINE = 'sqlite3'

DATABASE_NAME = 'c:/mydata.db' # change it free


测试一下:运行:

python manage.py shell

>>>from django.db import connection

>>>cursor = connection.cursor()


没有错误就ok了,否则根据错误提示调试一下

运行python manage.py syncdb

将模型同步到数据库中。

Creating table books_publisher

Creating table books_author

Creating table books_book

Installing index for books.Book model

生成的数据注意都是小写,引用的时候要注意啊。。。

常用语句说明:首先准备数据。

>>> from books.models import Publisher

插入数据

>>> p1 = Publisher.objects.create(name='Apress',

... address='2855 Telegraph Avenue',

... city='Berkeley', state_province='CA', country='U.S.A.',

... website='http://www.apress.com/')

>>> p1.save()

更新数据

>>> p1.name = 'Apress Publishing'

>>> p1.save()

>>> Publisher.objects.all().update(country='USA')

查找/选择数据

>>> Publisher.objects.filter(name='Apress')

>>> Publisher.objects.filter(country="U.S.A.", state_province="CA") # and 双条件

>>> from django.db.models import Q

>>> Publisher.objects.filter(Q(name='Apress') | Q(name='newone')) # or 条件

>>> Publisher.objects.filter(name__contains="press") # 模糊查找,相当于name like '%press%'

排序数据,类似的还有加下双划线icontains (不区分大小写的like), startswith、endswith、range (SQL
BETWEEN语句等).

>>> Publisher.objects.order_by("name") # 到排序用-name

综合

>>> Publisher.objects.filter(country="U.S.A.").order_by("-name")

删除数据

>>> p = Publisher.objects.get(name="O'Reilly")

>>> p.delete()

>>> Publisher.objects.filter(country='USA').delete()

执行自定义SQL

在自定义 model 方法和模块级方法里,你可以自由的执行自定义SQL语句. 对象 django.db.connection 表示当前的数据库连接. 调用 connection.cursor() 得到一个游标对象. 然后调用 cursor.execute(sql, [params])``以执行 SQL 语句, 使用 ``cursor.fetchone() 或 cursor.fetchall() 得到结果集. 下面是一个例子:

from django.db import connection

cursor = connection.cursor()

cursor.execute("SELECT foo FROM bar WHERE baz = %s", [self.baz])

row = cursor.fetchone()

如果你的SQL语句改变了数据库中的数据 -- 比如你使用了 DELETE 或 UPDATE 语句. 你需要调用 connection.commit() 来使你的修改生效. 例子:

from django.db import connection

cursor = connection.cursor()

cursor.execute("DELETE FROM bar WHERE baz = %s", [self.baz])

connection.commit()

connection 和 cursor 直接调用 Python DB-API. 如果你对 Python DB-API 不熟悉, 注意``cursor.execute()`` 中的SQL语句使用了占位符 "%s", 这比直接在 SQL语句中指定参数要灵活. 如果你使用此技术, 后台的数据库会自动的在需要时用引号引并转义你的参数.

最后提醒一下: 如果你想要的仅仅是一个自定义的 WHERE 子句,你可以在标准查询 API 中通过指定 where, tables 和 params 参数来完成同样的功能.参阅 其它查询选项.

在dos下运行:python manage.py sqlall books

会列出所有的sql语句。

注意:

CREATE TABLE "books_book_authors" (

"id" integer NOT NULL PRIMARY KEY,

"book_id" integer NOT NULL REFERENCES "books_book" ("id"),

"author_id" integer NOT NULL REFERENCES "books_author" ("id"),

UNIQUE ("book_id", "author_id")

)

; # 这个是因为多对多产生的一个中间表。

CREATE INDEX "books_book_publisher_id" ON "books_book" ("publisher_id");

外键产生一个索引,对应publisher的id。book中publisher字段存的是一个id值。

将常用的业务逻辑写到特定的模型中也是一个比较不错的封装方法:

from django.db import models

class DahlBookManager(models.Manager):

def get_query_set(self):

return super(DahlBookManager, self).get_query_set().filter(author='Roald Dahl')

class Book(models.Model):

title = models.CharField(max_length=100)

author = models.CharField(max_length=50)

# ...

objects = models.Manager() # The default manager.

dahl_objects = DahlBookManager() # The Dahl-specific manager.

django系统学习笔记~~(5)admin系统管理 数据和用户

(4)http://hi.baidu.com/derris/blog/item/8cb9a635bf795b1a91ef39ef.html

(6)http://hi.baidu.com/derris/blog/item/e8ee10fafd711915a9d31185.html

通过admin模块来进行数据的后台管理和用户控制。

进入mysite目录,编辑settings.py文件:找到

INSTALLED_APPS 编辑为:

INSTALLED_APPS = (

'django.contrib.admin',

'django.contrib.auth',

'django.contrib.contenttypes',

'django.contrib.sessions',

'django.contrib.sites',

'mysite.books',

)


如果需要本地化为当地语言,增加'django.middleware.locale.LocaleMiddleware',到MIDDLEWARE_CLASSES的设置里面,确保增加在'django.contrib.sessions.middleware.SessionMiddleware'后面就可以了。

编辑urls.py文件为如下内容:

from django.conf.urls.defaults import *

from mysite.views import hello, current_datetime, hours_ahead

from django.contrib import admin

admin.autodiscover()


urlpatterns = patterns('',

('^$', hello),

('^hello/$', hello),

('^time/$', current_datetime),

(r'^time/plus/(\d{1,2})/$', hours_ahead),

(r'^admin/', include(admin.site.urls)),

)

搞定。在dos下运行python manage.py syncdb,同步数据库以后访问:http://127.0.0.1:8000/admin/可以用设置的用户和密码登录了。

如果没有选择创建系统管理员账户,可以用python manage.py createsuperuser命令创建用户。

目前因为没有指定admin管理的内容,所以admin登录进去只能进行系统的用户和组设置。下面把我们的books系统表增加到里面:

在目录mysite/books里面增加admin.py,内容为:

from django.contrib import admin

from mysite.books.models import Publisher, Author, Book


admin.site.register(Publisher)

admin.site.register(Author)

admin.site.register(Book)


现在可以对这3个表的所有信息进行编辑了,所有的字段默认都不允许为空。

下面考虑一些字段的具体选项,比如那些字段可以为空,以及显示格式等。关于字段可空的选项主要在模型后面增加选项,因为django默认所有的数据库都不可以为null。

对于字符类型来说增加blank=True就可以了,django会自动插入None作为数据库空值。对于数字和日期等,必须允许数据库为null。这样需要设置选项为:blank=True, null=True。

如果在模型中增加了null=True的选项,django不会自动同步到数据库中,需要手工进行设置

>>> import sqlite3

>>> conn = sqlite3.connect('c:\\mydata.db')

>>> cur = conn.cursor()

>>> cur.execute("drop TABLE books_book;")

然后再同步数据库

python manage.py syncdb

最好全部删除了数据库文件,重新执行,否则有重复报错,不过也无所谓了。最多有些垃圾数据。

sqlite3的具体sql文档见:http://www.sqlite.org/lang.html

列出所有的sqlite3中的表:

>>> cur.execute("SELECT name FROM sqlite_master where type='table'")

>>> for a in cur :

... print a

--------------------- 如果需要更新列,sqlite3不支持删除列的。只能备份数据后,再搞进去

BEGIN TRANSACTION;

CREATE TEMPORARY TABLE t1_backup(a,b);

INSERT INTO t1_backup SELECT a,b FROM t1;

DROP TABLE t1;

CREATE TABLE t1(a);

INSERT INTO t1 SELECT a FROM t1_backup;

DROP TABLE t1_backup;

COMMIT;

-----------------------------------

在amdin对表记录进行列表选择的时候,默认列出的是__unicode__定义的内容,如果想对字段进行详细设置,更改admin.py如下:

from django.contrib import admin

from mysite.books.models import Publisher, Author, Book


class AuthorAdmin(admin.ModelAdmin):

list_display = ('first_name', 'last_name', 'email') # 设置选择某表列出的内容

search_fields = ('first_name','last_name', 'email') # 设置是否有搜索框,搜索的内容包含哪些字段。


class BookAdmin(admin.ModelAdmin):

list_display = ('title','publisher', 'publication_date')

ordering = ('-publication_date',) # 显示的排序字段

fields = ('title', 'authors', 'publisher', 'publication_date') # 列出可以编辑的字段

filter_horizontal = ('authors',) # 水平显示一个可以选择的列表框

raw_id_fields = ('publisher',) # 录入出版商对应的号码。


admin.site.register(Publisher)

admin.site.register(Author, AuthorAdmin)

admin.site.register(Book, BookAdmin)


可以看到列出的格式和内容都发生了变化。

-------------------------------------------------------------------------------------------------常用查询

生成的所有表中自动追加一个id字段

CREATE TABLE "books_publisher" ( "id" serial NOT NULL PRIMARY KEY,……

ManyToMany的字段将不会再表中生成,而是自动生成一个中间表,储存2个表的主键对应。

publication_date = models.DateField(blank=True, null=True, verbose_name='显示标签名' )

在类中定义列表的显示内容。

def __unicode__(self):

return u'%s %s' % (self.first_name, self.last_name)

from django.contrib import admin

from mysite.books.models import Publisher, Author, Book

class xxxAdmin(admin.ModelAdmin):

list_display = ('first_name', 'last_name', 'email')

search_fields = ('first_name', 'last_name')

list_filter = (' first_name ',) 快速选择数据

date_hierarchy = 'publication_date'

ordering = ('-publication_date',)

fields = ('title', 'authors', 'publisher', 'publication_date') 字段显示顺序

filter_horizontal = ('authors',) 多对多选择用。filter_vertical

raw_id_fields = ('publisher',) 外键选择不用太慢把全部数据加载到下拉列表中,

admin.site.register(Author, AuthorAdmin)

django系统学习笔记~~(6)表单

(5)http://hi.baidu.com/derris/blog/item/80e8eb956b0b1240d0135e4b.html

(7)http://hi.baidu.com/derris/blog/item/8883efbf1d0c470118d81f10.html

先显示一下http的访问格式。在mysite目录里面的views.py最后增加一段显示代码

def display_meta(request):

html = []

for i in [ 'GET', 'REQUEST', 'POST', 'COOKIES', 'FILES', 'META']:

html.append('<tr><td>------%s---------</td></tr>' % i)

values = eval("request.%s" % i)

if not isinstance(values, str):

valuex = values.items()

for k, v in valuex:

html.append('<tr><td>%s</td><td>%s</td></tr>' % (k, v))

return HttpResponse('<table>%s</table>' % '\n'.join(html))


在urls.py中,编辑如下:

from django.conf.urls.defaults import *

from mysite.views import hello, current_datetime, hours_ahead, display_meta

from django.contrib import admin

admin.autodiscover()


urlpatterns = patterns('',

('^$', hello),

('^hello/$', hello),

('^time/$', current_datetime),

(r'^time/plus/(\d{1,2})/$', hours_ahead),

(r'^admin/', include(admin.site.urls)),

(r'^look/$', display_meta),

)

然后访问:
http://127.0.0.1:8000/look/ 看到列出了一堆。。。。

下面开始使用form了,在mysite下面建立一个search_form.html文件,内容如下:

<html>

<head>

<title>Search</title>

</head>

<body>

<form action="/look/" method="get">

<input type="text" name="q">

<input type="submit" value="Search">

</form>

</body>

</html>


urls.py变更如下:

from django.conf.urls.defaults import *

from mysite.views import hello, current_datetime, hours_ahead, display_meta

from django.contrib import admin

from mysite import views

admin.autodiscover()


urlpatterns = patterns('',

('^$', hello),

('^hello/$', hello),

('^time/$', current_datetime),

(r'^time/plus/(\d{1,2})/$', hours_ahead),

(r'^admin/', include(admin.site.urls)),

(r'^look/$', display_meta),

(r'^look/$', display_meta),

(r'^search_form/$', views.search_form),

)

mysite的views.py中增加对应的处理

def search_form(request):

return render_to_response('search_form.html')



然后访问:http://127.0.0.1:8000/search_form/ 录入一下查找,又看到列出了一堆,其中get和REQUEST下面有一列,变量q,内容就是你输入的数据...如果把search_form.html里面的form提交方法更改为post,那么就在post和REQUEST下面出现你提交的数据。

数据看明白了,把search_form.html里面表单的form提交对象更改成search,继续做例子

<form action="/search/" method="get">

建立一个搜索结果的反馈模板文件:search_results.html

<p>You searched for: <strong>{{ query }}</strong></p>

{% if books %}

<p>Found {{ books|length }} book{{ books|pluralize }}.</p>

<ul>

{% for book in books %}

<li>{{ book.title }}</li>

{% endfor %}

</ul>

{% else %}

<p>No books matched your search criteria.</p>

{% endif %}

注意:books|pluralize 会根据books大于1个自动加一个s,变成复数:)

urls.py中增加对应的处理

(r'^search/$', views.search),

views.py中增加对应的方法:

from mysite.books.models import Book

def search(request):

if 'q' in request.GET and request.GET['q']:

q = request.GET['q']

books = Book.objects.filter(title__icontains=q)

return render_to_response('search_results.html',

{'books': books, 'query': q})

else:

return HttpResponse('Please submit a search term.')


现在,可以访问http://127.0.0.1:8000/search_form/ 输入书名就可以查询了。

因为如果输入空提交我们是直接return HttpResponse('Please submit a search term.'),造成需要回退才可以再次输入,为了提高服务质量,最好能够在同一个页面里面提示,可以直接再次查询。这样把最后一句return HttpResponse的改为:

return render_to_response('search_form.html', {'error': True})

再更新一下'search_form.html'文件

<html>

<head>

<title>Search</title>

</head>

<body>

{% if error %}

<p style="color: red;">Please submit a search term.</p>

{% endif %}

<form action="/search/" method="get">

<input type="text" name="q">

<input type="submit" value="Search">

</form>

</body>

</html>



现在发现search_form已经不需要访问了。直接访问search只是多一个空提示,更改程序如下,search_form方法就可以完全淘汰了(search_form.html还要留着哈)。

def search(request):

error = False

if 'q' in request.GET:

q = request.GET['q']

if not q:

error = True

else:

books = Book.objects.filter(title__icontains=q)

return render_to_response('search_results.html',

{'books': books, 'query': q})

return render_to_response('search_form.html',

{'error': error})


error 目前只是一个字符串的变量,可以更改为列表,一次提示出来所有的错误。

按照上面的方式,如果字段非常多,需要很多的判断和错误提示,非常麻烦。django提供我们一些更好的模板来处理他~~

先做一个简单表单,包括3个字段:标题,内容,Email。在mysite目录里面创建一个目录contact,建立一个forms.py文件:

from django import forms

class ContactForm(forms.Form):

subject = forms.CharField(max_length=100)

email = forms.EmailField(required=False, label='Your e-mail address')

message = forms.CharField(widget=forms.Textarea)

def clean_message(self):

message = self.cleaned_data['message']

num_words = len(message.split())

if num_words < 4:

raise forms.ValidationError("Not enough words!")

return message



Django系统自动查找clean_开头,并且后面的名字是其中字段的方法,在系统的验证完后作为用户验证运行。forms.ValidationError的内容自动加载到字段错误中。

在mysite目录的views.py文件中增加:

from mysite.contact.forms import ContactForm

def contact(request):

if request.method == 'POST':

form = ContactForm(request.POST)

if form.is_valid():

cd = form.cleaned_data

send_mail(

cd['subject'],

cd['message'],

cd.get('email', 'noreply@example.com'),

['siteowner@example.com'],

)

return HttpResponse("thanks visit mysite!")

else:

form = ContactForm(initial={'subject': 'I love your site!'})

return render_to_response('contact_form.html', {'form': form})

在mysite里面创建一个模板文件:contact_form.html

<html>

<head>

<title>Contact us</title>

</head>

<body>

<h1>Contact us</h1>

{% if form.errors %}

<p style="color: red;">

Please correct the error{{ form.errors|pluralize }} below.

</p>

{% endif %}

<form action="" method="post">

<table>

{{ form.as_table }}

</table>

<input type="submit" value="Submit">

</form>

</body>

</html>


在urls.py文件里面增加一行引用:

(r'^contact/$', views.contact),


在contact目录里面需要增加一个__init__.py的空文件,不然提示import错误。

send_mail(subject, message, from_email, recipient_list,
fail_silently=False, auth_user=None, auth_password=None,
connection=None)

如果要成功发送email,需要在setting.py里面增加如下设置。

EMAIL_HOST = "smtp.163.com"

EMAIL_HOST_PASSWORD = "xxxxxxx"

EMAIL_HOST_USER = "yourname"

EMAIL_PORT = "25"


关于form类的理解,自动生成各种需要的语法:

>>> from contact.forms import ContactForm

>>> f = ContactForm()

>>> print f

<tr><th><label for="id_subject">Subject:</label></th><td><input type="text" name="subject" id="id_subject" /></td></tr>

<tr><th><label for="id_email">Email:</label></th><td><input type="text" name="email" id="id_email" /></td></tr>

<tr><th><label for="id_message">Message:</label></th><td><input type="text" name="message" id="id_message" /></td></tr>

>>> print f.as_ul()<li><label for="id_subject">Subject:</label> <input type="text" name="subject" id="id_subject" /></li><li><label for="id_email">Email:</label> <input type="text" name="email" id="id_email" /></li><li><label for="id_message">Message:</label>
<input type="text" name="message" id="id_message" /></li>>>> print f.as_p()<p><label for="id_subject">Subject:</label> <input type="text" name="subject" id="id_subject" /></p><p><label for="id_email">Email:</label> <input type="text" name="email" id="id_email"
/></p><p><label for="id_message">Message:</label> <input type="text" name="message" id="id_message" /></p>
>>> print f['subject']

<input type="text" name="subject" id="id_subject" />

>>> print f['message']

<input type="text" name="message" id="id_message" />

>>> f = ContactForm({'subject': 'Hello', 'email': 'adrian@example.com', 'message': 'Nice site!'})
一旦你关联上数据以后,就创建了一个基础form,判断:

>>> f.is_boundTrue
检查合法性:

>>> f.is_valid()True
如果有不和逻辑的,比如非空字段没有填写等,is_valid()就返回False,可以通过具体引用返回错误。

>>> f = ContactForm({'subject': 'Hello', 'message': ''})

>>> f['message'].errors

[u'This field is required.']

>>> f['subject'].errors

[]

>>> f['email'].errors

[]

>>> f.errors

{'message': [u'This field is required.']}

>>> f.cleaned_data

{‘message’: u’Nice site!’, ‘email’: u’adrian@example.com’, ‘subject’: u’Hello’}

cleaned_data用于将文本转换成python对应的具体数据类型,如数字、文本、日期等。

可以用css方便的对自动生成的html进行格式定义,只要根据生成的源代码进行修饰就可以了~!

详见:http://www.djangobook.com/en/2.0/chapter07/

django系统学习笔记~~(7)高级视图和URL配置

(6)http://hi.baidu.com/derris/blog/item/e8ee10fafd711915a9d31185.html

(8)http://hi.baidu.com/derris/blog/item/f490f213dc314f095baf53cc.html

urls.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),

)

有一种相对简洁的写法,这样起码不用再写2边:

from mysite import views

urlpatterns = patterns('',

(r'^hello/$', views.hello),

(r'^time/$', views.current_datetime),

(r'^time/plus/(d{1,2})/$', views.hours_ahead),

)

甚至不用模块导入直接写,但是必须要声明为字符串,。

from django.conf.urls.defaults import *

urlpatterns = patterns('',

(r'^hello/$', 'mysite.views.hello'),

(r'^time/$', 'mysite.views.current_datetime'),

(r'^time/plus/(d{1,2})/$', 'mysite.views.hours_ahead'),

)

还可以更好的处理一下,在第一个参数中声明好导入模块。

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

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'),

)

可以声明调试模式,提供一些参数信息:

from django.conf import settings

from django.conf.urls.defaults import *

from mysite import views

urlpatterns = patterns('',

(r'^$', views.homepage),

(r'^(\d{4})/([a-z]{3})/$', views.archive_month),

)

if settings.DEBUG:

urlpatterns += patterns('',

(r'^debuginfo/$', views.debug),

)

django自动根据正则表达式匹配对应的函数调用,对于函数参数,有2种传递方式:

按顺序的匿名参数传递和指定参数名字的传递方式,如:

urlpatterns = patterns('',

(r'^articles/(\d{4})/$', views.year_archive),

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

) 产生函数调用:month_archive(request, '2006', '03')

urlpatterns = patterns('',

(r'^articles/(?P<year>\d{4})/$', views.year_archive),

(r'^articles/(?P<year>\d{4})/(?P<month>\d{2})/$', views.month_archive),

) 产生函数调用:month_archive(request, year='2006', month='03')

注意在同一个模式中是不能2者混用的。

urlpattern甚至能够传递一个字典参数:

urlpatterns = patterns('',

(r'^foo/$', views.foobar_view, {'template_name': 'template1.html'}),

(r'^bar/$', views.foobar_view, {'template_name': 'template2.html'}),

)

这样对应的处理。注意参数名字和字典的主键必须一致起来就可以,参数类型可以任意。最好加上参数的默认值,就会灵活很多。

def foobar_view(request, template_name=‘default’):

m_list = MyModel.objects.filter(is_new=True)

return render_to_response(template_name, {'m_list': m_list})

注意:参数的数值优先于patter匹配的数值,就是说,比如

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

对于/mydata/2/ 或者 /mydata/432432/) id这个变量都会为3。

模式匹配是有优先原则的,就是django会按照第一个能匹配的进行处理。

这样我们就可以写一个几乎能适应所有情况的一个固定模式的view处理函数:

# urls.py文件

from django.conf.urls.defaults import *

from mysite import models, views

urlpatterns = patterns('',

(r'^events/$', views.object_list, {'model': models.Event}),

(r'^blog/entries/$', views.object_list, {'model': models.BlogEntry}),

)

# views.py文件

from django.shortcuts import render_to_response

def object_list(request, model):

obj_list = model.objects.all()

template_name = 'mysite/%s_list.html' % model.__name__.lower()

return render_to_response(template_name, {'object_list': obj_list})

这样只要编辑好对应的model就可以了~!然后需要改动的只有urls.py文件和对应的模型,在views中的处理都是一样的。

由于request的请求一般分为post和get的,而且会有跟着参数,我们写一个比较通用的处理函数:# views.py

from django.http import Http404, HttpResponseRedirect

from django.shortcuts import render_to_response

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

def some_page_get(request):

assert request.method == 'GET'

do_something_for_get()

return render_to_response('page.html')

def some_page_post(request):

assert request.method == 'POST'

do_something_for_post()

return HttpResponseRedirect('/someurl/')

# urls.py

from django.conf.urls.defaults import *

from mysite import views

urlpatterns = patterns('',

# ...

(r'^somepage/$', views.method_splitter, {'GET': views.some_page_get, 'POST': views.some_page_post}),

# ...

)

参数*args和和**kwargs(注意*号) 这是一个Python特性,允许函数接受动态的、可变数量的、参数名只在运行时可知的参数。 如果你在函数定义时,只在参数前面加一个*号,所有传递给函数的参数将会保存为一个元组. 如果你在函数定义时,在参数前面加两个*号,所有传递给函数的关键字参数,将会保存为一个字典

最后处理一个重复代码的例子:假设每个函数都要验证用户,我们这样处理一下就好了:

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

函数requires_login,传入一个视图函数view,然后返回一个新的视图函数new_view.这个新的视图函数new_view在函数requires_login内定义 处理request.user.is_authenticated()这个验证,从而决定是否执行原来的view函数 from django.conf.urls.defaults import *

from mysite.views import requires_login, my_view1, my_view2, my_view3

urlpatterns = patterns('',

(r'^view1/$', requires_login(my_view1)),

(r'^view2/$', requires_login(my_view2)),

(r'^view3/$', requires_login(my_view3)),

)

关于url的包含可以写的更具有模块性一点,比如前面我们学的amdin模块的添加。如:

urlpatterns = patterns('',

(r'^weblog/', include('mysite.blog.urls')),

(r'^photos/', include('mysite.photos.urls')),

(r'^about/$', 'mysite.views.about'),

)

他会根据指定目录下面对应方法进行处理。如(r'^admin/', include(admin.site.urls)),碰到admin,django会截断后面的内容,发送给admin.site.urls方法中对应的pattern进行处理。

最后注意的是inlcude包含在父urls捕获的变量或者声明的变量,会自动传递给所有的下级视图处理函数。不处理也可以~~

django系统学习笔记~~(8)模板的高级用法~~

(7)http://hi.baidu.com/derris/blog/item/8883efbf1d0c470118d81f10.html

(9)http://hi.baidu.com/derris/blog/item/c0fe9f31140fd5a35fdf0e32.html

django除了context还有一个django.template.RequestContext 默认地在模板context中加入了一些变量

from django.shortcuts import render_to_response

from django.template import RequestContext

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']

}

def view_1(request):

# ...

return render_to_response('template1.html',

{'message': 'I am view 1.'},

context_instance=RequestContext(request, processors=[custom_proc]))

def view_2(request):

# ...

return render_to_response('template2.html',

{'message': 'I am the second view.'},

context_instance=RequestContext(request, processors=[custom_proc]))

一, RequestContext 的第一个参数需要传递一个 HttpRequest 对象,就是传递给视图函数的第一个参数( request )。二, RequestContext 有一个可选的参数 processors ,这是一个包含context处理器函数的list或者tuple。 在这里,我们传递了我们之前定义的函数 curstom_proc 。

每次都写 processors=[] 似乎很麻烦,django提供一个默认的设置:

TEMPLATE_CONTEXT_PROCESSORS = (

'django.core.context_processors.auth',

'django.core.context_processors.debug',

'django.core.context_processors.i18n',

'django.core.context_processors.media',

)

这样我们测试一下:在mysite目录下面的settings.py增加

TEMPLATE_CONTEXT_PROCESSORS = (

'django.core.context_processors.auth',

'django.core.context_processors.debug',

'django.core.context_processors.i18n',

'django.core.context_processors.media',

)

在views.py中增加一个测试模板:

def test(request):

return render_to_response('test.html',{'app': 'I am a test view'},

context_instance=RequestContext(request ) )

urls.py中增加对应的处理

(r'^test/$', views.test),

增加一个test.html的文件模板:

<html> <body>

<h1>test</h1>

<p /> app is -> {{ app }}

<p /> user is -> {{ user }}

<p />

LANGUAGES is -> {{ LANGUAGES }}

</body> </html>

访问:
http://127.0.0.1:8000/test/ 可以看到,我们只传递了app参数,但是user, LANGUAGES也可以用了。

具体默认参数如下:

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 的一个实例,包含了当前登录用户有哪些权限。

django.core.context_processors.debug

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

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

由于调试信息比较敏感,所以这个context处理器只有当同时满足下面两个条件的时候才有效:

DEBUG 参数设置为 True 。

请求的ip应该包含在 INTERNAL_IPS 的设置里面。

django.core.context_processors.i18n如果这个处理器启用,每个 RequestContext 将包含下面的变量:

LANGUAGES : LANGUAGES 选项的值。

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

附录E提供了有关这两个设置的更多的信息。

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

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

{{ request.REMOTE_ADDR }}

你也可以写自己的processors,只要包含进去就可以了。

html语法的转意,比如变量里面如果存在script语句就会很危险~django默认给所有的语法相关的东东都自动转义了,比如<号转为:<等

可以有2种方法进行控制

This will be escaped: {{ data }}

This will not be escaped: {{ data|safe }}

--------------------------------------------

This will be escaped: <b>

This will not be escaped: <b>

还可以成块的注释:

{% autoescape off %}

Hello {{ name }}

{% endautoescape %}

---------

对于变量的复制是不受过滤的,因为是受控语句复制的。所以可以信任。

如 {{ data|default:"This is a string literal." }}, 是不会过滤的。

默认情况下这些函数使用 TEMPLATE_DIRS 的设置来载入模板。

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 异常。

django.template.loaders.filesystem.load_template_source : 这个加载器根据 TEMPLATE_DIRS 的设置从文件系统加载模板。

django.template.loaders.app_directories.load_template_source : 这个加 载器从文件系统上的Django应用中加载模板。 对 INSTALLED_APPS 中的每个应用,这个加 载器会查找一个 templates 子目录。 如果这个目录存在,Django就在那里寻找模板。

这意味着你可以把模板和你的应用一起保存,从而使得Django应用更容易和默认模板一起发布。例如,如果 INSTALLED_APPS 包含 ('myproject.polls','myproject.music') ,那么 get_template('foo.html') 会按这个顺序查找模板:

/path/to/myproject/polls/templates/foo.html

/path/to/myproject/music/templates/foo.html

扩展模板系统

创建一个模板库

创建一个模板库分两步走:

第一,决定哪个Django应用应当拥有这个模板库。确保把你的应用添加到 INSTALLED_APPS 中。(如果想在主目录里面,又算那个应用的呢?)

第二,在应用包里创建一个 templatetags 目录。

在 templatetags 中创建两个空文件:__init__.py和一个用来存放你自定义的标签/过滤器定义的文件。

第二个文件 的名字稍后将用来加载标签。如,如果你的自定义标签/过滤器在一个叫作 poll_extras.py 的文件中,你需要在模板中写入如下内容:

{% load poll_extras %}

{% load %} 标签检查 INSTALLED_APPS 中的设置,仅允许加载已安装的Django应用程序中的模板库。 这是一个安全特性。

测试一下:在book目录里面增加一个templatetags目录,里面增加1个空文件:__init__.py

创建book_extras.py,内容如下

from django import template

register = template.Library()

def test(value, arg):

"Removes all values of arg from the given string"

return str(value) + ' ' + arg + 'and this is a test filter '

register.filter('testx', test)


@register.filter

def toup(value):

return str(value).upper()


增加一个booktest.html文件,内容如下:

{% load book_extras %}

<html>

<body>

<p> first test : {{ user|testx:"123" }}

<p> second upper: {{ user|toup }}

</body>

</html>


更改books目录里面views.py内容为:

#coding:gbk


from django.template import RequestContext

from django.shortcuts import render_to_response

import os.path


def booktest(request):

bookurl = unicode(os.path.dirname(__file__), 'gbk') + ur'\templatetags\booktest.html'

return render_to_response(bookurl,{'app': 'I am a test view'},

context_instance=RequestContext(request ) )


然后在mysite目录里面的urls.py增加一个对应的处理项:

(r'^booktest/$', "mysite.books.views.booktest"),


访问:http://127.0.0.1:8000/booktest/ 可以看到结果。

定义tag标签:The time is {% current_time "%Y-%m-%d %I:%M %p" %}.

标签块:{% comment %} {% endcomment %}

包含标签:{% books_for_author author %}

编写自定义模板加载器: load_template_source(template_name, template_dirs=None)

还没有来得及研究~~

2010-03-04 21:45

django系统学习笔记~~(9)数据模型说明

(8)http://hi.baidu.com/derris/blog/item/f490f213dc314f095baf53cc.html

(10)http://hi.baidu.com/derris/blog/item/8cb9a635d06d061a91ef39f3.html

在dos模式,进入到mysite的目录里面~~

运行:

>>> from mysite.books.models import Book

>>> for i in Book.objects.all():

... print i.id, i.title

............................在列出的一堆里面找一个。 id 是默认表的主键,自动生成的。

>>> b = Book.objects.get(id=1) # 1一般都有

>>> b.title

u'The Django Book' # 具体当然不一样

我们可以根据外键来直接引用其他的表数据:

>>> for i in Book.objects.all():

... print i.id, i.title, i.publisher.website

把对应的出版社的网站都打印出来了。反向也可以,但是因为是一对多的关系:

>>> from mysite.books.models import Publisher

>>> for i in Publisher.objects.all():

... print i

...

Apress

newpub

>>> p = Publisher.objects.get(name='newpub')

>>> p.book_set.all() # 因为一对多的关系,所以要反向追溯,就要加_set找到book的数据集。

[<Book: ruby cook book>, <Book: ccccccccc>]

>>> p.book_set.filter(title__icontains='s')

[<Book: dfasdfadf>, <Book: python test>]

对于多对多,也是同一对多是一样的,在book表名后面加_set来反向追溯。(因为authors表里面没有指定book的字段,所以只能通过book_set来反向找。)

>>> b = Book.objects.get(id=1)

>>> b.authors.get(id=1).book_set.get(id=1).authors.get(id=1).book_set.all()

整整转了一个圈来引用着玩~~

更改数据库的表结构的时候一定要注意,django不会自动做的,最好的办法就是删除掉数据库重新建~~

如果都运行了,就要小心一点,把模型和数据一定要对应起来,尤其是不要引起数据的逻辑错误。比如外键找不到了。。。

models.Manager的用法

在books下面的models.py文件中增加一个测试表和测试的Manager方法。

class TestManager(models.Manager):

def count_me(self, keyword):

return self.filter(myname__icontains=keyword).count()

class TestTable(models.Model):

myname = models.CharField(max_length=100)

myage = models.IntegerField()

objects = TestManager()

def __unicode__(self):

return self.myname

运行:python manage.py syncdb

Creating table books_testtable

然后运行shell:python manage.py shell

>>> from books.models import TestTable

>>> p = TestTable()

>>> p.myname='test'

>>> p.myage=18

>>> p.save()

测试数据加上,可以测试一下方法了 :) 注意不能用p调用~,因为manager方法建在类里面。

>>> TestTable.objects.count_me('test')

1

注意着一个objects本身就存在django.db.models.manager.Manager object类型的。不可以用别的名字,否则默认只能有一个manager对象。objects就不存在了,也无法调用all,get等默认包含的方法。不过也可以显式的声明,增加多个manager。

objects = models.Manager() # The default manager.

dahl_objects = DahlBookManager() # The Dahl-specific manager.

objects.all()默认调用Manager.get_query_set(),可以进行覆盖产生诸如:Person.men.all(),Person.women.all(),Person.people.all()的效果。。。子类再细分小类~~ 用的着么?

类里面可以增加方法,使得类用起来更面向对象一些~~ 也可以扩充一下数据库的sql语句,使得更加灵活,直接执行一些数据库依赖的sql语句~~

>>> from django.db import connection

>>> cursor = connection.cursor()

>>> cursor.execute("""

... SELECT DISTINCT first_name

... FROM people_person

... WHERE last_name = %s""", ['Lennon'])

>>> row = cursor.fetchone()

>>> print row

['John']

注意在SQL语句cursor.execute()使用”%s”,而不要在SQL内试图立刻添加一个参数. 如果你使用了这个技术,数据库后的基础库将会自动添加引用同时尽可能的转意你的参数.

不要把你的视图代码和django.db.connection语句混杂在一起,把它们放在自定义模型或者自定义manager方法中

django系统学习笔记~~(10)通用视图

(9)http://hi.baidu.com/derris/blog/item/c0fe9f31140fd5a35fdf0e32.html

(11)http://hi.baidu.com/derris/blog/item/88988e4b468297fb83025c1c.html

首先在mysite中加一个about.html的模板(utf8编码):

<html> <h1>ha,我是about</h1></html>

再更改urls.py文件,增加内容:

from django.views.generic.simple import direct_to_template

...............

(r'^about/$', direct_to_template, {'template': 'about.html' }),

运行python manage.py runserver,访问: http://127.0.0.1:8000/about/就可以了.

下面对books模型里面数据进行处理显示:

创建一个publisher_list_page.html的模板如下:

{% extends "base.html" %}

{% block content %}

<h2>Publishers</h2>

<ul>

{% for publisher in object_list %}

<li>{{ publisher.name }}</li>

{% endfor %}

</ul>

{% endblock %}


urls.py中最后增加以下内容:

from django.views.generic import list_detail

from mysite.books.models import Publisher

publisher_info = {

'queryset': Publisher.objects.all(),

'template_name': 'publisher_list_page.html'

}

urlpatterns += patterns('',

(r'^publishers/$', list_detail.object_list, publisher_info)

)


访问: http://127.0.0.1:8000/publishers/就可以了~!

下步扩展:

首先定义一个友好的变量,模板的object_list名字很没有意义~~

在publisher_info变量里面增加一个参数:'template_object_name': 'publisher', 就可以把object_list替换为publisher_list了.django自动加一个 _list真是无聊,感觉这些潜规则有些多,就和模型里面加_set一样.不如增加一个方法引用的明白.

如果需要增加额外的内容,比如为publisher增加图书的信息,可以使用: extra_context参数.

在publisher_info变量里面增加一个参数: 'extra_context': {'book_list': Book.objects.all()}这样可以把book的数据传过去.但是如果要传递数据的话,只会在第一访问的时候初始化一次,数据将会缓存起来,所以这里也可以传递函数名,这样可以保证每次都重新访问数据.更改为'extra_context': {'book_list': Book.objects.all}就可以了.这样传递的是all函数.

urls.py中增加对应处理项:

(r'^books/(\w+)/$', "mysite.views.books_by_publisher"),

views.py中增加代码:

from django.shortcuts import get_object_or_404

from django.views.generic import list_detail

from mysite.books.models import Book, Publisher

def books_by_publisher(request, name):

publisher = get_object_or_404(Publisher, name__iexact=name)

return list_detail.object_list(

request,

queryset = Book.objects.filter(publisher=publisher),

template_name = 'books_by_publisher.html',

template_object_name = 'book',

extra_context = {'publisher': publisher}

)


再增加一个处理模板books_by_publisher.html:

{% extends "base.html" %}

{% block content %}

<h2> book </h2>

{% for book in book_list %}

<li>{{ book.title }}</li>

{% endfor %}

{% endblock %}


访问http://127.0.0.1:8000/books/xxxxx

xxxx是数据库里面的某出版社.

2、Detail Views

视图函数 : django.views.generic.list_detail.

此视图提供单个对象的详细视图.

例子

继续上一个 object_list 的例子,我们将通过修改 URLconf 来添加一个给定作者的详细视图:

------------------------------------------------------------------------------------------------------------

from mysite.books.models import Author

from django.conf.urls.defaults import *

from django.views.generic import list_detail

author_list_info = {

'queryset' : Author.objects.all(),

'allow_empty': True,

}

author_detail_info = {

"queryset" : Author.objects.all(),

"template_name" : "author_detail.html",

}

urlpatterns = patterns('',

(r'authors/$', list_detail.object_list, author_list_info),

(r'^authors/(?P<object_id>\d+)/$', list_detail.object_detail, author_detail_info),

)

-------------- template中的变量引用:{{ object.字段名 }}

附录:django.views.generic.list_detail.object_list
Description:

A page representing a list of objects.

Required arguments:

queryset: A QuerySet that represents the objects.

Optional arguments:

paginate_by: An integer specifying how many objects should be displayed per page. If this is given, the view will paginate objects with
paginate_by objects per page. The view will expect either a page query string parameter (via
GET) or a page variable specified in the URLconf. See below.
page: The current page number, as an integer, or the string 'last'. This is 1-based. See below.

template_name: The full name of a template to use in rendering the page. This lets you override the default template name (see below).

template_loader: The template loader to use when loading the template. By default, it's
django.template.loader.
extra_context: A dictionary of values to add to the template context. By default, this is an empty dictionary. If a value in the dictionary is callable, the generic view will call it just before rendering the template.

allow_empty: A boolean specifying whether to display the page if no objects are available. If this is
False and no objects are available, the view will raise a 404 instead of displaying an empty page. By default, this is
True.
context_processors: A list of template-context processors to apply to the view's template.

template_object_name: Designates the name of the template variable to use in the template context. By default, this is
'object'. The view will append '_list' to the value of this parameter in determining the variable's name.

mimetype: The MIME type to use for the resulting document. Defaults to the value of the setting.

Template name:

If template_name isn't specified, this view will use the template
<app_label>/<model_name>_list.html by default.

Template context:

In addition to extra_context, the template's context will be:

object_list: The list of objects. This variable's name depends on the
template_object_name parameter, which is 'object' by default. If
template_object_name is 'foo', this variable's name will be
foo_list.
is_paginated: A boolean representing whether the results are paginated. Specifically, this is set to
False if the number of available objects is less than or equal to paginate_by.

If the results are paginated, the context will contain these extra variables:

paginator: An instance of django.core.paginator.Paginator.
page_obj: An instance of django.core.paginator.Page.

Notes on pagination
If paginate_by is specified, Django will paginate the results. You can specify the page number in the URL in one of two ways:

Use the page parameter in the URLconf. For example, this is what your URLconf might look like:

(r'^objects/page(?P<page>[0-9]+)/$','object_list',dict(info_dict))

Pass the page number via the page query-string parameter. For example, a URL would look like this:

/objects/?page=3

To loop over all the available page numbers, use the page_range variable. You can iterate over the list provided by
page_range to create a link to every page of results.

These values and lists are 1-based, not 0-based, so the first page would be represented as page
1.

For more on pagination, read the .

As a special case, you are also permitted to use last as a value for
page:

/objects/?page=last
This allows you to access the final page of results without first having to determine how many pages there are.

Note that pagemust be either a valid page number or the value
last; any other value for page will result in a 404 error.

django.views.generic.list_detail.object_detail
A page representing an individual object.

Description:

A page representing an individual object.

Required arguments:

queryset: A QuerySet that contains the object.

Either object_id or (slugandslug_field) is required.

If you provide object_id, it should be the value of the primary-key field for the object being displayed on this page.

Otherwise, slug should be the slug of the given object, and slug_field should be the name of the slug field in the
QuerySet's model. By default, slug_field is 'slug'.

Optional arguments:

template_name: The full name of a template to use in rendering the page. This lets you override the default template name (see below).

template_name_field: The name of a field on the object whose value is the template name to use. This lets you store template names in the data. In other words, if your object has a field
'the_template' that contains a string 'foo.html', and you set
template_name_field to 'the_template', then the generic view for this object will use the template
'foo.html'.

It's a bit of a brain-bender, but it's useful in some cases.

template_loader: The template loader to use when loading the template. By default, it's
django.template.loader.

extra_context: A dictionary of values to add to the template context. By default, this is an empty dictionary. If a value in the dictionary is callable, the generic view will call it just before rendering the template.

context_processors: A list of template-context processors to apply to the view's template.

template_object_name: Designates the name of the template variable to use in the template context. By default, this is
'object'.

mimetype: The MIME type to use for the resulting document. Defaults to the value of the setting.

Template name:

If template_name isn't specified, this view will use the template
<app_label>/<model_name>_detail.html by default.

Template context:

In addition to extra_context, the template's context will be:

object: The object. This variable's name depends on the template_object_name parameter, which is
'object' by default. If template_object_name is 'foo', this variable's name will be
foo.

-----------研究了一下,可以写个通用的paginate,拷贝到模版里面可以凑副着用,可以编辑成include的html文件:)

{% include 'pagenavi.html.inc' %}。没有进行数字验证,反正不碍事~~

<table border="1" width="400">

<tr align="right">

<td><a href="?page=1">第一页</a> </td>

<td>{% if has_previous %}

<a href="?page={{ previous }}">上一页</a>

{% else %}

<a href="?page=1">上一页</a>

{% endif %}

</td>

<td>

{% if has_next %}

<a href="?page={{ next }}">下一页</a>

{% else %}

<a href="?page=last">下一页</a>

{% endif %}

</td>

<td><a href="?page=last">最后一页{{pages}}</a> </td>

<td>当前第{{page}}页<input size = 3 name='gopage' id='gapage'>

<button onclick=" location.href='?page=' + (getElementById('gopage').value.toString()) ;" > go </button> </td>

</tr>

</table>

django系统学习笔记~~(11)用 fastcgi, lighttpd 在windows和ubuntu下面部署

(10)http://hi.baidu.com/derris/blog/item/8cb9a635d06d061a91ef39f3.html

(12)http://hi.baidu.com/derris/blog/item/881384869570923566096e2a.html

下载lighthttpd for windows版本 (当前是1.4.26-1 (SSL)版本)

http://en.wlmp-project.net/downloads.php?cat=lighty

安装后,把djanog的程序目录拷贝到htdocs下面,

conf目录下面的lighttpd-inc.conf中调整以下内容:

server.modules = (

"mod_rewrite",

"mod_access",

"mod_fastcgi",

"mod_accesslog",

"mod_alias",

#增加fastcgi的配置:

url.rewrite-once = (

"^(/media.*)$" => "$1",

"^/favicon\.ico$" => "/media/favicon.ico",

"^(/.*)$" => "/mysite.fcgi$1",

)

server.document-root = "htdocs/程序的目录/"

先运行程序目录下面的fcgiserver:manage.py runfcgi method=threaded host=127.0.0.1 port=3033

再运行lighttpd:lighttpd.exe -f conf/lighttpd-inc.conf -m lib -D

然后访问127.0.0.1就搞定了。。。

如果url总是被附加上了/*.fcgi/,则需要修改mysite目录里面的settings.py文件,加上选项:

FORCE_SCRIPT_NAME=''

重新运行一边!~~ 终于搞定了,哇哈哈~~~ 方便一点,编一个批处理文件:

start /b yedasp/manage.py runfcgi method=threaded host=127.0.0.1 port=3033

START /B lighttpd.exe -f yedasp/conf/lighttpd-inc.conf -m lib -D

--------------------------------------------------------------------

fastcgi在ubuntu8下面,好久不用ubuntu都忘光光用户名和密码了。。

直接安装:

apt-get install lighttpd

whereis lighttpd

从/etc/lighttpd/lighttpd.conf拷贝一份到/usr/local/lighttpd/

cd /usr/local/lighttpd

$ gedit lighttpd.conf #

配置文件很直观明了,一般只要把server.document-root、server.errorlog、accesslog.filename改成你的实际目录和文件名字就可以了。ps aux | grep lighttpd , kill xxx ,

运行:lighttpd -D -f lighttpd.conf ,访问127.0.0.1。没有问题就ok了

然后拷贝mysite到lighttpd下面。运行一下普通模式python manage.py runserver,基本没有问题~,有些目录分割号错误的地方~~linux下面是/,而windows下用\,

然后开始配置fastcgi了。

easy_install flup

然后运行 python manage.py runfcgi

能提示出来首页内容就说明没有问题拉~~

然后运行守护进程: python manage.py runfcgi daemonize=false method=threaded host=127.0.0.1 port=8888 端口无所谓了,就是等lighttpds的调用,配置对应起来就可以。

配置lighttpd文件:

server.modules = (

"mod_rewrite",

"mod_alias",

"mod_access",

"mod_status",

"mod_fastcgi",

"mod_accesslog",

)

server.document-root = "/usr/local/lighttpd/test/"

fastcgi.server = (

"/mysite.fcgi" => (

"main" => (

"host" => "127.0.0.1",

"port" => 8888,

"check-local" => "disable"

)

),

)

alias.url += (

"/media/" => "/usr/lib/python2.5/site-packages/django/contrib/admin/media/"

)

url.rewrite-once = (

"^(/media.*)$" => "$1",

"^/favicon\.ico$" => "/media/favicon.ico",

"^(/.*)$" => "/mysite.fcgi$1",

)

就是在根目录下面的所有东东都转送到mysite.fcgi的地方~~

重新运行lighttpd,访问127.0.0.1就可以了,如果url总是被附加上了/*.fcgi/,则需要修改mysite目录里面的settings.py文件,加上选项:

FORCE_SCRIPT_NAME=''

重新运行程序lighttpd restart -f -D lighttpd.conf,基本上不会有问题了。。。。 唉,我一马虎没看清楚去掉rewrite前面的注释。浪费了3个小时调试搜索检查。。。

------------------------------------------------------------- 记录乱七八糟的东东。

$ sbin/lighttpd -f lighttpd.conf # 启动lighttpd服务

$ ps aux |grep lighttpd

www 15403 0.0 0.9 2860 1148 ? S 00:15 0:00 sbin/lighttpd -f

这就完成了从安装到启动的整个过程,很简单吧。从最后一行的输出可以看出,lighttpd是单进程服务的,这和apache不一样(也许是它的稳定性不如apache的一个原因)。

-------------- 也可以自己下载特定版本:

下载:http://download.lighttpd.net/lighttpd/releases-1.4.x/lighttpd-1.4.26.tar.gz

root@ubuntu:/usr/local/lighttpd-1.4.26# ./configure

checking一堆以后:

提示错误:configure: error: pcre-config not found, install the pcre-devel package or build with --without-pcre

查了一下:

出现configure: error: C compiler cannot create executables … 安装apt-get install libc6-dev.

出现configure: error: configure: error: pcre-config not found … 安装apt-get install libpcre3-dev

出现configure: error: zlib-headers and/or libs where not found … 安装apt-get install zlib1g-dev

出现configure: error: bzip2-headers and/or libs where not found … 安装apt-get install libbz2-dev

于是运行:apt-get install libc3-dev

再检查一下,果然是configure: error: zlib-headers and/or libs where not found, install them or build with --without-zlib

运行:apt-get install zlib1g-dev

直接运行:apt-get install libbz2-dev

终于没有错误了

$ ./configure --prefix=/usr/local/lighttpd-1.4.26

$ make

$ make instal

fastcgi.server = (

"/mysite.fcgi" => (

"main" => (

# Use host / port instead of socket for TCP fastcgi

"host" => "127.0.0.1",

"port" => 3033,

"check-local" => "disable",

)

),

)

alias.url = (

"/media/" => "E:/LightTPD/yedaSp/media/",

)

django系统学习笔记~~(12)用 mod_python, apache 在windows下部署

(11)http://hi.baidu.com/derris/blog/item/88988e4b468297fb83025c1c.html

(13)http://hi.baidu.com/derris/blog/item/80e8eb9558405d40d1135e8e.html

首先安装apache2.2x~~

安装推荐的选项是windows服务方式,如果只是学习,可以选终端运行方式~~注意运行的时候会产生2个httpd的进程。因为Apache for Windows是多线程的,它并不像Unix版本那样为每个请求使用一个单独的进程。 而是通常运行两个Apache进程:一个父进程,和一个处理请求的子进程。在子进程内部由多个单独的线程来处理每个请求。

在安装目录中的conf文件夹中是配置文件:

生成httpd.conf,(如果已经有这个文件,会生成一个httpd.conf.default文件。在htdocs中生成index.html。如果有,也会生成一个.default文件。)

选择终端运行方式,根据提示的绑定地址和端口访问,It works就ok了。。。

具体可以参照以下:http://lamp.linux.gov.cn/Apache/ApacheMenu/platform/windows.html

然后安装mod_python3x

下载mod_python:http://www.apache.org/dist/httpd/modpython/win/3.3.1/

安装mod_python自动加入Python的Lib中了。 还要选apache的目录,自动加文件到modules目录中。

然后配置mod_python,打开Apache安装目录下的conf/httpd.conf,做如下修改:

1、在LoadModule部分下面加入:LoadModule python_module modules/mod_python.so

2、修改DocumentRoot 值,指向工作目录,比如:DocumentRoot "D:\Program Files\Apache Software Foundation\Apache2.2\htdocs\mysite" 。 我也不想这么长的目录,但是这个好像有权限方面的管理,在外面的目录总是提示访问拒绝~~回头再研究apache的使用说明吧~~

加入

<Location "/">

SetHandler python-program

PythonHandler django.core.handlers.modpython

SetEnv DJANGO_SETTINGS_MODULE mysite.settings

PythonDebug On

PythonPath "['D:\Program Files\Apache Software Foundation\Apache2.2\htdocs', 'D:\Python25\Lib\site-packages\django'] + sys.path"

</Location>

<Location "/media/">

SetHandler None

</Location>

<LocationMatch "\.(jpg|gif|png)$">

SetHandler None

</LocationMatch>

AddHandle说明如果GET此目录下所有的.py文件用mod_python处理;

PythonHandler MyTest是缺省的文件,当取得“/”时执行的文件;

PythonDebug On把调试开关打开,如果出现错误,在浏览器上能看见出错的调用栈信息。

重新启动Apache服务,在浏览器中访问就可以了~~

在admin模块格式很乱,把django\contrib\admin目录下面的media目录拷贝到mysite下面就可以了。

(很怪我在单位总是提示找不到对应的程序,mod_python.so加载不到server,查了半天,有人说是因为安装python没有选择for all user的问题,可是我试验了还是不行。。。浪费了一天,崩溃了。。。)

每次更改python代码,系统都需要重启才能体现出来,可以增加一个配置选项

MaxRequestsPerChild 1。

MaxRequestsPerChild就像Unix版本中的指令一样,这条指令控制一个进程退出前将为多少个请求提供服务。 然而,与Unix不同的是,一个进程将为所有请求而不是只为一个请求服务,因此如果设置这条指令,建议将它设为一个很大的值。默认设置 MaxRequestsPerChild 0 使得进程从不退出。1就是访问一次就退出,刷新啦~~

在google里面的解决方法,但是还是不行,我怀疑是我安装的某些dll支持版本不对,直接晕了.(cannot load mod_python into server site:apache.org)

Some of the more commonly asked questions asked on the mailing list relate to
mod_python
configuration issues that are not currently covered in the documentation.

Apache can't load mod_python.so

---------------------------------------------

This more common problem on Windows, but can occur on other platforms. A typical apache error message looks like this:

Syntax error on line 173 of C:/Program Files/Apache

Group/Apache2/conf/httpd.conf:

Cannot load C:/Program Files/Apache

Group/Apache2/modules/mod_python.so into server: The

specified module could not be found.

On Windows this may indicate a problem with missing D

Nicolas offered the following as an explanation on Windows:

"""

One of the possible cause of your problem is that Apache does find

mod_python.so but not one of the DLL it relies on. Unfortunately the error

reporting in this case is quite scarce and misguiding.

The candidates missing DLLs are python24.dll and the Microsoft Runtime DLLS

(normally msvcr71.dll and msvcp71.dll).

Make sure that your Python directory and the runtime DLLs can be found on

your PATH. The runtime DLLs are normaly copied in your Python directory, so

putting the Python directory on your PATH variable should do the trick.

Also, make sure that the user which is running Apache has its PATH variable

properly set. The best way to do this is to define it at the system-wide

level, but logging it under the user and defining the variable at the user

level is also possible.

"""

Apache can't load mod_python.so - undefined symbol

-----------------------------------------------------------------------

This may look similar to the first example, but indicates a deeper problem. Typical error message:

httpd: Syntax error on line 231 of /usr/local/apache2/conf/httpd.conf: Cannot load /usr/local/apache2/modules/mod_python.so
into server: /usr/local/apache2/modules/mod_python.so: undefined symbol: apr_sockaddr_port_get

This error could indicate an actual bug in mod_python, or a mismatch between the Apache version used to compile
mod_python versus the one being used to run it. I'm not sure there is an easy answer, but we should offer some initial troubleshooting suggestions.

make_obcallback: could not import mod_python.apache

--------------------------------------------------------------------------

This one seems to occur on all platforms with similar frequency, and is usually related to having python multiple versions on the same system. Typical error message:

[Sun Apr 09 14:03:46 2006] [error] make_obcallback: could not import

mod_python.apache.\n

[Sun Apr 09 14:03:46 2006] [error] python_handler: no interpreter

callback found.

[Sun Apr 09 14:03:46 2006] [error] [client 192.168.2.100]

python_handler: Can't get/create interpreter., referer:

http://localhost/mptest.py

The solution is to adjust that PATH apache uses so it finds the correct python version. This will be platform spe

django系统学习笔记~~(13)输出非HTML内容

(12)http://hi.baidu.com/derris/blog/item/881384869570923566096e2a.html

(14)http://hi.baidu.com/derris/blog/item/9a15e0fdb22d9e49d7887d71.html

输出一个图像~~, 在urls.py中增加一个对应项:

(r'^my_image/$', views.my_image),

在views.py增加处理方法:

def my_image(request):

image_data = open(r"d:\td.jpg", "rb").read()

return HttpResponse(image_data, mimetype="image/png")

访问:http://127.0.0.1:8000/my_image/ 可以看到图像了。

没什么意思了,就是简单记录一下怎样生成文件吧:

生成csv文件下载:

import csv

from django.http import HttpResponse

UNRULY_PASSENGERS = [146,184,235,200,226,251,299,273,281,304,203]

def unruly_passengers_csv(request):

response = HttpResponse(mimetype='text/csv')

response['Content-Disposition'] = 'attachment; filename=unruly.csv'

writer = csv.writer(response)

writer.writerow(['Year', 'Unruly Airline Passengers'])

for (year, num) in zip(range(1995, 2006), UNRULY_PASSENGERS):

writer.writerow([year, num])

return response

安装 ReportLab

>easy_install.py ReportLab

>>> import reportlab

from cStringIO import StringIO

from reportlab.pdfgen import canvas

from django.http import HttpResponse

def hello_pdf(request):

# Create the HttpResponse object with the appropriate PDF headers.

response = HttpResponse(mimetype='application/pdf')

response['Content-Disposition'] = 'attachment; filename=hello.pdf'

temp = StringIO()

# Create the PDF object, using the StringIO object as its "file."

p = canvas.Canvas(temp)

# Draw things on the PDF. Here's where the PDF generation happens.

# See the ReportLab documentation for the full list of functionality.

p.drawString(100, 100, "Hello world.")

# Close the PDF object cleanly.

p.showPage()

p.save()

# Get the value of the StringIO buffer and write it to the response.

response.write(temp.getvalue())

return response

rss

激活syndication feeds, 添加如下的 urls.py

from django.conf.urls.defaults import *

from mysite.feeds import LatestEntries, LatestEntriesByCategory

feeds = {

'latest': LatestEntries,

'categories': LatestEntriesByCategory,

}

urlpatterns = patterns('',

# ...

(r'^feeds/(?P<url>.*)/$', 'django.contrib.syndication.views.feed',

{'feed_dict': feeds}),

# ...

)

一个简单的FeedThis simple example describes a feed of the latest five blog entries for a given blog:

from django.contrib.syndication.feeds import Feed

from mysite.blog.models import Entry

class LatestEntries(Feed):

title = "My Blog"

link = "/archive/"

description = "The latest news about stuff."

def items(self):

return Entry.objects.order_by('-pub_date')[:5]

要注意的重要的事情如下所示:

子类 django.contrib.syndication.feeds.Feed .

title , link , 和 description 对应一个标准 RSS 里的 <title> , <link> , 和 <description> 标签.

items() 是一个方法,返回一个用以包含在包含在feed的 <item> 元素里的 list 虽然例子里用Djangos database API返回的 NewsItem 对象, items() 不一定必须返回 model的实例 Although this example returns Entry objects using Django’s database API, items() doesn’t have to return model instances.

还有一个步骤,在一个RSS feed里,每个(item)有一个(title),(link)和(description),我们需要告诉框架 把数据放到这些元素中 In an RSS feed, each <item> has a <title> , <link> , and <description> . We need to tell the framework what data to put into those elements.

如果要指定 <title> 和 <description> ,可以建立一个Django模板(见Chapter 4)名字叫 feeds/latest_title.html 和 feeds/latest_description.html ,后者是URLConf里为对应feed指定的 slug 。注意 .html 后缀是必须的。 Note that the .html extension is required.

RSS系统模板渲染每一个条目,需要给传递2个参数给模板上下文变量:

obj : 当前对象 ( 返回到 items() 任意对象之一 )。

site : 一个表示当前站点的 django.models.core.sites.Site 对象。 这对于 {{ site.domain }} 或者 {{ site.name }} 很有用。

如果你在创建模板的时候,没有指明标题或者描述信息,框架会默认使用 "{{ obj }}" ,对象的字符串表示。 (For model objects, this will be the __unicode__() method.

你也可以通过修改 Feed 类中的两个属性 title_template 和 description_template 来改变这两个模板的名字。

你有两种方法来指定 <link> 的内容。 Django 首先执行 items() 中每一项的 get_absolute_url() 方法。 如果该方法不存在,就会尝试执行 Feed 类中的 item_link() 方法,并将自身作为 item 参数传递进去。

get_absolute_url() 和 item_link() 都应该以Python字符串形式返回URL。

对于前面提到的 LatestEntries 例子,我们可以实现一个简单的feed模板。 latest_title.html 包括:

{{ obj.title }}

并且 latest_description.html 包含:

{{ obj.description }}

一个更复杂的Feed框架通过参数支持更加复杂的feeds。

For example, say your blog offers an RSS feed for every distinct tag you’ve used to categorize your entries. 如果为每一个单独的区域建立一个 Feed 类就显得很不明智。

取而代之的方法是,使用聚合框架来产生一个通用的源,使其可以根据feeds URL返回相应的信息。

Your tag-specific feeds could use URLs like this:

http://example.com/feeds/tags/python/ : Returns recent entries tagged with python

http://example.com/feeds/tags/cats/ : Returns recent entries tagged with cats

固定的那一部分是 "beats" (区域)。

举个例子会澄清一切。 下面是每个地区特定的feeds:

from django.core.exceptions import ObjectDoesNotExist

from mysite.blog.models import Entry, Tag

class TagFeed(Feed):

def get_object(self, bits):

# In case of "/feeds/tags/cats/dogs/mice/", or other such

# clutter, check that bits has only one member.

if len(bits) != 1:

raise ObjectDoesNotExist

return Tag.objects.get(tag=bits[0])

def title(self, obj):

return "My Blog: Entries tagged with %s" % obj.tag

def link(self, obj):

return obj.get_absolute_url()

def description(self, obj):

return "Entries tagged with %s" % obj.tag

def items(self, obj):

entries = Entry.objects.filter(tags__id__exact=obj.id)

return entries.order_by('-pub_date')[:30]

以下是RSS框架的基本算法,我们假设通过URL /rss/beats/0613/ 来访问这个类:

框架获得了URL /rss/beats/0613/ 并且注意到URL中的slug部分后面含有更多的信息。 它将斜杠("/" )作为分隔符,把剩余的字符串分割开作为参数,调用 Feed 类的 get_object() 方法。

在这个例子中,添加的信息是 ['0613'] 。对于 /rss/beats/0613/foo/bar/ 的一个URL请求, 这些信息就是 ['0613', 'foo', 'bar'] 。

get_object() 就根据给定的 bits 值来返回区域信息。

In this case, it uses the Django database API to retrieve the Tag . Note that get_object() should raise django.core.exceptions.ObjectDoesNotExist if given invalid parameters. 在 Beat.objects.get() 调用中也没有出现 try /except 代码块。 函数在出错时抛出 Beat.DoesNotExist 异常,而 Beat.DoesNotExist
是 ObjectDoesNotExist 异常的一个子类型。

为产生 <title> , <link> , 和 <description> 的feeds, Django使用 title() , link() , 和 description() 方法。 在上面的例子中,它们都是简单的字符串类型的类属性,而这个例子表明,它们既可以是字符串, 也可以是 方法。 对于每一个 title , link 和 description 的组合,Django使用以下的算法:

试图调用一个函数,并且以 get_object() 返回的对象作为参数传递给 obj 参数。

如果没有成功,则不带参数调用一个方法。

还不成功,则使用类属性。

最后,值得注意的是,这个例子中的 items() 使用 obj 参数。对于 items 的算法就如同上面第一步所描述的那样,首先尝试 items(obj) , 然后是 items() ,最后是 items 类属性(必须是一个列表)。

Feed 类所有方法和属性的完整文档,请参考官方的Django文档 (http://www.djangoproject.com/documentation/0.96/syndication_feeds/) 。

指定Feed的类型默认情况下, 聚合框架生成RSS 2.0. 要改变这样的情况, 在 Feed 类中添加一个 feed_type 属性. To change that, add a feed_type attribute to your Feed class:

from django.utils.feedgenerator import Atom1Feed

class MyFeed(Feed):

feed_type = Atom1Feed

注意你把 feed_type 赋值成一个类对象,而不是类实例。 目前合法的Feed类型如表11-1所示。

表 11-1. Feed 类型 Feed 类 类型

django.utils.feedgenerator.Rss201rev2Feed RSS 2.01 (default)

django.utils.feedgenerator.RssUserland091Feed RSS 0.91

django.utils.feedgenerator.Atom1Feed Atom 1.0

闭包为了指定闭包(例如,与feed项比方说MP3 feeds相关联的媒体资源信息),使用 item_enclosure_url , item_enclosure_length , 以及 item_enclosure_mime_type ,比如

from myproject.models import Song

class MyFeedWithEnclosures(Feed):

title = "Example feed with enclosures"

link = "/feeds/example-with-enclosures/"

def items(self):

return Song.objects.all()[:30]

def item_enclosure_url(self, item):

return item.song_url

def item_enclosure_length(self, item):

return item.song_length

item_enclosure_mime_type = "audio/mpeg"

当然,你首先要创建一个包含有 song_url 和 song_length (比如按照字节计算的长度)域的 Song 对象。

语言聚合框架自动创建的Feed包含适当的 <language> 标签(RSS 2.0) 或 xml:lang 属性(Atom). 他直接来自于您的 LANGUAGE_CODE 设置. This comes directly from your LANGUAGE_CODE setting.

URLslink 方法/属性可以以绝对URL的形式(例如, "/blog/" )或者指定协议和域名的URL的形式返回(例如 "http://www.example.com/blog/" )。如果 link 没有返回域名,聚合框架会根据 SITE_ID 设置,自动的插入当前站点的域信息。 (See Chapter 16 for more on SITE_ID
and the sites framework.)

Atom feeds需要 <link rel="self"> 指明feeds现在的位置。 The syndication framework populates this automatically.

同时发布Atom and RSS一些开发人员想 同时 支持Atom和RSS。这在Django中很容易实现: 只需创建一个你的 feed 类的子类,然后修改 feed_type ,并且更新URLconf内容。 下面是一个完整的例子: Here’s a full example:

from django.contrib.syndication.feeds import Feed

from django.utils.feedgenerator import Atom1Feed

from mysite.blog.models import Entry

class RssLatestEntries(Feed):

title = "My Blog"

link = "/archive/"

description = "The latest news about stuff."

def items(self):

return Entry.objects.order_by('-pub_date')[:5]

def item_link(self, item):

return "/qiye/%s/" % item.qiyname

def item_title(self, item):

return item.qiyname

def item_description(self, item):

return item.diz

class AtomLatestEntries(RssLatestEntries):

feed_type = Atom1Feed

这是与之相对应那个的URLconf:

from django.conf.urls.defaults import *

from myproject.feeds import RssLatestEntries, AtomLatestEntries

feeds = {

'rss': RssLatestEntries,

'atom': AtomLatestEntries,

}

urlpatterns = patterns('',

# ...

(r'^feeds/(?P<url>.*)/$', 'django.contrib.syndication.views.feed',

{'feed_dict': feeds}),

# ...

)

Sitemap 框架sitemap 是你服务器上的一个XML文件,它告诉搜索引擎你的页面的更新频率和某些页面相对于其它页面的重要性。 这个信息会帮助搜索引擎索引你的网站。

例如,这是 Django 网站(http://www.djangoproject.com/sitemap.xml)sitemap的一部分:

<?xml version="1.0" encoding="UTF-8"?>

<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">

<url>

<loc>http://www.djangoproject.com/documentation/</loc>

<changefreq>weekly</changefreq>

<priority>0.5</priority>

</url>

<url>

<loc>http://www.djangoproject.com/documentation/0_90/</loc>

<changefreq>never</changefreq>

<priority>0.1</priority>

</url>

...

</urlset>

需要了解更多有关 sitemaps 的信息, 请参见 http://www.sitemaps.org/.

Django sitemap 框架允许你用 Python 代码来表述这些信息,从而自动创建这个XML文件。 To create a sitemap, you just need to write a Sitemap class and point to it in your URLconf.

安装要安装 sitemap 应用程序, 按下面的步骤进行:

将 'django.contrib.sitemaps' 添加到您的 INSTALLED_APPS 设置中.

确保 'django.template.loaders.app_directories.load_template_source' 在您的 TEMPLATE_LOADERS 设置中。 默认情况下它在那里, 所以, 如果你已经改变了那个设置的话, 只需要改回来即可。

确定您已经安装了 sites 框架 (参见第14章).

Note

sitemap 应用程序没有安装任何数据库表. 它需要加入到 INSTALLED_APPS 中的唯一原因是: 这样 load_template_source 模板加载器可以找到默认的模板. The only reason it needs to go into INSTALLED_APPS is so the load_template_source template loader can find the default templates.

Initialization要在您的Django站点中激活sitemap生成, 请在您的 URLconf 中添加这一行:

(r'^sitemap\.xml$', 'django.contrib.sitemaps.views.sitemap', {'sitemaps': sitemaps})

This line tells Django to build a sitemap when a client accesses /sitemap.xml . Note that the dot character in sitemap.xml is escaped with a backslash, because dots have a special meaning in regular expressions.

sitemap文件的名字无关紧要,但是它在服务器上的位置却很重要。 搜索引擎只索引你的sitemap中当前URL级别及其以下级别的链接。 用一个实例来说,如果 sitemap.xml 位于你的根目录,那么它将引用任何的URL。 然而,如果你的sitemap位于 /content/sitemap.xml ,那么它只引用以 /content/ 打头的URL。

sitemap视图需要一个额外的必须的参数: {'sitemaps': sitemaps} . sitemaps should be a dictionary that maps a short section label (e.g., blog or news ) to its Sitemap class (e.g., BlogSitemap or NewsSitemap ). It may also map to an instance of a Sitemap class (e.g., BlogSitemap(some_var)
).

Sitemap 类Sitemap 类展示了一个进入地图站点简单的Python类片断.例如,一个 Sitemap 类能展现所有日志入口,而另外一个能够调度所有的日历事件。 For example, one Sitemap class could represent all the entries of your weblog, while another could represent all of the events in your events calendar.

在最简单的例子中,所有部分可以全部包含在一个 sitemap.xml 中,也可以使用框架来产生一个站点地图,为每一个独立的部分产生一个单独的站点文件。

Sitemap 类必须是 django.contrib.sitemaps.Sitemap 的子类. 他们可以存在于您的代码树的任何地方。

例如假设你有一个blog系统,有一个 Entry 的model,并且你希望你的站点地图包含所有连到你的blog入口的超链接。 你的 Sitemap 类很可能是这样的:

from django.contrib.sitemaps import Sitemap

from mysite.blog.models import Entry

class BlogSitemap(Sitemap):

changefreq = "never"

priority = 0.5

def items(self):

return Entry.objects.filter(is_draft=False)

def lastmod(self, obj):

return obj.pub_date

声明一个 Sitemap 和声明一个 Feed 看起来很类似;这都是预先设计好的。

如同 Feed 类一样, Sitemap 成员也既可以是方法,也可以是属性。 想要知道更详细的内容,请参见上文 《一个复杂的例子》章节。

一个 Sitemap 类可以定义如下 方法/属性:

items (必需 ):提供对象列表。 框架并不关心对象的 类型 ;唯一关心的是这些对象会传递给 location() , lastmod() , changefreq() ,和 priority() 方法。

location (可选): 给定对象的绝对URL。 绝对URL不包含协议名称和域名。 下面是一些例子:

好的: '/foo/bar/' '/foo/bar/'

差的: 'example.com/foo/bar/' 'example.com/foo/bar/'

Bad: 'http://example.com/foo/bar/'

如果没有提供 location , 框架将会在每个 items() 返回的对象上调用 get_absolute_url() 方法.

lastmod (可选): 对象的最后修改日期, 作为一个Python datetime 对象. The object’s last modification date, as a Python datetime object.

changefreq (可选): 对象变更的频率。 可选的值如下(详见Sitemaps文档):

'always'

'hourly'

'daily'

'weekly'

'monthly'

'yearly'

'never'

priority (可选): 取值范围在 0.0 and 1.0 之间,用来表明优先级。

快捷方式sitemap框架提供了一些常用的类。 在下一部分中会看到。

FlatPageSitemapdjango.contrib.sitemaps.FlatPageSitemap 类涉及到站点中所有的flat page,并在sitemap中建立一个入口。 但仅仅只包含 location 属性,不支持 lastmod , changefreq ,或者 priority 。

参见第16章获取有关flat page的更多的内容.

GenericSitemapGenericSitemap 与所有的通用视图一同工作(详见第9章)。

你可以如下使用它,创建一个实例,并通过 info_dict 传递给通用视图。 唯一的要求是字典包含 queryset 这一项。 也可以用 date_field 来指明从 queryset 中取回的对象的日期域。 这会被用作站点地图中的 lastmod 属性。

下面是一个使用 FlatPageSitemap and GenericSiteMap (包括前面所假定的 Entry 对象)的URLconf:

from django.conf.urls.defaults import *

from django.contrib.sitemaps import FlatPageSitemap, GenericSitemap

from mysite.blog.models import Entry

info_dict = {

'queryset': Entry.objects.all(),

'date_field': 'pub_date',

}

sitemaps = {

'flatpages': FlatPageSitemap,

'blog': GenericSitemap(info_dict, priority=0.6),

}

urlpatterns = patterns('',

# some generic view using info_dict

# ...

# the sitemap

(r'^sitemap\.xml$',

'django.contrib.sitemaps.views.sitemap',

{'sitemaps': sitemaps})

)

创建一个Sitemap索引sitemap框架同样可以根据 sitemaps 字典中定义的单独的sitemap文件来建立索引。 用法区别如下:

您在您的URLconf 中使用了两个视图: django.contrib.sitemaps.views.index 和 django.contrib.sitemaps.views.sitemap . django.contrib.sitemaps.views.index and django.contrib.sitemaps.views.sitemap .

django.contrib.sitemaps.views.sitemap 视图需要带一个 section 关键字参数.

这里是前面的例子的相关的 URLconf 行看起来的样子:

(r'^sitemap.xml$',

'django.contrib.sitemaps.views.index',

{'sitemaps': sitemaps}),

(r'^sitemap-(?P<section>.+).xml$',

'django.contrib.sitemaps.views.sitemap',

{'sitemaps': sitemaps})

这将自动生成一个 sitemap.xml 文件, 它同时引用 sitemap-flatpages.xml 和 sitemap-blog.xml . Sitemap 类和 sitemaps 目录根本没有更改.

django系统学习笔记~~(14)session

(13) http://hi.baidu.com/derris/blog/item/80e8eb9558405d40d1135e8e.html
(15) http://hi.baidu.com/derris/blog/item/3b0bd4031e3e8de009fa93fd.html
确定settings.py中,SessionMiddleware 和 INSTALLED_APPS 设置中的'django.contrib.sessions' 没有被注释掉。

简单的测试一下seesion的功能,直接用request.session["sessionName"]引用就可以了,也可以删除del ..

做个实例~~

增加一个登录模板:login_form.html

<html> <body> <form action="" method="post">

<table> <input type="text" name="user">

<input type="password" name="passwd">

</table><input type="submit" value="Submit">

</form></body></html>


urls.py中增加一个对应选项

(r'^login/$', views.login),

views.py中增加对应的处理函数

from django.contrib import auth

def login(request):

# 如果提交form

if request.method == 'POST':

# 测试cookie是否工作:

if request.session.test_cookie_worked():

#如果cookie工作,就删除.

request.session.delete_test_cookie()

# 我们这里需要验证用户

user = auth.authenticate(username=request.POST['user'], password=request.POST['passwd'])

if user is not None and user.is_active:

auth.login(request, user)

return HttpResponse("login correct: " + request.POST['user'] + " : my cookie:" + request.session["mytest"])

else:

auth.logout(request) # 登录不正确,自动退出

return HttpResponse("login incorrect: " + request.POST['user'])

else:

return HttpResponse("需要cookie支持。")


#如果不是post方法,就显示网页.

request.session.set_test_cookie()

request.session["mytest"] = "my test is just like that."

return render_to_response('login_form.html')


运行服务器,访问http://127.0.0.1:8000/login,就可以看到结果。

--

列出你的服务器所有cookie内容.dos下进入到mysite目录,运行manage.py shell

>>> for i in Session.objects.all():

... print i.get_decoded(), i.pk

可以根据pk值进行查询,也可以访问http://127.0.0.1:8000/look可以看到你的sessionid,然后可以单独查询.

>>> s = Session.objects.get(pk="2271b2b1477c49c13ac9774a974229b0")

>>> s.expire_date

datetime.datetime(2010, 4, 2, 0, 0, 0, 0)

>>> s.session_data

u'gAJ9cQFVBm15dGVzdHECVRpteSB0ZXN0IGlzIGp1c3QgbGlrZSB0aGF0LnEDcy44OWFmNmRlZDU0\n

NTczZTk0ZGUyNTkzMjYyODEyNTQ3NA==\n'

>>> s.get_decoded()

{'mytest': 'my test is just like that.'}

session过期默认是2个周,SESSION_EXPIRE_AT_BROWSER_CLOSE 设置为 False , SESSION_COOKIE_AGE 保存多少秒

SESSION_COOKIE_DOMAIN 使用会话cookie(session cookies)的站点。将它设成一个字符串,就好象`` “.example.com”`` 以用于跨站点(cross-domain)的cookie,或`` None`` 以用于单个站点。

SESSION_COOKIE_NAME 会话中使用的cookie的名字。 它可以是任意的字符串。 "sessionid"

SESSION_COOKIE_SECURE 是否在session中使用安全cookie, 如果设置 True , cookie就会标记为安全, 这意味着cookie只会通过HTTPS来传输

django提供认证授权的支持,前面已经在settings.py中打开了. 访问http://127.0.0.1:8000/admin/就可以登录了.

判断授权的用户可以用request.user.is_authenticated().

user的属性

username 必需的,不能多于30个字符。 仅用字母数字式字符(字母、数字和下划线)。

first_name 可选; 少于等于30字符.

last_name 可选; 少于等于30字符.

email 可选. 邮件地址.

password 密码的哈希值,django不保存明码.

is_staff 布尔值. 用户是否拥有网站的管理权限.

is_active 布尔值. 用户是否拥有所有权限,而无需任何显式的权限分配定义用户最后登录的时间,缺省会设置为当前时间

is_superuser Boolean. Designates that this user has all permissions without explicitly assigning them.

last_login 用户上次登录的时间日期。 它被默认设置为当前的日期/时间。

date_joined 账号被创建的日期时间 当账号被创建时,它被默认设置为当前的日期/时间。

通过用户也可以得到用户groups和授权permissions表的引用.

myuser.groups = group_list

# 增加用户到某组:

myuser.groups.add(group1, group2,...)

# 删除某组

myuser.groups.remove(group1, group2,...)

# 删除所有

myuser.groups.clear()

# 授权

myuser.permissions = permission_list

myuser.permissions.add(permission1, permission2, ...)

myuser.permissions.remove(permission1, permission2, ...)

myuser.permissions.clear()

django手工认证.(自己增加一个用户,检查就好.)

>>> from django.contrib import auth

>>> user = auth.authenticate(username='derris', password='xman123')

>>> if user is not None and user.is_active:

... print "Correct!"

... else:

... print "Invalid password."

在视图里面,就可以用auth.login(request, user),完成登录了.

django提供自动的登录视图,只需要指定对应的模板就可以处理。(还是自己处理简单。。。)

from django.contrib.auth.views import login, logout

urlpatterns = patterns('',

# existing patterns here...

(r'^accounts/login/$', login),

(r'^accounts/logout/$', logout),

)

================================ 模板要包括这些东东:next的内容是自动在登录以后重新定向的url(缺省会重定向到 /accounts/profile )。。。

{% if form.errors %}

<p class="error">Sorry, that's not a valid username or password</p>

{% endif %}

<form action="" method="post">

<label for="username">User name:</label>

<input type="text" name="username" value="" id="username">

<label for="password">Password:</label>

<input type="password" name="password" value="" id="password">

<input type="submit" value="login" />

<input type="hidden" name="next" value="{{ next|escape }}" />

</form>

==============================

对于需要登录的视图函数,可以加个修饰符。

from django.contrib.auth.decorators import login_required

@login_required

def my_view(request):

# ...

#如果用户没有登录,就无法访问改页啦,如果想自动到登录页面,就要使用django系统的login模板~~。

检查用户是否有访问资源的权限用:request.user.has_perm('xxxx'))就可以了。权限在admin管理里面可以设置。

也有对应的修饰符:

def user_can_vote(user):

return user.is_authenticated() and user.has_perm("polls.can_vote")

@user_passes_test(user_can_vote, login_url="/login/")

def vote(request):

# Code here can assume a logged-in user with the correct permission.

还有更简单的:

from django.contrib.auth.decorators import permission_required

@permission_required('polls.can_vote', login_url="/login/")

def vote(request):

# ...

后面不打算自己开发用~~简单记录一下:

创建用户使用 create_user 辅助函数创建用户:

>>> from django.contrib.auth.models import User

>>> user = User.objects.create_user(username='john',

... email='jlennon@beatles.com',

... password='glass onion')

在这里, user 是 User 类的一个实例,准备用于向数据库中存储数据。 create_user() 函数并没有在数据库中创建记录,在保存数据之前,你仍然可以继续修改它的属性值。

>>> user.is_staff = True

>>> user.save()

修改密码你可以使用 set_password() 来修改密码:

>>> user = User.objects.get(username='john')

>>> user.set_password('goo goo goo joob')

>>> user.save()

除非你清楚的知道自己在做什么,否则不要直接修改 password 属性。 其中保存的是密码的 加入salt的hash值 ,所以不能直接编辑。

一般来说, User 对象的 password 属性是一个字符串,格式如下:

hashtype$salt$hash

这是哈希类型,salt和哈希本身,用美元符号($)分隔。

hashtype 是 sha1 (默认)或者 md5 ,它是用来处理单向密码哈希的算法,Salt是一个用来加密原始密码来创建哈希的随机字符串,例如: salt is a random string used to salt the raw password to create the hash, for example:

sha1$a1976$a36cc8cbf81742a8fb52e221aaeab48ed7f58ab4

User.set_password() 和 User.check_password() 函数在后台处理和检查这些值。

加了salt是为了防止对单向哈希值进行字典对应查找破解,就算知道salt的算法,也要一个一个的计算,增加破解难度。

创建自己的用户注册功能:

from django import forms

from django.contrib.auth.forms import UserCreationForm

from django.http import HttpResponseRedirect

from django.shortcuts import render_to_response

def register(request):

if request.method == 'POST':

form = UserCreationForm(request.POST)

if form.is_valid():

new_user = form.save()

return HttpResponseRedirect("/books/")

else:

form = UserCreationForm()

return render_to_response("registration/register.html", {

'form': form,

})

这个表单构想了一个叫 registration/register.html 的模板. 这里是一个这个模板的可能的样子的例子:

{% extends "base.html" %}

{% block title %}Create an account{% endblock %}

{% block content %}

<h1>Create an account</h1>

<form action="" method="post">

{{ form.as_p }}

<input type="submit" value="Create the account">

</form>

{% endblock %}

从技术上来说,只有当你使用了 RequestContext 并且 TEMPLATE_CONTEXT_PROCESSORS 设置包含了 "django.core.context_processors.auth" (默认情况就是如此)时,这些变量才能在模板context中使用。

当使用 RequestContext 时, 当前用户 (是一个 User 实例或一个 AnonymousUser 实例) 存储在模板变量 {{ user }} 中:

{% if user.is_authenticated %}

<p>Welcome, {{ user.username }}. Thanks for logging in.</p>

{% else %}

<p>Welcome, new user. Please log in.</p>

{% endif %}

这些用户的权限信息存储在 {{ perms }} 模板变量中。

你有两种方式来使用 perms 对象。 你可以使用类似于 {{ perms.polls }} 的形式来检查,对于某个特定的应用,一个用户是否具有 任意 权限;你也可以使用 {{ perms.polls.can_vote }} 这样的形式,来检查一个用户是否拥有特定的权限。

这样你就可以在模板中的 {% if %} 语句中检查权限:

{% if perms.polls %}

<p>You have permission to do something in the polls app.</p>

{% if perms.polls.can_vote %}

<p>You can vote!</p>

{% endif %}

{% else %}

<p>You don't have permission to do anything in the polls app.</p>

{% endif %}

消息系统会为给定的用户接收消息。 每个消息都和一个 User 相关联。

在每个成功的操作以后,Django的admin管理接口就会使用消息机制。 例如,当你创建了一个对象,你会在admin页面的顶上看到 The object was created successfully 的消息。

你也可以使用相同的API在你自己的应用中排队接收和显示消息。 API非常地简单:

要创建一条新的消息,使用 user.message_set.create(message='message_text') 。

要获得/删除消息,使用 user.get_and_delete_messages() ,这会返回一个 Message 对象的列表,并且从队列中删除返回的项。

在例子视图中,系统在创建了播放单(playlist)以后,为用户保存了一条消息。

def create_playlist(request, songs):

# Create the playlist with the given songs.

# ...

request.user.message_set.create(

message="Your playlist was added successfully."

)

return render_to_response("playlists/create.html",

context_instance=RequestContext(request))

当使用 RequestContext ,当前登录的用户以及他(她)的消息,就会以模板变量 {{ messages }} 出现在模板的context中。

{% if messages %}

<ul>

{% for message in messages %}

<li>{{ message }}</li>

{% endfor %}

</ul>

{% endif %}

django系统学习笔记~~(15)缓存

(14) http://hi.baidu.com/derris/blog/item/9a15e0fdb22d9e49d7887d71.html
缓存工作原理:

接到一个链接请求URL,尝试在缓存中搜索。

如果存在:

返回缓存内容。

否则:

生成指定页面

保存到缓存中

返回页面

------------

访问前面的例子:http://127.0.0.1:8000/time/

每次访问都会返回当前时间,就是说每次访问都是变化的。

settings.py文件中增加一个文件系统的全站缓存。

CACHE_BACKEND = 'file://d:/foo'

更改middlewar_classes的选项(注意顺序很重要,先update再fetch)。

MIDDLEWARE_CLASSES = (

'django.middleware.cache.UpdateCacheMiddleware',

'django.middleware.common.CommonMiddleware',

'django.contrib.sessions.middleware.SessionMiddleware',

'django.middleware.locale.LocaleMiddleware',

'django.contrib.auth.middleware.AuthenticationMiddleware',

'django.middleware.cache.FetchFromCacheMiddleware',

)


然后再访问:http://127.0.0.1:8000/time/ ,被缓存了,就不会再变化了。。。

当然这个缓存的很无聊。。。这里故意用他测试的,注释掉吧。

#'django.middleware.cache.UpdateCacheMiddleware',

#'django.middleware.cache.FetchFromCacheMiddleware',


访问:http://127.0.0.1:8000/time/, 又开始变化了。

如果全局缓存的时候注意get和post的页面是不区分的,所以不可以使用~~

对于不想缓存的页面,用@never_cache修饰视图方法就可以。

测试一下单个视图的缓存。

urls.py中,

增加:

from django.views.decorators.cache import cache_page

更改time对应项

('^time/$', cache_page(current_datetime)),

再访问:http://127.0.0.1:8000/time/, 又不变化,被缓存了~~

也可以在视图中用参数,不过感觉在urls中大体感好些~~

@cache_page(60 * 15)

def current_datetime(request):

cache_page后面可以加时间参数,定时刷新一下。

cache_page(my_view, 10)) 缓存10秒。(要把原来的缓存清掉。)

如果是0,就不进行缓存,不知道处理方法是不是和@never_cache一样?

对于上游isp提供商或者浏览器客户端缓存数据进行控制,可以使用vary头。

比如在视图上用修饰符:

@vary_on_headers('User-Agent', 'Cookie')

def my_view(request):

# ...

该段代码通知上游缓存对两者都进行不同操作,也就是说 user-agent 和 cookie 的每种组合都应获取自己的缓存值。 举例来说,使用 Mozilla 作为 user-agent 而 foo=bar 作为 cookie 值的请求应该和使用 Mozilla 作为 user-agent 而 foo=ham 的请求应该被视为不同请求

因为对于cookie缓存太常用,所以对于@vary_on_headers('Cookie')有个简单写法:@vary_on_cookie。

对于敏感数据的缓存~~

from django.views.decorators.cache import cache_control

@cache_control(private=True)

def my_view(request):

# ...

对于大量数据传送,可以在中间件中进行压缩,用的很少把。。。

django.middleware.gzip.GZipMiddleware

---------------------------------

在模板里面可以用标签使用缓存数据:

{% load cache %}

{% cache 500 sidebar request.user.username %}

.. sidebar for logged in user ..

{% endcache %}

cache 时间 名字 对应用户

底层api

>>> from django.core.cache import cache

>>> cache.set('my_key', 'hello, world!', 30)

>>> cache.get('my_key')

'hello, world!'

------------------------------------

缓存选择在你的settings文件的 CACHE_BACKEND 设置中,如果你使用缓存但没有指定 CACHE_BACKEND ,Django将默认使用 simple:///

内存缓存Memcached

CACHE_BACKEND = 'memcached://127.0.0.1:11211/'

Memcached的一个极好的特性是它在多个服务器分享缓存的能力,这意味着你可以在多台机器上运行Memcached进程,程序将会把这组机器当作一个*单独的*缓存,而不需要在每台机器上复制缓存值

CACHE_BACKEND = 'memcached://172.19.26.240:11211;172.19.26.242:11212;172.19.26.244:11213/'

数据库缓存

python manage.py createcachetable [cache_table_name]

CACHE_BACKEND = 'db://my_cache_table'

文件系统缓存

CACHE_BACKEND = 'file:///var/tmp/django_cache'

本地内存缓存

CACHE_BACKEND = 'locmem:///'

目前没有跨进程共享,所以不是很好的选择,但是很有发展前途。

仿缓存

开发测试的时候用~~

CACHE_BACKEND = 'dummy:///'

CACHE_BACKEND参数每个缓存后端都可能使用参数,它们在CACHE_BACKEND设置中以查询字符串形式给出,合法的参数为: 他们给予查询字符串的CACHE_BACKEND设置样式。 有效参数如下:

timeout:用于缓存的过期时间,以秒为单位。 这个参数默认被设置为300秒(五分钟)

filesystemmax_entries:对于locmem,database和后端,在高速缓存允许的最大条目数之前的旧值将被删除。 这个参数默认是300.

cull_frequency :当达到 max_entries 的时候,被接受的访问的比率。 实际的比率是 1/cull_frequency ,所以设置cull_frequency=2就是在达到 max_entries 的时候去除一半数量的缓存

把 cull_frequency 的值设置为 0 意味着当达到 max_entries 时,缓存将被清空。 这将以很多缓存丢失为代价,大大提高接受访问的速度。

在这个例子中, timeout 被设成 60

CACHE_BACKEND = "memcached://127.0.0.1:11211/?timeout=60"

而在这个例子中, timeout 设为 30 而 max_entries 为 400 :

CACHE_BACKEND = "locmem:///?timeout=30&max_entries=400"

其中,非法的参数与非法的参数值都将被忽略。

站点级 Cache一旦高速缓存设置,最简单的方法是使用缓存缓存整个网站。您需要添加’django.middleware.cache.UpdateCacheMiddleware’和 ‘django.middleware.cache.FetchFromCacheMiddleware’您的MIDDLEWARE_CLASSES设置,在这个例子为:

MIDDLEWARE_CLASSES = (

'django.middleware.cache.UpdateCacheMiddleware',

'django.middleware.common.CommonMiddleware',

'django.middleware.cache.FetchFromCacheMiddleware',

)

注意:

不,这不是一个错字: 中间件的更新,必须先在列表中,而获取的中间件,必须最后。 的细节有点模糊,但看到下面的MIDDLEWARE_CLASSES订阅如果您想看到完整的故事。

然后,在你的Django settings文件里加入下面所需的设置:

CACHE_MIDDLEWARE_SECONDS :每个页面应该被缓存的秒数

CACHE_MIDDLEWARE_KEY_PREFIX :如果缓存被多个使用相同Django安装的网站所共享,那么把这个值设成当前网站名,或其他能代表这个Django实例的唯一字符串,以避免key发生冲突。 如果你不在意的话可以设成空字符串。

缓存中间件缓存每个没有GET或者POST参数的页面,即如果用户请求页面并在查询字符串里传递GET参数或者POST参数,中间件将不会尝试得到缓存版本的页面,如果你打算使用整站缓存,设计你的程序时牢记这点,例如,不要使用拥有查询字符串的URLs,除非那些页面可以不缓存或者,如果CACHE_MIDDLEWARE_ANONYMOUS_ONLY设置为True,只有匿名请求(即不是由登录的用户)将被缓存作出的声明。 如果想取消用户相关页面(user-specific pages)的缓存,例如Djangos 的管理界面,这是一种既简单又有效的方法。
CACHE_MIDDLEWARE_ANONYMOUS_ONLY,你应该确保你已经启动AuthenticationMiddleware。

此外,缓存中间件自动设置在每个中HttpResponse几个标题:

当一个新(没缓存的)版本的页面被请求时设置Last-Modified头部为当前日期/时间

设置Expires头部为当前日期/时间加上定义的CACHE_MIDDLEWARE_SECONDS

设置Cache-Control头部来给页面一个最大的时间—再一次,根据CACHE_MIDDLEWARE_SECONDS设置

视图级缓存更加颗粒级的缓存框架使用方法是对单个视图的输出进行缓存。 django.views.decorators.cache defines a cache_page decorator that will automatically cache the view’s response for you. 他是很容易使用的:

from django.views.decorators.cache import cache_page

def my_view(request):

# ...

my_view = cache_page(my_view, 60 * 15)

Or, using Python 2.4’s decorator syntax:

@cache_page(60 * 15)

def my_view(request):

# ...

cache_page 只接受一个参数: 以秒计的缓存超时。 在前例中, “my_view()” 视图的结果将被缓存 15 分钟。 (注意: 为了提高可读性,该参数被书写为 60 * 15 。 60 * 15 将被计算为 900 ,也就是说15 分钟乘以每分钟 60 秒。)

和站点缓存一样,视图缓存与 URL 无关。 如果多个 URL 指向同一视图,每个视图将会分别缓存。 继续 my_view 范例,如果 URLconf 如下所示:

urlpatterns = ('',

(r'^foo/(\d{1,2})/$', my_view),

)

那么正如你所期待的那样,发送到 /foo/1/ 和 /foo/23/ 的请求将会分别缓存。 但一旦发出了特定的请求(如:

在 URLconf 中指定视图缓存前一节中的范例将视图硬编码为使用缓存,因为 cache_page 在适当的位置对 my_view 函数进行了转换。 该方法将视图与缓存系统进行了耦合,从几个方面来说并不理想。 例如,你可能想在某个无缓存的站点中重用该视图函数,或者你可能想将该视图发布给那些不想通过缓存使用它们的人。 解决这些问题的方法是在 URLconf 中指定视图缓存,而不是紧挨着这些视图函数本身来指定。

完成这项工作非常简单: 在 URLconf 中用到这些视图函数的时候简单地包裹一个 cache_page 。以下是刚才用到过的 URLconf : Here’s the old URLconf from earlier:

urlpatterns = ('',

(r'^foo/(\d{1,2})/$', my_view),

)

以下是同一个 URLconf ,不过用 cache_page 包裹了 my_view :

from django.views.decorators.cache import cache_page

urlpatterns = ('',

(r'^foo/(\d{1,2})/$', cache_page(my_view, 60 * 15)),

)

如果采取这种方法, 不要忘记在 URLconf 中导入 cache_page .
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: