The Django Book

Chapter 14: Other Contributed Subframeworks

第十四章 集成的子框架

One of the many strengths of Python is its batteries included philosophy: when you install Python, it comes with a large standard library of packages that you can start using immediately, without having to download anything else. Django aims to follow this philosophy, and it includes its own standard library of add-ons useful for common Web development tasks. This chapter covers that collection of add-ons.

ifRqur <a href=”http://boillucronlx.com/“>boillucronlx</a>, [url=http://pfkayzbowvrx.com/]pfkayzbowvrx[/url], [link=http://onajxszobhba.com/]onajxszobhba[/link], http://spfvpxdqczbk.com/

The Django Standard Library

Django标准库

Djangos standard library lives in the package django.contrib . Within each subpackage is a separate piece of add-on functionality. These pieces are not necessarily related, but some django.contrib subpackages may require other ones.

Django的标准库存放在 django.contrib 包中。每个子包都是一个独立的附加功能包。 它们互相之间一般没有必然的关联,但是有些 django.contrib 子包可能依赖其他的包。

Theres no hard requirement for the types of functionality in django.contrib . Some of the packages include models (and hence require you to install their database tables into your database), but others consist solely of middleware or template tags.

django.contrib 中对函数的类型并没有强制要求 。其中一些包中带有模型(因此需要你在数据库中安装对应的数据表),但其它一些由独立的中间件及模板标签组成。

The single characteristic the django.contrib packages have in common is this: if you were to remove the django.contrib package entirely, you could still use Djangos fundamental features with no problems. When the Django developers add new functionality to the framework, they use this rule of thumb in deciding whether the new functionality should live in django.contrib or elsewhere.

django.contrib 开发包共有的特性是:就算你将整个 django.contrib 开发包删除,你依然可以使用 Django 的基础功能而不会遇到任何问题。当 Django 开发者向框架增加新功能的时,他们会严格根据这一教条来决定是否把新功能放入 django.contrib 中。

django.contrib consists of these packages:

django.contrib 由以下开发包组成:

  • admin : The automatic admin site. See Chapters 6 and 18.

  • admin : 自动化的站点管理工具。请查看第6章和第18章

  • auth : Djangos authentication framework. See Chapter 12.

  • auth : Django的用户验证框架。请查看第12章

  • comments : A comments application. This application is currently under heavy development and thus couldnt be covered fully in time for this books publication. Check the Django Web site for the latest information about the comments application.

  • comments : 一个评论应用,目前,这个应用正在紧张的开发中,因此在本书出版的时候还不能给出一个完整的说明,关于这个应用的更多信息请参见Django的官方网站.

  • contenttypes : A framework for hooking into types of content, where each installed Django model is a separate content type. This framework is used internally by other contrib applications and is mostly intended for very advanced Django developers. Those developers should find out more about this application by reading the source code in django/contrib/contenttypes/ .

  • contenttypes : 这是一个用于文档类型钩子的框架,每个安装的Django模块作为一种独立的文档类型。这个框架主要在Django内部被其他应用使用,它主要面向Django的高级开发者。可以通过阅读源码来了解关于这个框架的更多信息,源码的位置在 django/contrib/contenttypes/ .

  • csrf : Protection against Cross-Site Request Forgery (CSRF). See the later section titled CSRF Protection.

  • csrf : 这个模块用来防御跨站请求伪造(CSRF).参见后面标题为”CSRF 防御”的小节。

  • flatpages : A framework for managing simple flat HTML content in a database. See the later section titled Flatpages.

  • flatpages : 一个在数据库中管理单一HTML内容的模块,参见后面标题为“Flatpages”的小节。

  • humanize : A set of Django template filters useful for adding a human touch to data. See the later section titled Humanizing Data.

  • humanize : 一系列 Django 模块过滤器,用于增加数据的人性化。参阅稍后的章节《人性化数据》。

  • markup : A set of Django template filters that implement a number of common markup languages. See the later section titled Markup Filters.

  • markup : 一系列的 Django 模板过滤器,用于实现一些常用标记语言。参阅后续章节《标记过滤器》。

  • redirects : A framework for managing redirects. See the later section titled Redirects.

  • redirects : 用来管理重定向的框架。参见后面标题为《重定向》的小节。

  • sessions : Djangos session framework. See Chapter 12.

  • sessions : Django 的会话框架,参见12章。

  • sitemaps : A framework for generating sitemap XML files. See Chapter 11.

  • sitemaps : 用来生成网站地图的 XML 文件的框架。参见 11 章。

  • sites : A framework that lets you operate multiple Web sites from the same database and Django installation. See the next section, Sites.

  • sites : 一个让你可以在同一个数据库与 Django 安装中管理多个网站的框架。参见下一节:站点。

  • syndication : A framework for generating syndication feeds in RSS and Atom. See Chapter 11.

  • syndication : 一个用 RSS 和 Atom 来生成聚合订阅源的的框架。参阅第 11 章。

The rest of this chapter goes into detail about each django.contrib package that we havent yet covered in this book.

本章接下来将详细描述前面没有介绍过的 django.contrib 开发包内容。

Sites

多个站点

Djangos sites system is a generic framework that lets you operate multiple Web sites from the same database and Django project. This is an abstract concept, and it can be tricky to understand, so well start with a couple of scenarios where it would be useful.

Django 的多站点系统是一种通用框架,它让你可以在同一个数据库和同一个Django项目下操作多个网站。这是一个抽象概念,理解起来可能有点困难,因此我们从几个让它能派上用场的实际情景入手。

Scenario 1: Reusing Data on Multiple Sites

情景1:对多个站点重用数据

As we explained in Chapter 1, the Django-powered sites LJWorld.com and Lawrence.com are operated by the same news organization: the Lawrence Journal-World newspaper in Lawrence, Kansas. LJWorld.com focuses on news, while Lawrence.com focuses on local entertainment. But sometimes editors want to publish an article on both sites.

正如我们在第一章里所讲,Django 构建的网站 LJWorld.com 和 Lawrance.com 是用由同一个新闻组织控制的:肯萨斯州劳伦斯市的 劳伦斯日报世界 报纸。 LJWorld.com 主要做新闻,而 Lawrence.com 关注本地娱乐。然而有时,编辑可能需要把一篇文章发布到 两个 网站上。

The brain-dead way of solving the problem would be to use a separate database for each site and to require site producers to publish the same story twice: once for LJWorld.com and again for Lawrence.com. But thats inefficient for site producers, and its redundant to store multiple copies of the same story in the database.

解决此问题的死脑筋方法可能是使用每个站点分别使用不同的数据库,然后要求站点维护者把同一篇文章发布两次:一次为 LJWorld.com,另一次为Lawrence.com。但这对站点管理员来说是低效率的,而且为同一篇文章在数据库里保留多个副本也显得多余。

The better solution? Both sites use the same article database, and an article is associated with one or more sites via a many-to-many relationship. The Django sites framework provides the database table to which articles can be related. Its a hook for associating data with one or more sites.

更好的解决方案?两个网站用的是同一个文章数据库,并将每一篇文章与一个或多个站点用多对多关系关联起来。Django 站点框架提供数据库记载哪些文章可以被关联。它是一个把数据与一个或多个站点关联起来的钩子。

Scenario 2: Storing Your Site Name/Domain in One Place

情景2:把你的网站名称/域存储到唯一的位置

LJWorld.com and Lawrence.com both have e-mail alert functionality, which lets readers sign up to get notifications when news happens. Its pretty basic: a reader signs up on a Web form, and he immediately gets an e-mail saying, Thanks for your subscription.

LJWorld.com 和 Lawrence.com 都有邮件提醒功能,使读者注册后可以在新闻发生后立即收到通知。这是一种完美的的机制:某读者提交了注册表单,然后马上就受到一封内容是“感谢您的注册”的邮件。

It would be inefficient and redundant to implement this signup-processing code twice, so the sites use the same code behind the scenes. But the Thank you for your subscription notice needs to be different for each site. By using Site objects, we can abstract the thank-you notice to use the values of the current sites name (e.g., 'LJWorld.com' ) and domain (e.g., 'www.ljworld.com' ).

把这个注册过程的代码实现两遍显然是低效、多余的,因此两个站点在后台使用相同的代码。但感谢注册的通知在两个网站中需要不同。通过使用 Site 对象,我们通过使用当前站点的 name (例如 'LJWorld.com' )和 domain (例如 'www.ljworld.com' )可以把感谢通知抽提出来。

The Django sites framework provides a place for you to store the name and domain for each site in your Django project, which means you can reuse those values in a generic way.

Django 的多站点框架为你提供了一个位置来存储 Django 项目中每个站点的 namedomain ,这意味着你可以用同样的方法来重用这些值。

How to Use the Sites Framework

如何使用多站点框架

The sites framework is more a series of conventions than a framework. The whole thing is based on two simple concepts:

多站点框架与其说是一个框架,不如说是一系列约定。所有的一切都基于两个简单的概念:

  • The Site model, found in django.contrib.sites , has domain and name fields.

  • 位于 django.contrib.sitesSite 模型有 domainname 两个字段。

  • The SITE_ID setting specifies the database ID of the Site object associated with that particular settings file.

  • SITE_ID 设置指定了与特定配置文件相关联的 Site 对象之数据库 ID。

How you use these two concepts is up to you, but Django uses them in a couple of ways automatically via simple conventions.

如何运用这两个概念由你决定,但 Django 是通过几个简单的约定自动使用的。

To install the sites application, follow these steps:

安装多站点应用要执行以下几个步骤:

  1. Add 'django.contrib.sites' to your INSTALLED_APPS .

  1. 'django.contrib.sites' 加入到 INSTALLED_APPS 中。

  1. Run the command manage.py syncdb to install the django_site table into your database.

  1. 运行 manage.py syncdb 命令将 django_site 表安装到数据库中。

  1. Add one or more Site objects, either through the Django admin site or via the Python API. Create a Site object for each site/domain that this Django project powers.

  1. 通过 Django 管理后台或通过 Python API 添加一个或者多个 ‘Site’ 对象。为该 Django 项目支撑的每个站(或域)创建一个 Site 对象。

  1. Define the SITE_ID setting in each of your settings files. This value should be the database ID of the Site object for the site powered by that settings file.

  1. 在每个设置文件中定义一个 SITE_ID 变量。该变量值应当是该设置文件所支撑的站点之 Site 对象的数据库 ID 。

The Sites Frameworks Capabilities

多站点框架的功能

The sections that follow describe the various things you can do with the sites framework.

下面几节讲述的是用多站点框架能够完成的几项工作。

Reusing Data on Multiple Sites
多个站点的数据重用

To reuse data on multiple sites, as explained in the first scenario, just create a ManyToManyField to Site in your models, for example:

正如在情景一中所解释的,要在多个站点间重用数据,仅需在模型中为 Site 添加一个 多对多字段 即可,例如:

from django.db import models
from django.contrib.sites.models import Site

class Article(models.Model):
    headline = models.CharField(maxlength=200)
    # ...
    sites = models.ManyToManyField(Site)

Thats the infrastructure you need to associate articles with multiple sites in your database. With that in place, you can reuse the same Django view code for multiple sites. Continuing the Article model example, heres what an article_detail view might look like:

这是在数据库中为多个站点进行文章关联操作的基础步骤。在适当的位置使用该技术,你可以在多个站点中重复使用同一段 Django 视图代码。继续 Article 模型范例,下面是一个可能的 article_detail 视图:

from django.conf import settings

def article_detail(request, article_id):
    try:
        a = Article.objects.get(id=article_id, sites__id=settings.SITE_ID)
    except Article.DoesNotExist:
        raise Http404
    # ...

This view function is reusable because it checks the articles site dynamically, according to the value of the SITE_ID setting.

该视图方法是可重用的,因为它根据 SITE_ID 设置的值动态检查 articles 站点。

For example, say LJWorld.coms settings file has a SITE_ID set to 1 , and Lawrence.coms settings file has a SITE_ID set to 2 . If this view is called when LJWorld.coms settings file is active, then it will limit the article lookup to articles in which the list of sites includes LJWorld.com.

例如, LJWorld.coms 设置文件中有有个 SITE_ID 设置为 1 ,而 Lawrence.coms 设置文件中有个 SITE_ID 设置为 2 。如果该视图在 LJWorld.coms 处于激活状态时被调用,那么它将把查找范围局限于站点列表包括 LJWorld.com 在内的文章。

Associating Content with a Single Site
将内容与单一站点相关联

Similarly, you can associate a model to the Site model in a many-to-one relationship using ForeignKey .

同样,你也可以使用 外键 在多对一关系中将一个模型关联到 Site 模型。

For example, if an article is allowed on only a single site, you could use a model like this:

举例来说,如果某篇文章仅仅能够出现在一个站点上,你可以使用下面这样的模型:

from django.db import models
from django.contrib.sites.models import Site

class Article(models.Model):
    headline = models.CharField(maxlength=200)
    # ...
    site = models.ForeignKey(Site)

This has the same benefits as described in the last section.

这与前一节中介绍的一样有益。

Hooking Into the Current Site from Views
从视图钩挂当前站点

On a lower level, you can use the sites framework in your Django views to do particular things based on the site in which the view is being called, for example:

在底层,通过在 Django 视图中使用多站点框架,你可以让视图根据调用站点不同而完成不同的工作,例如:

from django.conf import settings

def my_view(request):
    if settings.SITE_ID == 3:
        # Do something.
    else:
        # Do something else.

Of course, its ugly to hard-code the site IDs like that. A slightly cleaner way of accomplishing the same thing is to check the current sites domain:

当然,像那样对站点 ID 进行硬编码是比较难看的。略为简洁的完成方式是查看当前的站点域:

from django.conf import settings
from django.contrib.sites.models import Site

def my_view(request):
    current_site = Site.objects.get(id=settings.SITE_ID)
    if current_site.domain == 'foo.com':
        # Do something
    else:
        # Do something else.

The idiom of retrieving the Site object for the value of settings.SITE_ID is quite common, so the Site models manager (Site.objects ) has a get_current() method. This example is equivalent to the previous one:

Site 对象中获取 settings.SITE_ID 值的做法比较常见,因此 Site 模型管理器 (Site.objects ) 具备一个 get_current() 方法。下面的例子与前一个是等效的:

from django.contrib.sites.models import Site

def my_view(request):
    current_site = Site.objects.get_current()
    if current_site.domain == 'foo.com':
        # Do something
    else:
        # Do something else.

Note

注意

In this final example, you dont have to import django.conf.settings .

在这个最后的例子里,你不用导入 django.conf.settings

Getting the Current Domain for Display
获取当前域用于呈现

For a DRY (Dont Repeat Yourself) approach to storing your sites name and domain name, as explained in Scenario 2: Storing Your Site Name/Domain in One Place, just reference the name and domain of the current Site object. For example:

正如情景二中所解释的那样,对于储存站名和域名的 DRY (Dont Repeat Yourself) 方法(在一个位置储存站名和域名)来说,只需引用当前 Site 对象的 namedomain 。例如:

from django.contrib.sites.models import Site
from django.core.mail import send_mail

def register_for_newsletter(request):
    # Check form values, etc., and subscribe the user.
    # ...
    current_site = Site.objects.get_current()
    send_mail('Thanks for subscribing to %s alerts' % current_site.name,
        'Thanks for your subscription. We appreciate it.\n\n-The %s team.' % current_site.name,
        'editor@%s' % current_site.domain,
        [user_email])
    # ...

Continuing our ongoing example of LJWorld.com and Lawrence.com, on Lawrence.com this e-mail has the subject line Thanks for subscribing to lawrence.com alerts. On LJWorld.com, the e-mail has the subject line Thanks for subscribing to LJWorld.com alerts. This same site-specific behavior is applied to the e-mails message body.

继续我们正在讨论的 LJWorld.com 和 Lawrence.com 例子,在Lawrence.com 该邮件的标题行是“感谢注册 Lawrence.com 提醒信件”。在 LJWorld.com ,该邮件标题行是“感谢注册 LJWorld.com 提醒信件”。这种站点关联行为方式对邮件信息主体也同样适用。

An even more flexible (but more heavyweight) way of doing this would be to use Djangos template system. Assuming Lawrence.com and LJWorld.com have different template directories (TEMPLATE_DIRS ), you could simply delegate to the template system like so:

完成这项工作的一种更加灵活(但重量级也更大)的方法是使用 Django 的模板系统。假定 Lawrence.com 和 LJWorld.com 各自拥有不同的模板目录( TEMPLATE_DIRS ),你可将工作轻松地转交给模板系统,如下所示:

from django.core.mail import send_mail
from django.template import loader, Context

def register_for_newsletter(request):
    # Check form values, etc., and subscribe the user.
    # ...
    subject = loader.get_template('alerts/subject.txt').render(Context({}))
    message = loader.get_template('alerts/message.txt').render(Context({}))
    send_mail(subject, message, 'do-not-reply@example.com', [user_email])
    # ...

In this case, you have to create subject.txt and message.txt templates in both the LJWorld.com and Lawrence.com template directories. As mentioned previously, that gives you more flexibility, but its also more complex.

本例中,你不得不在 LJWorld.com 和 Lawrence.com 的模板目录中都创建一份 subject.txtmessage.txt 模板。正如之前所说,该方法带来了更大的灵活性,但也带来了更多复杂性。

Its a good idea to exploit the Site objects as much as possible to remove unneeded complexity and redundancy.

尽可能多的利用 Site 对象是减少不必要的复杂、冗余工作的好办法。

Getting the Current Domain for Full URLs
获取当前域的完整 URL

Djangos get_absolute_url() convention is nice for getting your objects URLs without the domain name, but in some cases you might want to display the full URL with http:// and the domain and everything for an object. To do this, you can use the sites framework. Heres a simple example:

Django 的 get_absolute_url() 约定对与获取不带域名的对象 URL 非常理想,但在某些情形下,你可能想显示某个对象带有 http:// 和域名以及所有部分的完整 URL 。要完成此工作,你可以使用多站点框架。下面是个简单的例子:

>>> from django.contrib.sites.models import Site
>>> obj = MyModel.objects.get(id=3)
>>> obj.get_absolute_url()
'/mymodel/objects/3/'
>>> Site.objects.get_current().domain
'example.com'
>>> 'http://%s%s' % (Site.objects.get_current().domain, obj.get_absolute_url())
'http://example.com/mymodel/objects/3/'

CurrentSiteManager

当前站点管理器

If Site``s play a key role in your application, consider using the helpful ``CurrentSiteManager in your model(s). Its a model manager (see Appendix B) that automatically filters its queries to include only objects associated with the current Site .

如果 站点 在你的应用中扮演很重要的角色,请考虑在你的模型中使用方便的 CurrentSiteManager 。这是一个模型管理器(见附录B),它会自动过滤使其只包含与当前 站点 相关联的对象。

Use CurrentSiteManager by adding it to your model explicitly. For example:

通过显示地将 CurrentSiteManager 加入模型中以使用它。例如:

from django.db import models
from django.contrib.sites.models import Site
from django.contrib.sites.managers import CurrentSiteManager

class Photo(models.Model):
    photo = models.FileField(upload_to='/home/photos')
    photographer_name = models.CharField(maxlength=100)
    pub_date = models.DateField()
    site = models.ForeignKey(Site)
    objects = models.Manager()
    on_site = CurrentSiteManager()

With this model, Photo.objects.all() will return all Photo objects in the database, but Photo.on_site.all() will return only the Photo objects associated with the current site, according to the SITE_ID setting.

通过该模型, Photo.objects.all() 将返回数据库中所有的 Photo 对象,而 Photo.on_site.all() 仅根据 SITE_ID 设置返回与当前站点相关联的 Photo 对象。

In other words, these two statements are equivalent:

换言之,以下两条语句是等效的:

Photo.objects.filter(site=settings.SITE_ID)
Photo.on_site.all()

How did CurrentSiteManager know which field of Photo was the Site ? It defaults to looking for a field called site . If your model has a ForeignKey or ManyToManyField called something other than site , you need to explicitly pass that as the parameter to CurrentSiteManager . The following model, which has a field called publish_on , demonstrates this:

CurrentSiteManager 是如何知道 Photo 的哪个字段是 Site 呢?缺省情况下,它会查找一个叫做 site 的字段。如果模型中有个 外键多对多字段 叫做 site 之外 的名字,你必须显示地将它作为参数传递给 CurrentSiteManager 。下面的模型中有个叫做 publish_on 的字段,如下所示:

from django.db import models
from django.contrib.sites.models import Site
from django.contrib.sites.managers import CurrentSiteManager

class Photo(models.Model):
    photo = models.FileField(upload_to='/home/photos')
    photographer_name = models.CharField(maxlength=100)
    pub_date = models.DateField()
    publish_on = models.ForeignKey(Site)
    objects = models.Manager()
    on_site = CurrentSiteManager('publish_on')

If you attempt to use CurrentSiteManager and pass a field name that doesnt exist, Django will raise a ValueError .

如果试图使用 CurrentSiteManager 并传入一个不存在的字段名, Django 将引发一个 ValueError 异常。

Note

注意事项

Youll probably want to keep a normal (non-site-specific) Manager on your model, even if you use CurrentSiteManager . As explained in Appendix B, if you define a manager manually, then Django wont create the automatic objects = models.Manager() manager for you.

即便是已经使用了 CurrentSiteManager ,你也许还想在模型中拥有一个正常的(非站点相关)的 管理器 。正如在附录 B 中所解释的,如果你手动定义了一个管理器,那么 Django 不会为你创建全自动的 objects = models.Manager() 管理器。

Also, certain parts of Django namely, the Django admin site and generic views use whichever manager is defined first in the model, so if you want your admin site to have access to all objects (not just site-specific ones), put objects = models.Manager() in your model, before you define CurrentSiteManager .

同样,Django 的特定部分——即 Django 超级管理站点和通用视图——使用的管理器 首先 在模型中定义,因此如果希望超级管理站点能够访问所有对象(而不是仅仅站点特有对象),请于定义 CurrentSiteManager 之前在模型中放入 objects = models.Manager()

How Django Uses the Sites Framework

Django如何使用多站点框架

Although its not required that you use the sites framework, its strongly encouraged, because Django takes advantage of it in a few places. Even if your Django installation is powering only a single site, you should take a few seconds to create the site object with your domain and name , and point to its ID in your SITE_ID setting.

尽管并不是必须的,我们还是强烈建议使用多站点框架,因为 Django 在几个地方利用了它。即使只用 Django 来支持单个网站,你也应该花一点时间用 domainname 来创建站点对象,并将 SITE_ID 设置指向它的 ID 。

Heres how Django uses the sites framework:

以下讲述的是 Django 如何使用多站点框架:

  • In the redirects framework (see the later section Redirects), each redirect object is associated with a particular site. When Django searches for a redirect, it takes into account the current SITE_ID .

  • 在重定向框架中(见后面的重定向一节),每一个重定向对象都与一个特定站点关联。当 Django 搜索重定向的时候,它会考虑当前的 SITE_ID

  • In the comments framework, each comment is associated with a particular site. When a comment is posted, its site is set to the current SITE_ID , and when comments are listed via the appropriate template tag, only the comments for the current site are displayed.

  • 在注册框架中,每个注释都与特定站点相关。每个注释被张贴时,其 site 被设置为当前的 SITE_ID ,而当通过适当的模板标签列出注释时,只有当前站点的注释将会显示。

  • In the flatpages framework (see the later section Flatpages), each flatpage is associated with a particular site. When a flatpage is created, you specify its site , and the flatpage middleware checks the current SITE_ID in retrieving flatpages to display.

  • 在 flatpages 框架中 (参见后面的 Flatpages 一节),每个 flatpage 都与特定的站点相关联。创建 flatpage 时,你都将指定它的 site ,而 flatpage 中间件在获取 flatpage 以显示它的过程中,将查看当前的 SITE_ID

  • In the syndication framework (see Chapter 11), the templates for title and description automatically have access to a variable {{ site }} , which is the Site object representing the current site. Also, the hook for providing item URLs will use the domain from the current Site object if you dont specify a fully qualified domain.

  • 在 syndication 框架中(参阅第 11 章), titledescription 的模板自动访问变量 {{ site }} ,它就是代表当前着桨的 Site 对象。而且,如果你不指出一个完全合格的domain的话,提供目录URLS的钩子将会使用当前“Site”对象的domain。

  • In the authentication framework (see Chapter 12), the django.contrib.auth.views.login view passes the current Site name to the template as {{ site_name }} .

  • 在身份验证框架(参见第 12 章)中, django.contrib.auth.views.login 视图将当前 Site 名称作为 {{ site_name }} 传递给模板。

Flatpages

Flatpages - 简单页面

Often youll have a database-driven Web application up and running, but youll need to add a couple of one-off static pages, such as an About page or a Privacy Policy page. It would be possible to use a standard Web server such as Apache to serve these files as flat HTML files, but that introduces an extra level of complexity into your application, because then you have to worry about configuring Apache, you have to set up access for your team to edit those files, and you cant take advantage of Djangos template system to style the pages.

尽管通常情况下总是建造和运行数据库驱动的 Web 应用,你还是会需要添加一两张一次性的静态页面,例如“关于”页面,或者“隐私策略”页面等等。可以用像 Apache 这样的标准Web服务器来处理这些静态页面,但却会给应用带来一些额外的复杂性,因为你必须操心怎么配置 Apache,还要设置权限让整个团队可以修改编辑这些文件,而且你还不能使用 Django 模板系统来统一这些页面的风格。

The solution to this problem is Djangos flatpages application, which lives in the package django.contrib.flatpages . This application lets you manage such one-off pages via Djangos admin site, and it lets you specify templates for them using Djangos template system. It uses Django models behind the scenes, which means it stores the pages in a database, just like the rest of your data, and you can access flatpages with the standard Django database API.

这个问题的解决方案是使用位于 django.contrib.flatpages 开发包中的 Django 简单页面(flatpages)应用程序。该应用让你能够通过 Django 超级管理站点来管理这些一次性的页面,还可以让你使用 Django 模板系统指定它们使用哪个模板。它在后台使用了 Django 模型,也就是说它将页面存放在数据库中,你也可以像对待其他数据一样用标准 Django 数据库 API 存取简单页面。

Flatpages are keyed by their URL and site. When you create a flatpage, you specify which URL its associated with, along with which site(s) its on. (For more on sites, see the Sites section.)

简单页面以它们的 URL 和站点为键值。当创建简单页面时,你指定它与哪个URL以及和哪个站点相关联 。(有关站点的更多信息,请查阅《站点》一节)

Using Flatpages

使用简单页面

To install the flatpages application, follow these steps:

安装简单页面应用程序必须按照下面的步骤:

  1. Add 'django.contrib.flatpages' to your INSTALLED_APPS . django.contrib.flatpages depends on django.contrib.sites , so make sure the both packages are in INSTALLED_APPS .

  1. 添加 'django.contrib.flatpages'INSTALLED_APPS 设置。 django.contrib.flatpages 依赖于 django.contrib.sites , 所以确保这两个开发包都包括在 INSTALLED_APPS 设置中。

  1. Add 'django.contrib.flatpages.middleware.FlatpageFallbackMiddleware' to your MIDDLEWARE_CLASSES setting.

  1. 'django.contrib.flatpages.middleware.FlatpageFallbackMiddleware' 添加到 MIDDLEWARE_CLASSES 设置中。

  1. Run the command manage.py syncdb to install the two required tables into your database.

  1. 运行 manage.py syncdb 命令在数据库中创建必需的两个表。

The flatpages application creates two tables in your database: django_flatpage and django_flatpage_sites . django_flatpage simply maps a URL to a title and bunch of text content. django_flatpage_sites is a many-to-many table that associates a flatpage with one or more sites.

简单页面应用程序在数据库中创建两个表: django_flatpagedjango_flatpage_sitesdjango_flatpage 只是将 URL 映射到标题和一段文本内容。 django_flatpage_sites 是一个多对多表,用于关联某个简单页面以及一个或多个站点。

The application comes with a single FlatPage model, defined in django/contrib/flatpages/models.py . It looks like this:

该应用所带来的 FlatPage 模型在 django/contrib/flatpages/models.py 进行定义,如下所示:

from django.db import models
from django.contrib.sites.models import Site

class FlatPage(models.Model):
    url = models.CharField(maxlength=100)
    title = models.CharField(maxlength=200)
    content = models.TextField()
    enable_comments = models.BooleanField()
    template_name = models.CharField(maxlength=70, blank=True)
    registration_required = models.BooleanField()
    sites = models.ManyToManyField(Site)

Lets examine these fields one at a time:

让我们逐项看看这些字段的含义:

  • url : The URL at which this flatpage lives, excluding the domain name but including the leading slash (e.g., /about/contact/ ).

  • url : 该简单页面所处的 URL,不包括域名,但是包含前导斜杠 (例如 /about/contact/ )。

  • title : The title of the flatpage. The framework doesnt do anything special with this. Its your responsibility to display it in your template.

  • title : 简单页面的标题。框架不对它作任何特殊处理。由你通过模板来显示它。

  • content : The content of the flatpage (i.e., the HTML of the page). The framework doesnt do anything special with this. Its your responsibility to display it in the template.

  • content : 简单页面的内容 (即 HTML 页面)。框架不会对它作任何特别处理。由你负责使用模板来显示。

  • enable_comments : Whether to enable comments on this flatpage. The framework doesnt do anything special with this. You can check this value in your template and display a comment form if needed.

  • enable_comments : 是否允许该简单页面使用评论。框架不对此做任何特别处理。你可在模板中检查该值并根据需要显示评论窗体。

  • template_name : The name of the template to use for rendering this flatpage. This is optional; if its not given or if this template doesnt exist, the framework will fall back to the template flatpages/default.html .

  • template_name : 用来解析该简单页面的模板名称。这是一个可选项;如果未指定模板或该模板不存在,系统会退而使用默认模板 flatpages/default.html

  • registration_required : Whether registration is required for viewing this flatpage. This integrates with Djangos authentication/user framework, which is explained further in Chapter 12.

  • registration_required : 是否注册用户才能查看此简单页面。该设置项集成了 Djangos 验证/用户框架,该框架于第十二章详述。

  • sites : The sites that this flatpage lives on. This integrates with Djangos sites framework, which is explained in the Sites section of this chapter.

  • sites : 该简单页面放置的站点。该项设置集成了 Django 多站点框架,该框架在本章的《多站点》一节中有所阐述。

You can create flatpages through either the Django admin interface or the Django database API. For more information on this, see the section Adding, Changing, and Deleting Flatpages.

你可以通过 Django 超级管理界面或者 Django 数据库 API 来创建简单页面。要了解更多内容,请查阅《添加、修改和删除简单页面》一节。

Once youve created flatpages, FlatpageFallbackMiddleware does all of the work. Each time any Django application raises a 404 error, this middleware checks the flatpages database for the requested URL as a last resort. Specifically, it checks for a flatpage with the given URL with a site ID that corresponds to the SITE_ID setting.

一旦简单页面创建完成, FlatpageFallbackMiddleware 将完成(剩下)所有的工作。每当 Django 引发 404 错误,作为终极手段,该中间件将根据所请求的 URL 检查平页面数据库。确切地说,它将使用所指定的 URL以及 SITE_ID 设置对应的站点 ID 查找一个简单页面。

If it finds a match, it loads the flatpages template or flatpages/default.html if the flatpage has not specified a custom template. It passes that template a single context variable, flatpage , which is the flatpage object. It uses RequestContext in rendering the template.

如果找到一个匹配项,它将载入该简单页面的模板(如果没有指定的话,将使用默认模板 flatpages/default.html )。同时,它把一个简单的上下文变量—— flatpage (一个简单页面对象)传递给模板。在模板解析过程中,它实际用的是 RequestContext

If FlatpageFallbackMiddleware doesnt find a match, the request continues to be processed as usual.

如果 FlatpageFallbackMiddleware 没有找到匹配项,该请求继续如常处理。

Note

注意

This middleware only gets activated for 404 (page not found) errors not for 500 (server error) or other error responses. Also note that the order of MIDDLEWARE_CLASSES matters. Generally, you can put FlatpageFallbackMiddleware at or near the end of the list, because its a last resort.

该中间件仅在发生 404 (页面未找到)错误时被激活,而不会在 500 (服务器错误)或其他错误响应时被激活。还要注意的是必须考虑 MIDDLEWARE_CLASSES 的顺序问题。通常,你可以把 FlatpageFallbackMiddleware 放在列表最后,因为它是一种终极手段。

Adding, Changing, and Deleting Flatpages

添加、修改和删除简单页面

You can add, change and delete flatpages in two ways:

可以用两种方式增加、变更或删除简单页面:

Via the Admin Interface
通过超级管理界面

If youve activated the automatic Django admin interface, you should see a Flatpages section on the admin index page. Edit flatpages as you would edit any other object in the system.

如果已经激活了自动的 Django 超级管理界面,你将会在超级管理页面的首页看到有个 Flatpages 区域。你可以像编辑系统中其它对象那样编辑简单页面。

Via the Python API
通过 Python API

As described previously, flatpages are represented by a standard Django model that lives in django/contrib/flatpages/models.py . Hence, you can access flatpage objects via the Django database API, for example:

前面已经提到,简单页面表现为 django/contrib/flatpages/models.py 中的标准 Django 模型。因此,你可以通过 Django 数据库 API 来存取简单页面对象,例如:

>>> from django.contrib.flatpages.models import FlatPage
>>> from django.contrib.sites.models import Site
>>> fp = FlatPage(
...     url='/about/',
...     title='About',
...     content='<p>About this site...</p>',
...     enable_comments=False,
...     template_name='',
...     registration_required=False,
... )
>>> fp.save()
>>> fp.sites.add(Site.objects.get(id=1))
>>> FlatPage.objects.get(url='/about/')
<FlatPage: /about/ -- About>

Using Flatpage Templates

使用简单页面模板

By default, flatpages are rendered via the template flatpages/default.html , but you can override that for a particular flatpage with the template_name field on the FlatPage object.

缺省情况下,系统使用模板 flatpages/default.html 来解析简单页面,但你也可以通过设定 FlatPage 对象的 template_name 字段来覆盖特定简单页面的模板。

Creating the flatpages/default.html template is your responsibility. In your template directory, just create a flatpages directory containing a default.html file.

你必须自己创建 flatpages/default.html 模板。只需要在模板目录创建一个 flatpages 目录,并把 default.html 文件置于其中。

Flatpage templates are passed a single context variable, flatpage , which is the flatpage object.

简单页面模板只接受有一个上下文变量—— flatpage ,也就是该简单页面对象。

Heres a sample flatpages/default.html template:

以下是一个 flatpages/default.html 模板范例:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"
    "http://www.w3.org/TR/REC-html40/loose.dtd">
<html>
<head>
<title>{{ flatpage.title }}</title>
</head>
<body>
{{ flatpage.content }}
</body>
</html>

Redirects

重定向

Djangos redirects framework lets you manage redirects easily by storing them in a database and treating them as any other Django model object. For example, you can use the redirects framework to tell Django, Redirect any request to /music/ to /sections/arts/music/ . This comes in handy when you need to move things around on your site; Web developers should do whatever is necessary to avoid broken links.

通过将重定向存储在数据库中并将其视为 Django 模型对象,Django 重定向框架让你能够轻松地管理它们。比如说,你可以通过重定向框架告诉Django,把任何指向 /music/ 的请求重定向到 /sections/arts/music/ 。当你需要在站点中移动一些东西时,这项功能就派上用场了——网站开发者应该穷尽一切办法避免出现坏链接。

Using the Redirects Framework

使用重定向框架

To install the redirects application, follow these steps:

安装重定向应用程序必须遵循以下步骤:

  1. Add 'django.contrib.redirects' to your INSTALLED_APPS .

  1. 'django.contrib.redirects' 添加到 INSTALLED_APPS 设置中。

  1. Add 'django.contrib.redirects.middleware.RedirectFallbackMiddleware' to your MIDDLEWARE_CLASSES setting.

  1. 'django.contrib.redirects.middleware.RedirectFallbackMiddleware' 添加到 MIDDLEWARE_CLASSES 设置中。

  1. Run the command manage.py syncdb to install the single required table into your database.

  1. 运行 manage.py syncdb 命令将所需的表安装到数据库中。

manage.py syncdb creates a django_redirect table in your database. This is a simple lookup table with site_id , old_path , and new_path fields.

manage.py syncdb 在数据库中创建了一个 django_redirect 表。这是一个简单的查询表,只有 site_idold_pathnew_path 三个字段。

You can create redirects through either the Django admin interface or the Django database API. For more, see the section Adding, Changing, and Deleting Redirects.

你可以通过 Django 超级管理界面或者 Django 数据库 API 来创建重定向。要了解更多信息,请参阅《增加、变更和删除重定向》一节。

Once youve created redirects, the RedirectFallbackMiddleware class does all of the work. Each time any Django application raises a 404 error, this middleware checks the redirects database for the requested URL as a last resort. Specifically, it checks for a redirect with the given old_path with a site ID that corresponds to the SITE_ID setting. (See the earlier section Sites for more information on SITE_ID and the sites framework.) Then it follows these steps:

一旦创建了重定向, RedirectFallbackMiddleware 类将完成所有的工作。每当 Django 应用引发一个 404 错误,作为终极手段,该中间件将为所请求的 URL 在重定向数据库中进行查找。确切地说,它将使用给定的 old_path 以及 SITE_ID 设置对应的站点 ID 查找重定向设置。(查阅前面的《多站点》一节可了解关于 SITE_ID 和多站点框架的更多细节) 然后,它将执行以下两个步骤:

  • If it finds a match, and new_path is not empty, it redirects to new_path .

  • 如果找到了匹配项,并且 new_path 非空,它将重定向到 new_path

  • If it finds a match, and new_path is empty, it sends a 410 (Gone) HTTP header and an empty (contentless) response.

  • 如果找到了匹配项,但 new_path 为空,它将发送一个 410 (Gone) HTTP 头信息以及一个空(无内容)响应。

  • If it doesnt find a match, the request continues to be processed as usual.

  • 如果未找到匹配项,该请求将如常处理。

The middleware only gets activated for 404 errors not for 500 errors or responses of any other status code.

该中间件仅为 404 错误激活,而不会为 500 错误或其他任何状态码的响应所激活。

Note that the order of MIDDLEWARE_CLASSES matters. Generally, you can put RedirectFallbackMiddleware toward the end of the list, because its a last resort.

注意必须考虑 MIDDLEWARE_CLASSES 的顺序。通常,你可以将 RedirectFallbackMiddleware 放置在列表的最后,因为它是一种终极手段。

Note

注意

If youre using both the redirect and flatpage fallback middleware, consider which one (redirect or flatpage) youd like checked first. We suggest flatpages before redirects (thus putting the flatpage middleware before the redirect middleware), but you might feel differently.

如果同时使用重定向和简单页面回退中间件, 必须考虑先检查其中的哪一个(重定向或简单页面)。我们建议将简单页面放在重定向之前(因此将简单页面中间件放置在重定向中间件之前),但你可能有不同想法。

Adding, Changing, and Deleting Redirects

增加、变更和删除重定向

You can add, change and delete redirects in two ways:

你可以两种方式增加、变更和删除重定向:

Via the Admin Interface
通过超级管理界面

If youve activated the automatic Django admin interface, you should see a Redirects section on the admin index page. Edit redirects as you would edit any other object in the system.

如果已经激活了全自动的 Django 超级管理界面,你应该能够在超级管理首页看到重定向区域。可以像编辑系统中其它对象一样编辑重定向。

Via the Python API
通过 Python API

Redirects are represented by a standard Django model that lives in django/contrib/redirects/models.py . Hence, you can access redirect objects via the Django database API, for example:

django/contrib/redirects/models.py 中的一个标准 Django 模型代表了重定向。因此,你可以通过 Django 数据库 API 来存取重定向对象,例如:

>>> from django.contrib.redirects.models import Redirect
>>> from django.contrib.sites.models import Site
>>> red = Redirect(
...     site=Site.objects.get(id=1),
...     old_path='/music/',
...     new_path='/sections/arts/music/',
... )
>>> red.save()
>>> Redirect.objects.get(old_path='/music/')
<Redirect: /music/ ---> /sections/arts/music/>

CSRF Protection

CSRF 防护

The django.contrib.csrf package protects against Cross-Site Request Forgery (CSRF).

django.contrib.csrf 开发包能够防止遭受跨站请求伪造攻击 (CSRF).

CSRF, also known as session riding, is a Web site security exploit. It happens when a malicious Web site tricks a user into unknowingly loading a URL from a site at which that user is already authenticated, hence taking advantage of the users authenticated status. This can be a bit tricky to understand at first, so we walk through two examples in this section.

CSRF, 又叫进程跳转,是一种网站安全攻击技术。当某个恶意网站在用户未察觉的情况下将其从一个已经通过身份验证的站点诱骗至一个新的 URL 时,这种攻击就发生了,因此它可以利用用户已经通过身份验证的状态。开始的时候,要理解这种攻击技术比较困难,因此我们在本节将使用两个例子来说明。

A Simple CSRF Example

一个简单的 CSRF 例子

Suppose youre logged in to a webmail account at example.com . This webmail site has a Log Out button that points to the URL example.com/logout that is, the only action you need to take in order to log out is to visit the page example.com/logout .

假定你已经登录到 example.com 的网页邮件账号。该网页邮件站点上有一个登出按钮指向了 URL example.com/logout ,换句话说,要登出的话,需要做的唯一动作就是访问 URL : example.com/logout

A malicious site can coerce you to visit the URL example.com/logout by including that URL as a hidden <iframe> on its own (malicious) page. Thus, if youre logged in to the example.com webmail account and visit the malicious page that has an <iframe> to example.com/logout , the act of visiting the malicious page will log you out from example.com .

通过在(恶意)网页上用隐藏一个指向 URL example.com/logout<iframe> ,恶意网站可以强迫你访问该 URL 。因此,如果你登录 example.com 的网页邮件账号之后,访问了带有指向 example.com/logout<iframe> 的恶意站点,访问该恶意页面的动作将使你登出 example.com

Clearly, being logged out of a webmail site against your will is not a terrifying breach of security, but this same type of exploit can happen to any site that trusts users, such as an online banking site or an e-commerce site.

诚然,对你而言登出一个网页邮件站点并不会构成多大的安全破坏,但同样的攻击可能发生在 任何 信任用户的站点之上,比如在线银行网站或者电子商务网站。

A More Complex CSRF Example

稍微复杂一点的CSRF例子

In the previous example, example.com was partially at fault because it allowed a state change (i.e., logging the user out) to be requested via the HTTP GET method. Its much better practice to require an HTTP POST for any request that changes state on the server. But even Web sites that require POST for state-changing actions are vulnerable to CSRF.

在上一个例子中, example.com 应该负部分责任,因为它允许通过 HTTP GET 方法进行状态变更(即登入和登出)。如果对服务器的状态变更要求使用 HTTP POST 方法,情况就好得多了。但是,即便是强制要求使用 POST 方法进行状态变更操作也易受到 CSRF 攻击。

Suppose example.com has upgraded its Log Out functionality so that its a <form> button that is requested via POST to the URL example.com/logout . Furthermore, the logout <form> includes this hidden field:

假设 example.com 对登出功能进行了升级,登出 <form> 按钮是通过一个指向 URL example.com/logoutPOST 动作完成,同时在 <form> 中加入了以下隐藏的字段:

<input type="hidden" name="confirm" value="true" />

This ensures that a simple POST to the URL example.com/logout wont log a user out; in order for a user to log out, the user must request example.com/logout via POST and send the confirm POST variable with a value of 'true' .

这就确保了用简单的 POSTexample.com/logout 不会让用户登出;要让用户登出,用户必须通过 POSTexample.com/logout 发送请求 并且 发送一个值为 'true'POST 变量。

Well, despite the extra security, this arrangement can still be exploited by CSRF the malicious page just needs to do a little more work. Attackers can create an entire form targeting your site, hide it in an invisible <iframe> , and then use JavaScript to submit that form automatically.

尽管增加了额外的安全机制,这种设计仍然会遭到 CSRF 的攻击——恶意页面仅需一点点改进而已。攻击者可以针对你的站点设计整个表单,并将其藏身于一个不可见的 <iframe> 中,然后使用 Javascript 自动提交该表单。

Preventing CSRF

防止 CSRF

How, then, can your site protect itself from this exploit? The first step is to make sure all GET requests are free of side effects. That way, if a malicious site includes one of your pages as an <iframe> , it wont have a negative effect.

那么,是否可以让站点免受这种攻击呢?第一步,首先确保所有 GET 方法没有副作用。这样以来,如果某个恶意站点将你的页面包含为 <iframe> ,它将不会产生负面效果。

That leaves POST requests. The second step is to give each POST <form> a hidden field whose value is secret and is generated from the users session ID. Then, when processing the form on the server side, check for that secret field and raise an error if it doesnt validate.

该技术没有考虑 POST 请求。第二步就是给所有 POST<form> 一个 隐藏字段,它的值是保密的并根据用户进程的 ID 生成。这样,从服务器端访问表单时,可以检查该保密的字段,不吻合时可以引发一个错误。

This is exactly what Djangos CSRF prevention layer does, as explained in the sections that follow.

这正是 Django CSRF 防护层完成的工作,正如下面的小节所介绍的。

Using the CSRF Middleware
使用CSRF中间件

The django.contrib.csrf package contains only one module: middleware.py . This module contains a Django middleware class, CsrfMiddleware , which implements the CSRF protection.

django.contrib.csrf 开发包只有一个模块: middleware.py 。该模块包含了一个 Django 中间件类—— CsrfMiddleware ,该类实现了 CSRF 防护功能。

To activate this CSRF protection, add 'django.contrib.csrf.middleware.CsrfMiddleware' to the MIDDLEWARE_CLASSES setting in your settings file. This middleware needs to process the response after SessionMiddleware , so CsrfMiddleware must appear before SessionMiddleware in the list (because the response middleware is processed last-to-first). Also, it must process the response before the response gets compressed or otherwise mangled, so CsrfMiddleware must come after GZipMiddleware . Once youve added that to your MIDDLEWARE_CLASSES setting, youre done. See the section Order of MIDDLEWARE_CLASSES in Chapter 13 for more explanation.

在设置文件中将 'django.contrib.csrf.middleware.CsrfMiddleware' 添加到 MIDDLEWARE_CLASSES 设置中可激活 CSRF 防护。该中间件必须在 SessionMiddleware 之后 执行,因此在列表中 CsrfMiddleware 必须出现在 SessionMiddleware 之前 (因为响应中间件是自后向前执行的)。同时,它也必须在响应被压缩或解压之前对响应结果进行处理,因此 CsrfMiddleware 必须在 GZipMiddleware 之后执行。一旦将它添加到 MIDDLEWARE_CLASSES 设置中,你就完成了工作。参阅第 13 章中的《MIDDLEWARE_CLASSES 的顺序》一节了解更多诠释。

In case youre interested, heres how CsrfMiddleware works. It does these two things:

如果感兴趣的话,下面是 CsrfMiddleware 的工作模式。它完成以下两项工作:

  1. It modifies outgoing requests by adding a hidden form field to all POST forms, with the name csrfmiddlewaretoken and a value that is a hash of the session ID plus a secret key. The middleware does not modify the response if theres no session ID set, so the performance penalty is negligible for requests that dont use sessions.

  1. 它修改当前处理的请求,向所有的 POST 表单增添一个隐藏的表单字段,使用名称是 csrfmiddlewaretoken ,值为当前会话 ID 加上一个密钥的散列值。如果未设置会话 ID ,该中间件将 不会 修改响应结果,因此对于未使用会话的请求来说性能损失是可以忽略的。

  1. On all incoming POST requests that have the session cookie set, it checks that csrfmiddlewaretoken is present and correct. If it isnt, the user will get a 403 HTTP error. The content of the 403 error page is the message Cross Site Request Forgery detected. Request aborted.

  1. 对于所有含会话 cookie 集合的传入 POST 请求,它将检查是否存在 csrfmiddlewaretoken 及其是否正确。如果不是的话,用户将会收到一个 403 HTTP 错误。403 错误页面的内容是消息:检测到跨站伪装请求。请求被终止。”

This ensures that only forms originating from your Web site can be used to POST data back.

该步骤确保只有源自你的站点的表单才能将数据 POST 回来。

This middleware deliberately targets only HTTP POST requests (and the corresponding POST forms). As we explained, GET requests ought never to have side effects; its your own responsibility to ensure this.

该中间件特意只针对 HTTP POST 请求(以及对应的 POST 表单)。如我们所解释的,永远不应该因为使用了 GET 请求而产生负面效应,你必须自己来确保这一点。

POST requests not accompanied by a session cookie are not protected, but they dont need to be protected, because a malicious Web site could make these kind of requests anyway.

未使用会话 cookie 的 POST 请求无法受到保护,但它们也不 需要 受到保护,因为恶意网站可用任意方法来制造这种请求。

To avoid altering non-HTML requests, the middleware checks the responses Content-Type header before modifying it. Only pages that are served as text/html or application/xml+xhtml are modified.

为了避免转换非 HTML 请求,中间件在编辑响应结果之前对它的 Content-Type 头标进行检查。只有标记为 text/htmlapplication/xml+xhtml 的页面才会被修改。

Limitations of the CSRF Middleware
CSRF中间件的局限性

CsrfMiddleware requires Djangos session framework to work. (See Chapter 12 for more on sessions.) If youre using a custom session or authentication framework that manually manages session cookies, this middleware will not help you.

CsrfMiddleware 的运行需要 Django 的会话框架。(参阅第 12 章了解更多关于会话的内容)如果你使用了自定义会话或者身份验证框架手动管理会话 cookies,该中间件将帮不上你的忙。

If your application creates HTML pages and forms in some unusual way (e.g., if it sends fragments of HTML in JavaScript document.write statements), you might bypass the filter that adds the hidden field to the form. In this case, the form submission will always fail. (This happens because CsrfMiddleware uses a regular expression to add the csrfmiddlewaretoken field to your HTML before the page is sent to the client, and the regular expression sometimes cannot handle wacky HTML.) If you suspect this might be happening, just view the source in your Web browser to see whether csrfmiddlewaretoken was inserted into your <form> .

如果你的应用程序以某种非常规的方法创建 HTML 页面(例如:在 Javascript 的 document.write 语句中发送 HTML 片段),你可能会绕开了向表单添加隐藏字段的过滤器。在此情况下,表单提交永远无法成功。(这是因为在页面被发送到客户端之前, CsrfMiddleware 使用正则表达式向 HTML 中添加 csrfmiddlewaretoken 字段,而有时正则表达式无法处理非常规的 HTML。)如果你怀疑发生这类事情,只需在浏览器中查看源码的表单中是否已经插入了 csrfmiddlewaretoken

For more CSRF information and examples, visit http://en.wikipedia.org/wiki/CSRF.

想了解更多关于 CSRF 的信息和例子的话,可以访问 http://en.wikipedia.org/wiki/CSRF

Humanizing Data

人性化数据

This application holds a set of Django template filters useful for adding a human touch to data. To activate these filters, add 'django.contrib.humanize' to your INSTALLED_APPS setting. Once youve done that, use {% load humanize %} in a template, and youll have access to the filters described in the following sections.

该应用程序包括一系列 Django 模板过滤器,用于增加数据的人性化。要激活这些过滤器,仅需将 'django.contrib.humanize' 加入到 INSTALLED_APPS 设置中。一旦完成该项工作,在模板中使用 {% load humanize %} 就能访问后续小节中讲述的过滤器了。

apnumber

apnumber

For numbers 1 through 9, this filter returns the number spelled out. Otherwise, it returns the numeral. This follows Associated Press style.

对于 1 到 9 的数字,该过滤器返回了数字的拼写形式。否则,它将返回数字。这遵循的是美联社风格。

Examples:

举例:

  • 1 becomes one.

  • 1 变成 one 。

  • 2 becomes two.

  • 2 变成 two 。

  • 10 becomes 10.

  • 10 变成 10 。

You can pass in either an integer or a string representation of an integer.

你可以传入一个整数或者表示整数的字符串。

intcomma

intcomma

This filter converts an integer to a string containing commas every three digits.

该过滤器将整数转换为每三个数字用一个逗号分隔的字符串。

Examples:

例如:

  • 4500 becomes 4,500.

  • 4500 变成 4,500 。

  • 45000 becomes 45,000.

  • 45000 变成 45,000 。

  • 450000 becomes 450,000.

  • 450000 变成 450,000 。

  • 4500000 becomes 4,500,000.

  • 4500000 变成 4,500,000 。

You can pass in either an integer or a string representation of an integer.

你可以传入整数或者表示整数的字符串。

intword

intword

This filter converts a large integer to a friendly text representation. It works best for numbers over 1 million.

该过滤器将一个很大的整数转换成友好的文本表示方式。它对于超过一百万的数字最好用。

Examples:

例如:

  • 1000000 becomes 1.0 million.

  • 1000000 变成 1.0 million 。

  • 1200000 becomes 1.2 million.

  • 1200000 变成 1.2 million 。

  • 1200000000 becomes 1.2 billion.

  • 1200000000 变成 1.2 billion 。

Values up to 1 quadrillion (1,000,000,000,000,000) are supported.

最大支持不超过一千的五次方(1,000,000,000,000,000)。

You can pass in either an integer or a string representation of an integer.

你可以传入整数或者表示整数的字符串。

ordinal

ordinal

This filter converts an integer to its ordinal as a string.

该过滤器将整数转换为序数词的字符串形式。

Examples:

例如:

  • 1 becomes 1st.

  • 1 变成 1st 。

  • 2 becomes 2nd.

  • 2 变成 2nd 。

  • 3 becomes 3rd.

  • 3 变成 3rd 。

You can pass in either an integer or a string representation of an integer.

你可以传入整数或着表示整数的字符串。

Markup Filters

标记过滤器

The following collection of template filters implements common markup languages:

下列模板过滤器集合实现了常见的标记语言:

In each case, the filter expects formatted markup as a string and returns a string representing the marked-up text. For example, the textile filter converts text that is marked up in Textile format to HTML:

每种情形下,过滤器都期望字符串形式的格式化标记,并返回表示标记文本的字符串。例如: textile 过滤器把以 Textile 格式标记的文本转换为 HTML 。

{% load markup %}
{{ object.content|textile }}

To activate these filters, add 'django.contrib.markup' to your INSTALLED_APPS setting. Once youve done that, use {% load markup %} in a template, and youll have access to these filters. For more documentation, read the source code in django/contrib/markup/templatetags/markup.py.

要激活这些过滤器,仅需将 'django.contrib.markup' 添加到 INSTALLED_APPS 设置中。一旦完成了该项工作,在模板中使用 {% load markup %} 就能使用这些过滤器。要想掌握更多信息的话,可阅读 django/contrib/markup/templatetags/markup.py. 内的源代码。

Whats Next?

下一步?

Many of these contributed frameworks (CSRF, the auth system, etc.) do their magic by providing a piece of middleware . Middleware is essentially code that runs before and/or after every single request and can modify each request and response at will. Next, well discuss Djangos built-in middleware and explain how you can write your own.

这些继承框架(CSRF、身份验证系统等等)通过提供 中间件 来实现其奇妙的功能。本质上,中间件就是在每个请求之前或/和之后运行的代码,它们可随意修改每个请求或响应。接下来,我们将讨论 Django 的内建中间件,并解释如何编写自己的中间件。

Copyright 2006 Adrian Holovaty and Jacob Kaplan-Moss.
This work is licensed under the GNU Free Document License.
Hosting graciously provided by media temple
Chinese translate hosting by py3k.cn. 粤ICP备16122281号-1