Django 子域的实现

标签: django 子域 | 发表时间:2011-10-25 00:09 | 作者:(author unknown) est
出处:http://simple-is-better.com/

Django作为一个典型的MVC三层框架,有着自己一套full-stack的实现。针对开发和运行效率而言,有人想用[SQLAlchemy]来替换Django的ORM;有人会吐槽Django的Template模板渲染系统,转而尝试[Jinjia2];但或许没有人对Django的URL处理机制不满。StackOverflow上说,面对愈发大型的系统,Django的URL Routing可能是唯一剩下的模块。Django使用了强大的正则表达式来Resolve URL,重用了程序员既有的知识;提供了Reverse方法来反向构造URL,使得View与其对应的URL解耦;再加之飞快的处理速度(因为全局的resolver_cache的存在),使得一切看起来是那么美好。然而,美中不足的是,Django官方对subdomain的支持并不完备,譬如URL的Routing只考虑URI,并不考虑host信息(#8896)。

在Django里有两种方式可以实现subdomain:Contrib下的SitesApp&Middleware动态指定request.urlconf。

让我们先来看看第一种方式:Sites,可定义任意的Domain。
我们知道每个项目的配置文件settings.py都一个属性SITE_ID(默认为1), INSTALLED_APPS中也默认包含‘django.contrib.sites’,那么说明了django内部有使用这个APP。
那么,对于我们上层应用而言,Sites适用于什么场合呢?Django文档上说:
“Use it if your single Django installation powers more than one site and you need to differentiate between those sites in some way.”
对于singleDjangoinstallation,我的理解是不同site使用相同的default数据库,即它们使用同一张django_site数据库表。
咋一看,很符合我们的需求嘛:我们本来在同一个数据库里,只要设置不同的site_id即可。但是site_id设置在settings里,这意味着不同的site需要有不同的project。这对于某些不同站点间功能关联不紧密,原有结构划分清晰,有可重用的APP的项目而言可能不是什么大问题,然而,对于subdoamin来言其功能逻辑代码关联紧密,用sites的方式来处理显得过于粗暴了。

来看看第二种方式:middleware指定request.urlconf属性。
Django对于request的转发基于两个部分。1. request.path_info, 请求的URL。2. request.urlconf, 项目处理的全部URL。
在middleware里我们可以指定urlconf到特定的urls.py,如果没有指定的话,默认使用settings里的ROOT_URLCONF。在调用urlresolvers中resolve和reverse方法都可指定request的urlconf属性,但遗憾的是template的url标签并没有将urlconf属性暴露出来。

试想一下,我们可以给不同的subdomain定义自己的一套urlconf(并不麻烦,归结于django灵活的urlpatterns构造),再在middleware里根据domain的信息,将其转发到定义的subdomain上,就可以达到了目的。

那么,这样的实现方式会有什么问题呢?
1. runserver时除ROOT_URLCONF定义的patterns,其他域名下的url不可用。因为我们在runserver时通过IP访问,没有Domain信息。
2. 因为Django的reverse没有domain信息,我们需要手动将reverse的结果指定到对应的subdomain上。

为解决这两个问题,我们使用了一个trick。我们在middleware处理时设法保留了subdomain的信息,并将其反映在path上;在urls.py中构造对应的patterns;最后在reverse时将subdomain的信息取出构造出正确的url。代码如下:

SubdomainMiddleware:

class SubdomainMiddleware(object):
    def process_request(self, request):
        domain_parts = request.get_host().split('.')
        if len(domain_parts) == 3:
            # 将subdomain的信息放到URI的第一层级
            request.path_info = '/%s%s' % (domain_parts[0], request.path)
    return None

将其添加在MIDDLEWARE_CLASSES中,确保一个靠上的位置。在此,我们没有修改request.path的信息,是因为path_info才是Django内部分发的依据,同时我们也可以根据我们的需要灵活引用path或path_info。

Reverse Monkey Patch:

# not in settings.py: will be imported twice
# not in urls.py: too late
# works in models.py
from django.conf import settings
if not settings.DEBUG:
    from django.core import urlresolvers
    def reverse_subdomain(*args, **kwargs):
        path_info = old_reverse(*args, **kwargs)
        parts = path_info[1:].split('/', 1)
        path_info = 'http://%s%s/%s' % (
                parts[0], settings.SESSION_COOKIE_DOMAIN, parts[1])
        return path_info
    old_reverse = urlresolvers.reverse
    urlresolvers.reverse = reverse_subdomain

在此我们有一个假设,假设我们和我们要使用的第三方包并不依赖于reverse的结果,都不会对其做进一步的处理,仅仅是显示在页面上显示或重定向等直接返回的行为。这个假设我们感觉基本上成立。

还有一点需要说明的是,包含re.VERBOSE(\x)或零宽断言的正则表达式在resolver时没有问题,但在reverse时会异常,因为它们是“Non-reversible reg-exp portion”。偶尔,我们可能会为了效率考虑,或许更多的是为了满足自己的好奇心和挑战欲,写出复杂的正则匹配,而往往是没有必要的。

# 来源:九九房博客


在微博上关注: 新浪, 腾讯   投稿

最新招聘

更多>>

相关 [django 子域] 推荐:

Django 子域的实现

- est - python.cn(jobs, news)
Django作为一个典型的MVC三层框架,有着自己一套full-stack的实现. 针对开发和运行效率而言,有人想用[SQLAlchemy]来替换Django的ORM;有人会吐槽Django的Template模板渲染系统,转而尝试[Jinjia2];但或许没有人对Django的URL处理机制不满. StackOverflow上说,面对愈发大型的系统,Django的URL Routing可能是唯一剩下的模块.

Django class-based view 基础

- Ken - python.cn(jobs, news)
自从Django在1.3中新增了class-based view以来,还没有仔细研究它,开始感觉这个东西是否有点多余. 因为Django已经有了Generic veiws了啊, 可是仔细看过class-based veiw之后, 这种想法打消了, 因为你完全可以用类方法实现你所有的视图, 而代码阅读起来却更容易!.

Django class-based view 深入

- Ken - python.cn(jobs, news)
上一篇我们粗略介绍了Django中的class-based view基础知识, 本篇我们继续来看关于class-based view的高级应用.. 我们继续沿用上篇中的model:. 我们来看看如何对一个Book实例进行更新, 我们要做的只是在视图类中更新 :.     template_name = 'updatebook.html'  #这里是你的模板文件名.

Nginx+uWSGI 部署 Django 应用

- Ken - python.cn(jobs, news)
常见的django webapp 部署方式采用FCGI 或 WSGI的方式部署,今天我这备忘下采用uWSGI的部署方式. 目前我这博客就是采用 Nginx + uWSGI + Python + Django 构建的,部署虽没有php那样扔到目录那么方便,但是并发和性能消耗还是非常不错的. 这里不想赘述关于FCGI, WSGI,uWSGI之间的比较,网上关于这样的对比测试也有很多,例如这里.

知名Python Web框架Django被墙

- Haisheng HU - Solidot
xuby 写道 "今天发现,知名Python Web框架Django的官方网站被墙. 目前尚不清楚是迎八一暂时屏蔽,还是永久屏蔽. " 北京联通ISP可以访问Https版.

Dotcloud 架设 Django 的几个问题

- Ken - python.cn(jobs, news)
几个月前写过一篇《在Dotcloud上架设Django网站》的文章,有读者将自己遇到的问题留在评论里,也有通过Gtalk联系我进行讨论的同学,在大家的帮助下解决了不少问题,现一并整理在这此. 这里说的是服务器的404错误,Django返回的404错误会有详细的提示,不在讨论范围内. 服务器404错误通常——当然也有例外——是Dotcloud设置不当引起的.

合理的组织 django 的 settings 文件

- Ken - python.cn(jobs, news)
django在一个项目的目录结构划分方面缺乏必要的规范,因此不同人的项目组织形式也千奇百怪,而且也很难说谁的做法就比较好. 我根据自己的项目组织习惯,发布了一个项目dj-scaffold. 前些天在reddit上为我的项目dj-scaffold打了个“广告”(见:http://redd.it/kw5d4).

如何阅读Django的文档

- - the5fire的技术博客
“大神你好,请问我打算学习Django,应该怎么做. “Django的文档都是英文,我看不下去,怎么办”. 答:“bla bla bla. “Django的文档那么多,我是不是都得看完才行. 答:“不用,用到哪看到哪,没事可以随意浏览”. 上面的对话经常会出现在我的QQ消息框中,有很多初学Django的人通常都会有这样或者那样的疑问,我之前写过一篇 《从Django的Turotial中可以学到什么》 ,在那篇文章中我总结过,练习完这个新手入门教程,基本上可以独自开发web项目了.

Django介绍、安装配置、基本使用、Django用户注册例子

- - CSDN博客编程语言推荐文章
    Django 是由 Python 开发的一个免费的开源网站框架,可以用于快速搭建高性能,优雅的网站.     DjangoMTV的思想.     没有controller,把view当成mvc的controller. 可以配合参考: http://blog.csdn.net/jerome_s/article/details/46340079 ( Python介绍、环境搭建、第一个程序).

给力百货开发历程分享:选择 Django 还是 Rails?

- nowa - python.cn(jobs, news)
之前 Eric.Mao 使用过 Bottle 开发 义乌小商品搜索,这回他转使用 Rails 开发一个B2B商城,那么他对 Python 熟悉的情况下为什么要转呢. 给力百货(www.geilibuy.com)定位于日用小百货的量贩平台,依托义乌小百货集聚的货源及物流的优势,打造价格、物流的洼地. 和之前的义乌小额批发网是一脉相承的.