对于Python的Django框架部署的一些建议


Posted in Python onApril 09, 2015

“Django应用、配置文件以及其他各种相关目录的最佳布局是什么样的?”

总是有朋友问我们这个问题,因此我想花一点时间,写一下我们究竟是如何看待这个问题的,这样我们就可以很容易让其他人参照这个文档。请注意,这里是基于 Django 1.7.1 版写的,但是可以很容易应用在 Django 1.4 版之后任何版本。

虽然 Django 1.4 发布时,它包含了一个改进后的项目布局(这还用了很长一段时间),但本文有一些优化项目布局的更好建议。
为什么这种布局比较好

我们在这里推荐的项目布局有几个优点,即:

  1.     让你获得、重新打包并复用单个的Django应用来用于其他的项目。这通常是不明确的,正如你正在构建一个不管是否要复用的应用。在一开始以想要复用的方式构建应用,会让这一切变得更加简单。
  2.     鼓励设计可复用的应用。
  3.     环境的详细设置。在一个单一的整体配置文件中,if DEBUG==True 没有什么意义。这使得很容易能看到哪些配置是共享的,哪些是在每个环境的基础上可覆写的。
  4.     环境的具体安装要求(PIP requirements)。
  5.     如果有必要,项目级的模板和静态文件可以覆写应用级的默认值。
  6.     小而更具体的测试文件更易于阅读和理解。

假设你有两个应用 blog 和 users,以及两个开发环境 dev 和 prod。你的项目布局结构应该是这样的:
 

myproject/

    manage.py

    myproject/

        __init__.py

        urls.py

        wsgi.py

        settings/

            __init__.py

            base.py

            dev.py

            prod.py

    blog/

        __init__.py

        models.py

        managers.py

        views.py

        urls.py

        templates/

            blog/

                base.html

                list.html

                detail.html

        static/

           …

        tests/

            __init__.py

            test_models.py

            test_managers.py

            test_views.py

    users/

        __init__.py

        models.py

        views.py

        urls.py

        templates/

            users/

                base.html

                list.html

                detail.html

        static/

            …

        tests/

            __init__.py

            test_models.py

            test_views.py

     static/

         css/

             …

         js/

             …

     templates/

         base.html

         index.html

     requirements/

         base.txt

         dev.txt

         test.txt

         prod.txt

本文的剩余部分介绍了如何将项目迁移到这个布局,以及为什么这种布局比较好。
当前默认布局

我们将调用示例项目foo,我知道这是一个非常有创意的名字。我们假设在这里,我们将要启动foo.com。但当我们希望将我们的项目名称映射最终域名时,该项目将以不以任何意义要求的方式存在在这里。

如果你使用 django-admin.py startproject foo 命令开启这个项目,你会得到一个像这样的目录结构:
 

foo/
  manage.py
  foo/
    __init__.py
    settings.py
    urls.py
    wsgi.py

这种布局是一个好起点,我们有一个顶级目录foo,里面包含了manage.py文件和项目目录foo/foo/。在这个目录,你可以查询到源代码控制系统(比如 Git) 。

你应该想到子目录foo/foo/就是这个项目。这里的所有文件,不是一个Django应用程序,就是与项目相关的配套文件。
修改配置

这里的任务是修正不好的配置文件。我将这个布局向新用户展示,我往往惊讶于这几个人怎么知道这甚至可能做到。事实上,当大家都知道这些配置只是Python代码时,他们也不将它们当做Python代码。

因此,让我们来改进配置。对于oo项目而言,将有4个开发环境:dev、stage、jenkins 和 production。给每个开发环境一个它们自己的配置文件。这个过程中要做的事情是:

    在foo/foo/目录下新建一个配置目录,并在里面创建一个空的__init __.py文件。
    将foo/foo/settings.py移动并重命名为foo/foo/settings/base.py。
    在foo/foo/settings/目录下创建单独的dev.py、stage.py、jenkins.py 和 production.py文件。这四种环境的特定配置文件应该包含如下内容:
   

from base import *

为什么这很重要呢?对于本地开发你想要设置DEBUG=True,但很容易不小心将这个推到生产代码中,因此需要打开 foo/foo/settings/production.py 文件,在初始导入base后加上DEBUG=False。现在,对于这种愚蠢的错误,你的生产环境是安全的。

还有什么可以定制?很明显你可以针对不同的数据库,甚至是不同的主机来配置staging、jenkins和production等开发环境。然后在每个环境配置文件中来调整那些配置。
使用这些配置

无论你通常使用哪种方法,使用这些配置都非常简单。要使用该操作系统的环境,你只要做:
 

export DJANGO_SETTINGS_MODULE=“foo.settings.jenkins”

现在你就在使用 jenkins 的配置。

或者,也许你更喜欢把它们作为这样的命令行选项:
 

./manage.py migrate —settings=foo.settings.production

同样的,如果你使用 gunicorn,命令则如下:
 

gunicorn -w 4 -b 127.0.0.1:8001 —settings=foo.settings.dev

还有什么可自定义的配置?

另一个实用建议是将一些默认的集合配置从元组改为列表。例如 INSTALLED_APPS,将它从:
 

INSTALLED_APPS =(
...
)

改为:
 

INSTALLED_APPS = [
  …
]

现在,基于每个环境的特定配置文件,我们可以更轻松地在 foo/settings/base.py文件中添加和删除应用。例如,你可能只想在dev环境而不是其他环境中安装Django调试工具栏。

这个技巧对 TEMPLATE_DIRS和MIDDLEWARE_CLASSES 配置也非常有用。

我们经常使用的另一个技巧是把应用分为两个列表,一个是项目的必要前提,另一个用于实际项目应用。如下面所示:
 

PREREQ_APPS = [
  ‘django.contrib.auth',
  ‘django.contrib.contenttypes',
  …
  ‘debug_toolbar',
  ‘imagekit',
  ‘haystack',
]
 
PROJECT_APPS = [
  ‘homepage',
  ‘users',
  ‘blog',
]
 
INSTALLED_APPS = PREREQ_APPS + PROJECT_APPS

为什么这个有用?第一,它有助于更好地区分Django核心应用、第三方应用及你自己的内部项目的具体应用。对于测试和代码覆盖率等事情,写明你的特定应用的PROJECT_APPS列表往往就派上了用场。你有写一个应用列表,因此你可以轻松自动地确保它们的测试运行,记录的测试覆盖率只包括它们而不包括任何第三方的应用,且无需在两个不同的地方维护这个列表。
修改要求

大多是项目有一个requirements.txt文件,它用如下命令安装:
 

pip install -r requirements.txt

对于简单的小项目这以足够了,但requirements.txt文件有一个鲜为人知的特点是,你可以使用-r参数来包括其他文件。因此,对于所有常见的安装要求,我们可以创建一个base.txt文件;然后,如果我们需要能够运行测试,我们可以创建一个包含如下内容的特定的requirements/test.txt文件:
 

-r base.txt

pytest==2.5.2

coverage==3.7.1

我承认这没有巨大的好处,但它确实有助于区分什么是每个开发环境的要求。同时,对于其性能,它不会安装一堆在实际生产中用不上的东西,来减少生产环境中的pip安装时间。
测试文件

我们为什么要拆分很大的测试文件呢?其中的一个主要原因是,如果你在一个tests.py文件中对每个应用写了足够多的测试,那么这个文件最终将变得非常臃肿。这样的代码可读性很差,并且你不得不在编辑器中花很多时间来滚动浏览代码。

当你和其他开发者一起工作时,小文件也能让你在代码合并时少遇到冲突。小文件是你的朋友。
URLs

对于小型项目,把所有的URL定义放在foo/urls.py文件中,让它们在同一个地方。但是,如果你的目标是代码的清晰和可复用,你最好在每个应用中定义它们的url,再将它们包含在你的主项目中。你不应如下所做:
 

urlpatterns = patterns(‘',
  url(r'^$', HomePageView.as_view(), name=‘home'),
  url(r'^blog/$', BlogList.as_view(), name=‘blog_list'),
  url(r'^blog/(?P<pk>d+)/$', BlogDetail.as_view(), name=‘blog_detail'),
  …
  url(r'^user/list/$', UserList.as_view(), name=‘user_list'),
  url(r'^user/(?P<username>w+)/$', UserDetail.as_view(), name=‘user_detail'),
)

你应该这样做:
 

urlpatterns = patterns(‘',
  url(r'^$', HomePageView.as_view(), name=‘home'),
  url(r'^blog/‘, include(‘blog.urls')),
  url(r'^user/‘, include(‘user.urls')),
)

模板和静态资源

每个应用中都有templates/和static/目录,这让一个应用可以基本上复用到其他的项目中。

对于一个很酷的功能,我们全在一个包中获得应用提供的默认模板和任何相关的静态资源,如特殊的Javascript。

但是,它也让我们可以覆写每个项目主目录foo/templates/下的模板。我们通过增加一个 templates/blog/detail.html 模板覆写默认的 blog/templates/blog/detail.html 模板。
复用Django应用

假设你已经使用这个布局一段时间,有一天你会意识到你的新项目需要一个blog应用,这个从你的foo项目出来的应用将是完美的。所以你复制、粘贴文件……错误!现在你有这个应用的两个副本。假定你还记得,在一个副本中进行Bug修复和新功能增添需要手动地在项目间迁移。

相反,为你的博客创建一个新的目录,并把foo/blog/目录中的内容放入其中。同时,调整现有的foo项目和你的新项目来进行安装。

如果需要的话,它们仍然可以跟踪这两个不同版本的应用,或持续更新,且获得它们不断发展中的所有bug修复和新功能。你仍然可以在每个项目的基础上,根据需求覆写模板和静态资源,所以这样做真的没有任何问题。

Python 相关文章推荐
Python中使用第三方库xlutils来追加写入Excel文件示例
Apr 05 Python
在MAC上搭建python数据分析开发环境
Jan 26 Python
Python设计模式编程中解释器模式的简单程序示例分享
Mar 02 Python
python中快速进行多个字符替换的方法小结
Dec 15 Python
windows下python之mysqldb模块安装方法
Sep 07 Python
python 按不同维度求和,最值,均值的实例
Jun 28 Python
Python中的支持向量机SVM的使用(附实例代码)
Jun 26 Python
在cmd中查看python的安装路径方法
Jul 03 Python
完美解决python3.7 pip升级 拒绝访问问题
Jul 12 Python
用python中的matplotlib绘制方程图像代码
Nov 21 Python
Python响应对象text属性乱码解决方案
Mar 31 Python
Python3如何实现Win10桌面自动切换
Aug 11 Python
Python线程中对join方法的运用的教程
Apr 09 #Python
在Python的Flask框架下使用sqlalchemy库的简单教程
Apr 09 #Python
详解Python中的正则表达式的用法
Apr 09 #Python
Python中几种操作字符串的方法的介绍
Apr 09 #Python
详解Python中的__new__()方法的使用
Apr 09 #Python
Python中动态获取对象的属性和方法的教程
Apr 09 #Python
详解Python中的循环语句的用法
Apr 09 #Python
You might like
在PHP中使用反射技术的架构插件使用说明
2010/05/18 PHP
PHP编程文件处理类SplFileObject和SplFileInfo用法实例分析
2017/07/22 PHP
PHP+MySQL实现消息队列的方法分析
2018/05/09 PHP
JavaScript 构造函数 面相对象学习必备知识
2010/06/09 Javascript
js动态添加表格数据使用insertRow和insertCell实现
2014/05/22 Javascript
JS实现图片产生波纹一样flash效果的方法
2015/02/27 Javascript
jQuery实现的淡入淡出二级菜单效果代码
2015/09/15 Javascript
jQuery实现从身份证号中获取出生日期和性别的方法分析
2016/02/25 Javascript
Ext JS框架程序中阻止键盘触发回退或者刷新页面的代码分享
2016/06/07 Javascript
两种简单的跨域方法(jsonp、php)
2017/01/02 Javascript
浅谈js中startsWith 函数不能在任何浏览器兼容的问题
2017/03/01 Javascript
jQuery插件zTree实现单独选中根节点中第一个节点示例
2017/03/08 Javascript
JavaScript装饰器函数(Decorator)实例详解
2017/03/30 Javascript
JavaScript实现重力下落与弹性效果的方法分析
2017/12/20 Javascript
javascript实现计算指定范围内的质数示例
2018/12/29 Javascript
微信小程序实现手势滑动效果
2019/08/26 Javascript
javascript实现一款好看的秒表计时器
2020/09/05 Javascript
如何在JavaScript中正确处理变量
2020/12/25 Javascript
Python使用scrapy采集时伪装成HTTP/1.1的方法
2015/04/08 Python
Python实现统计英文单词个数及字符串分割代码
2015/05/28 Python
Python实现希尔排序算法的原理与用法实例分析
2017/11/23 Python
查看django执行的sql语句及消耗时间的两种方法
2018/05/29 Python
python-itchat 统计微信群、好友数量,及原始消息数据的实例
2019/02/21 Python
python过滤中英文标点符号的实例代码
2019/07/15 Python
IRO美国官网:法国服装品牌
2018/03/06 全球购物
寄语十八大感言
2014/02/07 职场文书
最常使用的求职信
2014/05/25 职场文书
群众路线教育实践活动的心得体会
2014/09/03 职场文书
2014年教育教学工作总结
2014/11/13 职场文书
2015年暑期社会实践活动总结
2015/03/27 职场文书
运动会开幕式主持词
2015/07/01 职场文书
环境卫生标语
2015/08/03 职场文书
《最后一头战象》读后感:动物也有感情
2020/01/02 职场文书
详解JavaScript中的执行上下文及调用堆栈
2021/04/29 Javascript
HTML中的表单元素介绍
2022/02/28 HTML / CSS
将MySQL的表数据全量导入clichhouse库中
2022/03/21 MySQL