什么是django应用,settings,以及各种相关联的目录的最佳布局方式? Django1.4版本以后更新了默认的项目布局,这项工作花费了很长时间,但是现在还有更好建议可以使它变的更好。

关于这个问题,我们将结合我们的实际经验来进行探讨。这些布局实践是在django1.7.1版本下进行的,但是同样适用于1.4之后的版本。

为什么这种布局方式相比是更好的

我们推荐的项目布局有以下优点:

1.允许你将项目中的app进行分离,重新打包,然后重用到其他别的项目中去。当你新建一个app的时候,你不清楚它是否可以重用,但以这种布局方式,当你想要把它重用到其他地方的时候,会省事很多。 2.鼓励设计出更有利于重用的app 3.细化的环境配置。在单一的settings中没有 if DEBUG == True 这样无用的话。 有个basic的基础配置文件,其他配置文件都是在此基础上进行重载。 4.细化的requirements依赖 5.项目级别的template和staic files,如果需要的话,可以覆盖默认的app级别 6.更小而且细化的测试文件,易于阅读和理解。

确保你有两个app,一个是blog,一个是users,两种环境,dev和prod 项目布局结构如下:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
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。如果你执行

1
django-admin.py startproject foo

你会得到如下的目录结构

1
2
3
4
5
6
7
foo/
        manage.py
        foo/
           __init__.py
           settings.py
           urls.py
           wsgi.py

在这里,我们有个顶层的目录foo,包含了manage.py和项目目录foo/foo。

修改Settings

这里我们去修改你糟糕的settings文件。我们这里展示了一种布局,我很惊奇很少有人知道可以这样做。我把它归咎于,人们只知道settings是python代码,但是却没有把它当做python代码看待。

我们这里有4种环境下分别对应的settings文件,dev, stage, jenkins, production。

配置步骤如下: 1.在foo/foo目录下,新建一个名为settings的目录,并且创建一个空的__init__.py文件。 2.将foo/foo/settings.py 移动到 foo/foo/settings/base.py 3.创建独立的dev.py, stage.py, jenkins.py, prod.py。 这四个新建的py文件 应该包含如下代码:

1
from bae import *

在本地开发环境下,我们想要DEBUG=True, 但是有时候,会不小心在生产环境下,将DEBUG模式打开,为了避免这种情况,我们只需要在foo/foo/settings/prod.py下新增DEBUG=False。

这里这样做实际上是,相当于是重载。

还有哪些其他可以适配的? 还有一点是,在staging,jenkins,和production环境下,往往需要指向不同的数据库,甚至是不同hosts下的数据库。 所以,在不同的环境中,各自适配即可。

使用上述的settings文件

使用上述settings文件是容易的,无论以哪种方式 比如: 在wsgi.py中可以这样设置

1
export DJANGO_SETTINGS_MODULE=foo.settings.jenkins

可能,你想用在命令行选项下:

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

如果你使用gunicorn

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

settings下还有哪些可以适配?

另一个比较有用的tip是,修改一些默认设置从不可修改的元组,改为可以修改的列表。 以INSTALLED_APPS为例:

1
2
3
INSTALLED_APPS = (
   
)

修改为

1
2
3
INSTALLED_APPS = [
    
]

这样,我们可以在不同的环境下,新增或者删除INSTALLED_APPS中的选项了。 比如,我们只希望django-debug-toolbar安装在dev环境,而不是其他环境下。 这个技巧也被用在TEMPLATE_DIRS和MIDDLEWARE_CLASSES设置中。

另一个有用的技巧是,我们经常用来,将apps分为连个lists,一个作为prerequisites 另一个作为实际项目app。示例如下:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
PREREQ_APPS = [
   django.contrib.auth,
   django.contrib.contenttypes,
   
   debug_toolbar,
   imagekit,
   haystack,
]

PROJECT_APPS = [
   homepage,
   users,
   blog,
]

INSTALLED_APPS = PREREQ_APPS + PROJECT_APPS

为什么这是有用的?一个原因是,便于区分,django核心app,第三方app,和你自己项目内部的app。 ROJECT_APPS用来保存你自己项目内部的app,通常还被用来测试代码和检查代码覆盖。 通过PROJECT_APPS,你可以容易并且自动的,确保它们的测试代码在运行,代码覆盖被记录。

修正requirements文件

很多人有单独的requirements.txt文件,它们通常用来安装依赖,命令行代码如下:

1
pip install -r requirements.txt

对于小的项目来说,它足够用了。但是有一个技巧是,你可以在一个requirements文件中用-r来包含其他requirements文件。 比如我们可以有一个名为base.txt文件,并且我们在测试环境下,有一个requirements/test.txt文件,它的内容如下:

1
2
3
-r base.txt
pytest==2.5.2
coverage==3.7.1

我承认,这不是一个作用非常大的修改。但是它帮助我们分离了不同环境下的依赖配置。 比较有用的一点是,它减少了production环境下,pip安装的时间,因为可以避免安装开发环境下需要,但是production下不需要的依赖。

测试文件

为什么需要分离我们的测试文件? 主要的原因在于,如果你把测试都放在一个单独的test.py中,每个app最终会变得臃肿,难以测试,可读性变差。

当你和其他开发者合作开发的时候,你会减少很多代码合并的冲突(对于同一个文件,多人改动,容易造成代码冲突)

URLS

对于比较小的项目来说,可以把所有的url路由都配置到foo/urls.如果考虑可读性,重用性,建议在每个app里面都单独设置url.py,然后以incldue的方式包括项目的主url.py中。 不好的:

1
2
3
4
5
6
7
8
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),
)

好的:

1
2
3
4
5
urlpatterns = patterns(‘’,
    url(r^$’, HomePageView.as_view(), name=home),
    url(r^blog/, include(blog.urls)),
    url(r^user/, include(user.urls)),
)

模板和静态资源

在每个app下设置templates/和static/目录,可以帮助将app重用到别的项目中去。

通常情况下,app查找文件时,会默认加载app/templates下的模板,和app/static下面的静态文件

但是,我们可以从项目foo/tempaltes下覆盖掉app下面的模板。比如,templates/blog/detail.html会覆盖掉 blog/templates/blog/detail.html下面的模板。

适用于,比如说,我们引入了第三方的app,但是对第三方的模板不满意,需要做一些修改的情况

重用django app

假设你已经用这种布局一段时间了,你的新项目site中也需要一个类似blog的东西,你发现你的foo项目下的blog正好可以满足需求。 所以,你就把foo下面的blog代码粘贴复制到了你的新项目site中。 但是,这样做是不对的。因为,比如说你的foo下面的blog有bug或者新特性增加,你必须手动地把它移动到新项目site中。

相反,你应该为你的blog单独新建一个repo,并且把你的foo/blog放到其中。然后在你的现有项目和新项目中通过pip来安装。

此处的意思也就是通用的app,可以做成一个第三方的app,便于管理。

维护和更新的话,交与第三方app的作者负责就好啦。

你仍然可以在项目级别上,覆盖掉template模板和static资源,这样做没有什么问题。

同样的道理,不要尝试去修改第三方app的源码

其他资源:

cookiecutter-django可以用于快速构建django项目布局 django最佳实践的书籍推荐: Two Scoops of Django: Best Practices For Django

原文章出处:http://www.revsys.com/blog/2014/nov/21/recommended-django-project-layout/