ITEEDU

| 上一章 | 目 录 | 下一章 |

第十六章:集成的子框架 django.contrib

Python有众多优点,其中之一就是“开机即用”原则: 安装Python的同时安装好大量的标准软件包,这样 你可以立即使用而不用自己去下载。 Django也遵循这个原则,它同样包含了自己的标准库。 这一章就来讲 这些集成的子框架。

Django标准库

Django的标准库存放在 django.contrib 包中。 每个子包都是一个独立的附加功能包。

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

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

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

  • admindocs : Auto-documentation for the Django admin site. This book doesn’t cover this feature; check the official Django documentation.

  • auth : Django的用户验证框架。 See Chapter 14.

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

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

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

  • databrowse : A Django application that lets you browse your data. This book doesn’t cover this feature; check the official Django documentation.

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

  • formtools : A number of useful higher-level libraries for dealing with common patterns in forms. This book doesn’t cover this feature; check the official Django documentation.

  • gis : Extensions to Django that provide for GIS (Geographic Information Systems) support. These, for example, allow your Django models to store geographic data and perform geographic queries. This is a large, complex library and isn’t covered in this book. See http://geodjango.org/ for documentation.

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

  • localflavor : Assorted pieces of code that are useful for particular countries or cultures. For example, this includes ways to validate U.S. ZIP codes or Icelandic identification numbers.

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

  • redirects : 用来管理重定向的框架。 See the later section titled Redirects.

  • sessions : Django 的会话框架,参见12章。 See Chapter 14.

  • sitemaps : 用来生成网站地图的 XML 文件的框架。 See Chapter 13.

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

  • syndication : 一个用 RSS 和 Atom 来生成聚合订阅源的的框架。 See Chapter 13.

  • webdesign : Django add-ons that are particularly useful to Web designers (as opposed to developers). As of this writing, this included only a single template tag, {% lorem %} . Check the Django documentation for information.

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

多个站点

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

情景1:

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

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

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

情景2:

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

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

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

如何使用多站点框架

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

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

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

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

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

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

  1. 运行 manage.py syncdb 命令将 django_site 表安装到数据库中。 这样也会建立默认的站点对象,域名为 example.com。

  1. Change the example.com site to your own domain, and add any other Site objects, either through the Django admin site or via the Python API. 为该 Django 项目支撑的每个站(或域)创建一个 Site 对象。

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

多站点框架的功能

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

多个站点的数据重用

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

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

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

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

from django.conf import settings
from django.shortcuts import get_object_or_404
from mysite.articles.models import Article

def article_detail(request, article_id):
    a = get_object_or_404(Article, id=article_id, sites__id=settings.SITE_ID)
    # ...

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

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

将内容与单一站点相关联

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

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

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

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

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

从视图钩挂当前站点

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

from django.conf import settings

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

当然,像那样对站点 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.

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.

注意

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

获取当前域用于呈现

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

from djang