对于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实现的解析crontab配置文件代码
Jun 30 Python
Python heapq使用详解及实例代码
Jan 25 Python
Python利用BeautifulSoup解析Html的方法示例
Jul 30 Python
Python多进程multiprocessing用法实例分析
Aug 18 Python
Python使用遗传算法解决最大流问题
Jan 29 Python
python删除某个字符
Mar 19 Python
python 信息同时输出到控制台与文件的实例讲解
May 11 Python
Python 隐藏输入密码时屏幕回显的实例
Feb 19 Python
opencv 图像腐蚀和图像膨胀的实现
Jul 07 Python
python -v 报错问题的解决方法
Sep 15 Python
opencv实现图像平移效果
Mar 24 Python
Pytorch可视化的几种实现方法
Jun 10 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的ASCII码转换类
2013/07/05 PHP
PHP 输出URL的快捷方式示例代码
2013/09/22 PHP
php图像验证码生成代码
2017/06/08 PHP
laravel 中如何使用ajax和vue总结
2017/08/16 PHP
IE autocomplete internet explorer's autocomplete
2007/06/30 Javascript
js parentElement和offsetParent之间的区别
2010/03/23 Javascript
火狐4、谷歌12不支持Jquery Validator的解决方法分享
2011/06/20 Javascript
JavaScript中for..in循环陷阱介绍
2013/11/12 Javascript
使用jQuery将多条数据插入模态框的实现代码
2014/10/08 Javascript
用JavaScript判断CSS浏览器类型前缀的两种方法
2015/10/08 Javascript
AngularJS入门教程之Scope(作用域)
2016/07/27 Javascript
5分钟打造简易高效的webpack常用配置
2017/07/04 Javascript
vue-cli2.9.3 详细教程
2018/04/23 Javascript
详解Angular6.0使用路由步骤(共7步)
2018/06/29 Javascript
vue实现图片预览组件封装与使用
2019/07/13 Javascript
JQuery实现简单的复选框树形结构图示例【附源码下载】
2019/07/16 jQuery
详解Vue-cli3.X使用px2rem遇到的问题
2019/08/09 Javascript
微信小程序自定义组件components(代码详解)
2019/10/21 Javascript
javascript 原型与原型链的理解及实例分析
2019/11/23 Javascript
vue中渲染对象中属性时显示未定义的解决
2020/07/31 Javascript
[01:03]DOTA2新的征程 你的脚印值得踏上
2014/08/13 DOTA
Python使用cx_Oracle模块将oracle中数据导出到csv文件的方法
2015/05/16 Python
理解Python垃圾回收机制
2016/02/12 Python
python实现排序算法解析
2018/09/08 Python
python操作ini类型配置文件的实例教程
2020/10/30 Python
银河香水:Galaxy Perfume
2019/03/25 全球购物
澳大利亚网上书店:QBD
2021/01/09 全球购物
华为慧通面试题
2012/09/11 面试题
幼教个人求职信范文
2013/12/02 职场文书
纺织工程专业个人求职信范文
2014/01/27 职场文书
班级旅游计划书
2014/05/03 职场文书
2014年建筑工作总结
2014/11/26 职场文书
优秀教师推荐材料
2014/12/16 职场文书
工作检讨书怎么写
2015/01/23 职场文书
spring cloud eureka 服务启动失败的原因分析及解决方法
2022/03/17 Java/Android
SpringBoot全局异常处理方案分享
2022/05/25 Java/Android