对于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多线程扫描端口示例
Jan 16 Python
Python 分析Nginx访问日志并保存到MySQL数据库实例
Mar 13 Python
python一键升级所有pip package的方法
Jan 16 Python
Python中几种导入模块的方式总结
Apr 27 Python
Python实现的读取电脑硬件信息功能示例
May 30 Python
Python版名片管理系统
Nov 30 Python
Python实现计算字符串中出现次数最多的字符示例
Jan 21 Python
Django接收自定义http header过程详解
Aug 23 Python
如何在python开发工具PyCharm中搭建QtPy环境(教程详解)
Feb 04 Python
python代码能做成软件吗
Jul 24 Python
详解python os.path.exists判断文件或文件夹是否存在
Nov 16 Python
教你用python实现一个无界面的小型图书管理系统
May 21 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
删除及到期域名的查看(抢域名必备哦)
2008/05/14 PHP
探讨PHP JSON中文乱码的解决方法详解
2013/06/06 PHP
根据ip调用新浪api获取城市名并转成拼音
2014/03/07 PHP
ThinkPHP通过AJAX返回JSON的两种实现方法
2014/12/18 PHP
php基于表单密码验证与HTTP验证用法实例
2015/01/06 PHP
Zend Framework框架中实现Ajax的方法示例
2017/06/27 PHP
jQuery对象数据缓存Cache原理及jQuery.data方法区别介绍
2013/04/07 Javascript
js 实现 input type=&quot;file&quot; 文件上传示例代码
2013/08/07 Javascript
javascript if条件判断方法小结
2014/05/17 Javascript
Blocksit插件实现瀑布流数据无限( 异步)加载
2014/06/20 Javascript
node通过npm写一个cli命令行工具
2017/10/12 Javascript
Vue实现渲染数据后控制滚动条位置(推荐)
2019/12/09 Javascript
微信小程序 (地址选择1)--选取搜索地点并显示效果
2019/12/17 Javascript
vue实现lodop打印功能的示例
2020/11/11 Javascript
Python发送以整个文件夹的内容为附件的邮件的教程
2015/05/06 Python
Python给你的头像加上圣诞帽
2018/01/04 Python
Flask之flask-session的具体使用
2018/07/26 Python
解决jupyter notebook 前面书写后面内容消失的问题
2020/04/13 Python
Python内存映射文件读写方式
2020/04/24 Python
Python 数据的累加与统计的示例代码
2020/08/03 Python
Python函数__new__及__init__作用及区别解析
2020/08/31 Python
PyCharm设置注释字体颜色以及是否倾斜的操作
2020/09/16 Python
英国DVD和蓝光碟片购买网站:Zoom.co.uk(电影和电视)
2019/09/23 全球购物
Hobbs官方网站:英国奢华女性时尚服装
2020/02/22 全球购物
圣彼得堡鲜花配送:Semicvetic
2020/09/15 全球购物
酒店服务实习自我鉴定
2013/09/22 职场文书
物业经理求职自我评价
2013/09/22 职场文书
本科生求职简历的自我评价
2013/10/21 职场文书
《这儿真好》教学反思
2014/02/22 职场文书
卫生巾广告词
2014/03/18 职场文书
大学生自我鉴定书
2014/03/24 职场文书
班风口号
2014/06/18 职场文书
工作年限证明范本
2015/06/15 职场文书
幼儿园托班开学寄语(2016秋季)
2015/12/03 职场文书
React forwardRef的使用方法及注意点
2021/06/13 Javascript
JAVA 线程池(池化技术)的实现原理
2022/04/28 Java/Android