Django项目工作目录结构的最佳实践

257

我知道实际上没有单一的正确方式。然而,我发现很难创建一个对每个开发者和管理员都有效且保持清洁的目录结构。大多数github项目中有一些标准结构。但它不显示如何组织其他文件以及计算机上的所有项目。

在开发机器上组织所有这些目录的最方便方式是什么?您如何命名它们,以及如何连接并部署到服务器?

  • projects(您正在处理的所有项目)
  • source files(应用程序本身)
  • 版本库的工作副本(我使用git)
  • 虚拟环境(我喜欢将其放在项目附近)
  • 静态根(用于已编译的静态文件)
  • 媒体根(用于上传的媒体文件)
  • README
  • LICENSE
  • 文档
  • 草图
  • 示例(一个使用此项目提供的应用程序的示例项目)
  • 数据库(如果使用了sqlite)
  • 在项目成功工作所需的其他任何内容

我想解决的问题:

  • 好的目录名称,以便其用途清晰明确。
  • 将所有项目文件(包括virtualenv)放在一个地方,以便我可以轻松地复制、移动、归档、删除整个项目或估计磁盘空间使用情况。
  • 创建某些所选文件集的多个副本,例如整个应用程序、版本库或virtualenv,同时保留我不想克隆的其他文件的单个副本。
  • 通过rsync选择一个目录简单地将正确的文件集部署到服务器上。
6个回答

360

我在~/projects/目录中有两种不同结构的Django“项目”:

  • 独立网站
  • 可插拔的应用程序

独立网站

大多数是私人项目,但不一定。它通常是这样的:

~/projects/project_name/

docs/               # documentation
scripts/
  manage.py         # installed to PATH via setup.py
project_name/       # project dir (the one which django-admin.py creates)
  apps/             # project-specific applications
    accounts/       # most frequent app, with custom user model
    __init__.py
    ...
  settings/         # settings for different environments, see below
    __init__.py
    production.py
    development.py
    ...
        
  __init__.py       # contains project version
  urls.py
  wsgi.py
static/             # site-specific static files
templates/          # site-specific templates
tests/              # site-specific tests (mostly in-browser ones)
tmp/                # excluded from git
setup.py
requirements.txt
requirements_dev.txt
pytest.ini
...

设置

主要设置是生产环境的设置。其他文件(如staging.pydevelopment.py)仅从production.py导入所有内容,并仅覆盖必要的变量。

对于每个环境,都有单独的设置文件,例如生产环境和开发环境。在某些项目中,我还有测试(用于测试运行程序),暂存环境(在最终部署之前进行检查)和heroku(用于部署到heroku)设置。

需求

我更喜欢直接在setup.py中指定要求。仅在开发/测试环境中需要的那些要求我才会放在requirements_dev.txt中。

某些服务(如heroku)需要在根目录中具有requirements.txt

setup.py

在使用setuptools部署项目时很有用。它将manage.py添加到PATH中,因此我可以直接运行manage.py(任何地方)。

特定于项目的应用程序

我曾经将这些应用程序放入project_name/apps/目录中,并使用相对导入进行导入。

模板/静态/本地化/测试文件

我将这些模板和静态文件放入全局模板/静态目录中,而不是每个应用程序内部。通常由人编辑这些文件,他们不关心项目代码结构或python等内容。如果您是独自工作或小团队的全栈开发人员,则可以创建每个应用程序独立的模板/静态目录。这只是一种口味问题。

对于本地化,同样适用,尽管有时创建单独的本地化目录很方便。

测试通常最好放在每个应用程序内部,但通常有许多集成/功能测试测试更多应用程序共同工作,因此全局测试目录确实有意义。

临时目录

在项目根目录中有一个临时目录,被排除在版本控制之外。它用于在开发过程中存储媒体/静态文件和sqlite数据库。可以随时删除tmp中的所有内容而不会出现问题。

Virtualenv

我更喜欢virtualenvwrapper并将所有虚拟环境放置在~/.venvs目录中,但您可以将其放置在tmp/中以保持一致。

项目模板

我为此设置创建了项目模板:django-start-template

部署

该项目的部署如下:

source $VENV/bin/activate
export DJANGO_SETTINGS_MODULE=project_name.settings.production
git pull
pip install -r requirements.txt

# Update database, static files, locales
manage.py syncdb  --noinput
manage.py migrate
manage.py collectstatic --noinput
manage.py makemessages -a
manage.py compilemessages

# restart wsgi
touch project_name/wsgi.py

您可以使用rsync,而不是git,但仍需要运行一批命令来更新您的环境。

最近,我制作了django-deploy应用程序,它允许我运行单个管理命令来更新环境,但我仅在一个项目中使用过它,并且我仍在尝试中。

草图和草稿

我将模板的草案放在全局templates/目录中。我猜想可以在项目根目录中创建sketches/文件夹,但我还没有使用过它。

可插拔应用程序

这些应用程序通常准备发布为开源。我从django-forme中采取了下面的示例。

~/projects/django-app/

docs/
app/
tests/
example_project/
LICENCE
MANIFEST.in
README.md
setup.py
pytest.ini
tox.ini
.travis.yml
...

目录的名称应该很清晰(我希望如此)。我将测试文件放在应用程序目录之外,但实际上这并不重要。重要的是提供READMEsetup.py,这样包就可以通过pip轻松安装。


1
谢谢!我喜欢你的结构。它给了我有用的想法。关于使用setup.py进行要求和将manage.py安装到PATH中的好点子。你能展示一下最后一件事情怎么做吗?还有一个好点子是关于'tmp'目录。我宁愿把它命名为'local',这样我就可以在里面放置'env'、'tmp'和其他任何东西。这解决了与gitignore处理太多文件的问题。一个新问题是这个名称与'locale'太接近了。也许把'locale'移动到核心应用程序'project_name'中会有意义,但不确定。只是不想因为坏名称而改变结构。有什么建议吗? - raacer
你可以使用rsync --exclude=...命令来复制这个目录结构,留下“非repo”目录。虽然不像cp那么直接,但是一个好的别名(copy_project='rsync --exclude=.git --exclude=...')就足够了。 - Tomáš Ehrlich
你是否曾经遇到过从'project/apps/app1/templates/app1/'自动加载模板时出现问题,其中有额外的应用程序目录?.. 我在设置中有这个: "sys.path.insert(0, os.path.join(PROJECT_DIR, 'apps'))" .. 但是应用程序模板没有被加载:-/ - GerardJP
一个很酷的结构!但是,我遇到了错误 :( 如何让manage.py在父目录中看到"{{ project_name }}.settings.production"? - Stan Zeez
@StanZeez 有两件事情要注意:1)setup.pymanage.py安装到虚拟环境的路径下,因此当您运行它时,它将不再在scripts目录中。2)模块 {{ project_name }}.settings.production 使用绝对路径指定,只要您的项目能够在Python路径中访问,它就会找到它。 - Tomáš Ehrlich
显示剩余5条评论

24

我的回答是基于我自己的工作经验和大部分来自Django两球这本书,我强烈推荐阅读,你可以在那里找到更详细的解释。我只回答其中一些问题,欢迎任何改进或纠正。但也可能有更正确的方法来实现相同的目的。

项目
我在个人目录中有一个主文件夹,用于维护我正在处理的所有项目。

源文件
我个人使用django项目根目录作为我的项目仓库根目录。但是在这本书中推荐将它们分开。我认为这是一个更好的方法,所以我希望逐步开始在我的项目中进行更改。

project_repository_folder/
    .gitignore
    Makefile
    LICENSE.rst
    docs/
    README.rst
    requirements.txt
    project_folder/
        manage.py
        media/
        app-1/
        app-2/
        ...
        app-n/
        static/
        templates/
        project/
            __init__.py
            settings/
                __init__.py
                base.py
                dev.py
                local.py
                test.py
                production.py
            ulrs.py
            wsgi.py

代码仓库
在 Django 开发中,Git 或 Mercurial 是最受欢迎的版本控制系统。备份方面,最常用的托管服务是 GitHubBitbucket

虚拟环境
我使用 virtualenv 和 virtualenvwrapper。安装第二个之后,你需要设置你的工作目录。按照 virtualenvwrapper 的安装指南,我的目录在 /home/envs 下,但我认为最重要的不是它的位置,而是在使用虚拟环境时保持 requirements.txt 文件的最新状态。

pip freeze -l > requirements.txt 

静态根目录
项目文件夹

媒体根目录
项目文件夹

自述文件
仓库根目录

许可证
仓库根目录

文档
仓库根目录。这些Python包可以帮助您更轻松地维护文档:

示意图

示例

数据库


感谢您分享您的经验。在您的结构中有很多“project*”目录。您在实际生活中可能不使用这样的名称,对吧?假设我们有一个“todo”项目。在这种情况下,您如何命名这些目录?我在您当前的结构中看到的问题是将存储库与非存储库文件混合在一起(正如您上面所指出的)。将任何垃圾添加到.gitignore可能会很烦人,不是吗?另一个可疑的事情是将env目录保持远离项目本身。这有意义吗?为什么不创建/docs、/statics等呢?即使git也喜欢坐在源文件旁边。 - raacer
我会给它们命名为:“todo_project” -> todo -> todo(或者可能是todoapp)。我认为这很重要,因为仓库文件夹位于目录层次结构的根目录中。但这只是我的观点。关于环境目录,当您需要设置生产环境时,只需键入:pip install -U -r requirements.txt即可完成。但是,正如我所说,没有一种解决方案适用于所有情况。 - cor
3
因此,主应用程序的路径为“projects/todo_project/todo/todo”。单词“projects”重复了两次,而单词“todo”重复了三次。这似乎像是“projects/project/my_project/project_dir/project/project”。名称非常不清楚。这是我试图解决的主要问题之一,即通过目录结构来命名目录以便于理解层次结构。那么仓库根目录呢?您能否解释一下它的重要性?另外,您能否解释一下将envs保持在主项目目录之外的好处是什么? - raacer

14

我不喜欢创建一个新的settings/目录。我只需添加名为settings_dev.pysettings_production.py的文件,这样我就不必编辑BASE_DIR。 下面的方法增加了默认结构而不是改变它。

mysite/                   # Project
    conf/
        locale/
            en_US/
            fr_FR/
            it_IT/
    mysite/
        __init__.py
        settings.py
        settings_dev.py
        settings_production.py
        urls.py
        wsgi.py
    static/
        admin/
            css/           # Custom back end styles
        css/               # Project front end styles
        fonts/
        images/
        js/
        sass/
    staticfiles/
    templates/             # Project templates
        includes/
            footer.html
            header.html
        index.html
    myapp/                 # Application
        core/
        migrations/
            __init__.py
        templates/         # Application templates
            myapp/
                index.html
        static/
            myapp/
                js/  
                css/
                images/
        __init__.py
        admin.py
        apps.py
        forms.py
        models.py
        models_foo.py
        models_bar.py
        views.py
    templatetags/          # Application with custom context processors and template tags
        __init__.py
        context_processors.py
        templatetags/
            __init__.py
            templatetag_extras.py
    gulpfile.js
    manage.py
    requirements.txt

我认为这个:

    settings.py
    settings_dev.py
    settings_production.py
比这个更好。
    settings/__init__.py
    settings/base.py
    settings/dev.py
    settings/production.py

这个概念同样适用于其他文件。


我通常将node_modules/bower_components/放在项目目录中默认的static/文件夹内。

有时为了Git Submodules会创建一个vendor/目录,但通常我会把它们放在static/文件夹中。


8
根据 Django 项目模板,应该遵循以下适当的目录结构:
[projectname]/                  <- project root
├── [projectname]/              <- Django root
│   ├── __init__.py
│   ├── settings/
│   │   ├── common.py
│   │   ├── development.py
│   │   ├── i18n.py
│   │   ├── __init__.py
│   │   └── production.py
│   ├── urls.py
│   └── wsgi.py
├── apps/
│   └── __init__.py
├── configs/
│   ├── apache2_vhost.sample
│   └── README
├── doc/
│   ├── Makefile
│   └── source/
│       └── *snap*
├── manage.py
├── README.rst
├── run/
│   ├── media/
│   │   └── README
│   ├── README
│   └── static/
│       └── README
├── static/
│   └── README
└── templates/
    ├── base.html
    ├── core
    │   └── login.html
    └── README

请查看 https://django-project-skeleton.readthedocs.io/en/latest/structure.html 获取最新的目录结构。

23
我讨厌那种 [项目名称]/[项目名称] 的方式! - raacer
3
“django-project-skeleton并不是‘Django文档’。更准确地说,可以说‘根据django-project-skeleton的说明,...’。” - David Winiecki
1
@raacer 这会导致测试失败... 当项目根目录与 Django 根目录同名时,我会收到 ModuleNotFoundError 错误 :/ - morsik

4

以下是我在系统上遵循的规则。

  1. 所有项目:我的主文件夹中有一个projects目录,即 ~/projects。所有项目都存储在其中。

  2. 单个项目:我使用许多开发者都用过的标准化结构模板,称为django-skel来管理单个项目。它基本上可以处理所有静态文件和媒体文件等。

  3. 虚拟环境:我在主目录下有一个virtualenvs目录来存储所有虚拟环境,即 ~/virtualenvs 。这使得我非常灵活,我知道我有哪些虚拟环境并且可以轻松地使用它们。

以上三点是我的工作环境的主要组成部分。

你提到的所有其他部分大多数情况下都取决于具体项目(例如,你可能会针对不同的项目使用不同的数据库)。因此,它们应该存在于其各自的项目中。


谢谢。当将存储库与非存储库文件混合时,添加任何垃圾到.gitignore可能会很烦人。不是吗?我的一些项目有多达十个或更多这样的文件和目录,所以这对我来说是一个真正的问题。另一个可疑的事情是将env dir保持远离项目本身。这种解决方案的灵活性在哪里?为什么不创建/docs、/statics等呢?即使git也喜欢坐在源文件旁边。我认为灵活性就是当我可以复制/移动/归档/删除整个项目目录,包括virtualenv,并且可以轻松地在一个项目中维护多个envs。 - raacer

3
你可以使用 https://github.com/Mischback/django-project-skeleton 存储库。
运行以下命令:
$ django-admin startproject --template=https://github.com/Mischback/django-project-skeleton/archive/development.zip [projectname]

结构大致如下:

[projectname]/                  <- project root
├── [projectname]/              <- Django root
│   ├── __init__.py
│   ├── settings/
│   │   ├── common.py
│   │   ├── development.py
│   │   ├── i18n.py
│   │   ├── __init__.py
│   │   └── production.py
│   ├── urls.py
│   └── wsgi.py
├── apps/
│   └── __init__.py
├── configs/
│   ├── apache2_vhost.sample
│   └── README
├── doc/
│   ├── Makefile
│   └── source/
│       └── *snap*
├── manage.py
├── README.rst
├── run/
│   ├── media/
│   │   └── README
│   ├── README
│   └── static/
│       └── README
├── static/
│   └── README
└── templates/
    ├── base.html
    ├── core
    │   └── login.html
    └── README

有没有提到如何将业务逻辑与应用程序的其余部分解耦,以及如何测试它并将其插入视图和数据层之间?我认为这对于项目组织结构非常基础。 - Fed

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接