对于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学习笔记(二)基础语法
Jun 06 Python
Python实现提取文章摘要的方法
Apr 21 Python
git进行版本控制心得详谈
Dec 10 Python
python贪婪匹配以及多行匹配的实例讲解
Apr 19 Python
Python pygorithm模块用法示例【常见算法测试】
Aug 16 Python
对Python使用mfcc的两种方式详解
Jan 09 Python
numpy concatenate数组拼接方法示例介绍
May 27 Python
Python PyInstaller库基本使用方法分析
Dec 12 Python
pandas的resample重采样的使用
Apr 24 Python
pandas to_excel 添加颜色操作
Jul 14 Python
用Python将GIF动图分解成多张静态图片
Jun 11 Python
PYTHON 使用 Pandas 删除某列指定值所在的行
Apr 28 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的ZipArchive类用法实例
2014/10/20 PHP
PHP中的随机性 你觉得自己幸运吗?
2016/01/22 PHP
PHP中localeconv()函数的用法
2019/03/26 PHP
YII框架模块化处理操作示例
2019/04/26 PHP
简单通用的JS滑动门代码
2008/12/19 Javascript
10个新的最有前途的JavaScript框架
2009/03/12 Javascript
在jQuery 1.5中使用deferred对象的代码(翻译)
2011/03/10 Javascript
不提示直接关闭网页窗口的JS示例代码
2013/12/17 Javascript
JavaScript中指定函数名称的相关方法
2015/06/04 Javascript
javascript单页面手势滑屏切换原理详解
2016/03/21 Javascript
jQuery绑定事件的几种实现方式
2016/05/09 Javascript
html中鼠标滚轮事件onmousewheel的处理方法
2016/11/11 Javascript
详解前后端分离之VueJS前端
2017/05/24 Javascript
JS中的三个循环小结
2017/06/20 Javascript
JavaScript判断输入是否为数字类型的方法总结
2017/09/28 Javascript
jquery实现的简单轮播图功能【适合新手】
2018/08/17 jQuery
Object.keys() 和 Object.getOwnPropertyNames() 的区别详解
2020/05/21 Javascript
[49:41]NB vs NAVI Supermajor小组赛A组 BO3 第一场 6.2
2018/06/03 DOTA
[01:23:45]DOTA2-DPC中国联赛 正赛 CDEC vs Dragon BO3 第一场 1月22日
2021/03/11 DOTA
python之wxPython应用实例
2014/09/28 Python
Python实现的用户登录系统功能示例
2018/02/05 Python
Python中出现IndentationError:unindent does not match any outer indentation level错误的解决方法
2020/04/18 Python
在pycharm 中添加运行参数的操作方法
2019/01/19 Python
python3使用QQ邮箱发送邮件
2020/05/20 Python
python实现得到当前登录用户信息的方法
2019/06/21 Python
django 微信网页授权登陆的实现
2019/07/30 Python
基于python解线性矩阵方程(numpy中的matrix类)
2019/10/21 Python
使用python快速实现不同机器间文件夹共享方式
2019/12/22 Python
Python脚本打包成可执行文件过程解析
2020/10/20 Python
python3定位并识别图片验证码实现自动登录功能
2021/01/29 Python
行政主管岗位职责
2013/11/18 职场文书
甜品蛋糕店创业计划书
2014/09/21 职场文书
2014年小学数学教师工作总结
2014/12/03 职场文书
离婚被告代理词
2015/05/23 职场文书
民政局未婚证明
2015/06/15 职场文书
python实战之90行代码写个猜数字游戏
2021/04/22 Python