Django项目结构工程化

Django项目结构工程化

假设我们项目的名字为sort,当我们通过IDE或是django-admin startproject命令初始化了一个Django项目时,项目结构往往看起来像这样

(venv) Ember:sort admin$ tree -L 2
.
├── manage.py
└── sort
    ├── __init__.py
    ├── asgi.py
    ├── settings.py
    ├── urls.py
    └── wsgi.py

其中我们知道,manage.py是项目的管理脚本文件。sort文件夹中则存放着与项目配置相关的文件。asgi.pywsgi.py负责提供了项目网关入口;settings.py提供了项目整体的设置;urls.py中描述了项目最高级路由。

现在这个目录看起来还是比较好理解的,下面让我们添加几个实际的Django-app

(venv) Ember:sort admin$ python manage.py startapp foo
(venv) Ember:sort admin$ python manage.py startapp bar
(venv) Ember:sort admin$ tree -L 2
.
├── bar
│   ├── __init__.py
│   ├── admin.py
│   ├── apps.py
│   ├── migrations
│   ├── models.py
│   ├── tests.py
│   └── views.py
├── foo
│   ├── __init__.py
│   ├── admin.py
│   ├── apps.py
│   ├── migrations
│   ├── models.py
│   ├── tests.py
│   └── views.py
├── manage.py
└── sort
    ├── __init__.py
    ├── __pycache__
    ├── asgi.py
    ├── settings.py
    ├── urls.py
    └── wsgi.py

如你所见,我们为项目添加了两个app,一个foo和一个bar。项目结构现在看起来像这样。

这时候问题就出现了,按照Django项目默认组织的逻辑,app直接创建在根目录下,而项目的配置信息则存在于根目录下的同名文件夹内,这就造成了下列问题

  1. 项目下与项目同名的文件夹让人迷惑
  2. app目录和项目配置文件夹没有明确差异

下面我们来分别解决这一问题

分离项目配置

在实际业务中,项目配置往往都存放于项目根目录路径下,因此在这里我们不妨也这么做,简单来说就是将sort文件夹中的东西全部拿出来。

我们先一股脑的把东西都拿出来,然后删除sort文件夹,现在你的项目看起来应该是这样的。

(venv) Ember:sort lvtiancheng$ tree -L 2
.
├── __init__.py
├── bar
│   ├── __init__.py
│   ├── admin.py
│   ├── apps.py
│   ├── migrations
│   ├── models.py
│   ├── tests.py
│   └── views.py
├── foo
│   ├── __init__.py
│   ├── admin.py
│   ├── apps.py
│   ├── migrations
│   ├── models.py
│   ├── tests.py
│   └── views.py
├── asgi.py
├── manage.py
├── settings.py
├── urls.py
└── wsgi.py

仅仅把内容拿出来是不够的,我们还需要改变拿出来的文件的信息。先让我们看看asgi.py

# asgi.py
"""
ASGI config for sort project.

It exposes the ASGI callable as a module-level variable named ``application``.

For more information on this file, see
https://docs.djangoproject.com/en/3.1/howto/deployment/asgi/
"""

import os

from django.core.asgi import get_asgi_application

# 原来的信息表示他的配置文件参考sort.settings,我们把settings提升到根目录,因此可以去掉sort
# os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'sort.settings')

# 修改后
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'settings')

application = get_asgi_application()

wsgi.pyasgi.py更改的逻辑基本相同,都是去掉sort

然后是manage.py;作为项目的入口文件,我们看到他同样需要更换settings的路径

# manage.py
#!/usr/bin/env python
"""Django's command-line utility for administrative tasks."""
import os
import sys


def main():
    """Run administrative tasks."""
    # 修改前
    # os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'sort.settings')
    # 修改后
		os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'settings')
    try:
        from django.core.management import execute_from_command_line
    except ImportError as exc:
        raise ImportError(
            "Couldn't import Django. Are you sure it's installed and "
            "available on your PYTHONPATH environment variable? Did you "
            "forget to activate a virtual environment?"
        ) from exc
    execute_from_command_line(sys.argv)


if __name__ == '__main__':
    main()

urls.py的配置位于settings.py内,修改settings.py时一并修改

下面修改settings.py

# settings.py

# 修改项目根目录
# BASE_DIR = Path(__file__).resolve(strict=True).parent.parent
BASE_DIR = Path(__file__).resolve(strict=True).parent

# 修改urls
# ROOT_URLCONF = 'sort.urls'
ROOT_URLCONF = 'urls'

# 修改wsgi
# WSGI_APPLICATION = 'sort.wsgi.application'
WSGI_APPLICATION = 'wsgi.application'

全部修改完成后,执行python manage.py runserver启动开发服务器看看能否成功运行,若能运行,则修改内容完成。

整理项目apps

在实际的项目中,我们更希望把apps放在一个文件夹进行整理,下面我们就来做这一步工作。

项目下新建apps文件夹,把bar和foo都扔进去

(venv) Ember:sort lvtiancheng$ tree -L 2
.
├── __init__.py
│
├── apps
│   ├── bar
│   └── foo
├── asgi.py
├── manage.py
├── settings.py
├── urls.py
└── wsgi.py

这种情况下,在settings内对app的安装路径就要做相应的调整


INSTALLED_APPS = [
    'apps.foo',
    'apps.bar',
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
]

此外,在其他python模块内引用apps也要做以下调整

/apps/foo/models.py
from django.db import models
# 新的引入方式(pycharm报错)
from apps.bar.models import Bar
# pycharm正常使用但项目无法运行的引入方式
# from bar.models import Bar

class Foo(models.Model):
    fk = models.ForeignKey(Bar,on_delete=models.CASCADE)

然而,对于使用pycharm的同学来说,这可能让他们的代码失去代码提示并在IDE内报错(虽然项目能够运行)

解决这一问题,通常通过修改settings里的设置解决。

import sys
# 将apps/加入系统路径
sys.path.insert(0, str(BASE_DIR / 'apps'))

# 恢复apps安装名
INSTALLED_APPS = [
    'foo',
    'bar',
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
]

修改以上两个配置项,即可实现对apps的整理和IDE的高亮提示

这也就形成了两种app组织风格,一种是在注册和引用时时刻表明它属于哪个包,这在大型项目中会比较有利。我们可以对不同的应用进行一目了然的分包管理,例如分别建立apps和libs文件夹。然而IDE会因此失去代码提醒。可能pycharm提供了一些可以更改的设置,但是我个人对探索ide没啥兴趣,如果有这方面比较了解的老哥还请不吝赐教。

第二种设置则是将人工分离的app包路径都通过settings.py注册到系统路径中,这样更加简洁,也不会影响IDE的代码高亮。唯一问题就是当应用很多的时候会比较混乱。

拆分settings

下一步,让我们来看看settings.py

之所以要拆分settings,主要还是针对不同环境部署的考虑。在实际的工程中,我们往往需要为开发、测试和生产等多个不同环境准备多套配置文件,这些配置文件囊括数据库账号密码,项目密钥等。

首先还是老样子,将settings从一个文件转化为一个python模块,再将原有的settings.py改名为base.py放在这个模块内,同时新建prod.pydev.py分别指代开发环境和生产环境。

项目结构现在看起来像这样

.
├── __init__.py
│
├── apps
│   ├── __init__.py
│   ├── bar
│   └── foo
├── asgi.py
├── manage.py
├── settings
│   ├── __init__.py
│   ├── base.py
│   ├── dev.py
│   └── prod.py
├── urls.py
└── wsgi.py

我们在base.py内放通用配置,在dev.pyprod.py内则放为不同环境准备的配置信息。当然首先,我们需要恢复base.py(原settings.py)内的项目根目录(因为相对路径又发生了改变)

# base.py
# 恢复默认路径
BASE_DIR = Path(__file__).resolve(strict=True).parent.parent
# BASE_DIR = Path(__file__).resolve(strict=True).parent

下面我们来举几个例子说明哪些配置应当被拆分出来

# base.py

# 项目密钥
SECRET_KEY = ''

# 是否为DEBUG状态
DEBUG = True

#允许访问主机
ALLOWED_HOSTS = []

# 数据库配置
DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.sqlite3',
        'NAME': BASE_DIR / 'db.sqlite3',
    }
}
# dev.py
from .base.py import *

# 开发环境密钥
SECRET_KEY = 'xxxxxxxxxxxxxxxxx'
# 开发环境,DEBUG=True
DEBUG = True
ALLOWED_HOSTS = ["*"]

# 开发用数据库
DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.sqlite3',
        'NAME': BASE_DIR / 'db.sqlite3',
    }
}
# prod.py
from .base.py import *

# 生产环境密钥
SECRET_KEY = 'yyyyyyyyyyyyyyyyyy'

# 生产环境下,DEBUG=False
DEBUG = False

# 生产用数据库
DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.mysql', # 数据库引擎
        'NAME': 'django_mysql', # 数据库名
        'USER': 'root', # 账号
        'PASSWORD': 'root', # 密码
        'HOST': '127.0.0.1', # HOST
        'POST': 3306, # 端口
    }
}

观察这几个配置的例子,可以发现,拆分配置的本质就是对base.py内变量的重写。

配置拆分完成之后,我们还需指定启动项目所需的配置文件。这部分有点类似我们在分离项目配置时做的那样,只不过这次从删除变成了增加

# manage.py
# 开发环境下常用manage.py启动项目,因此默认设置采用dev
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'settings.dev')

# asgi.py/wsgi.py
# 开发环境下采用生产环境,默认采用prod
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'settings.prod')

此外,还可以在命令行内设置本次命令执行时采用的配置

# 临时使用prod配置
python manage.py runserver --setting=setting.prod

其他

至此,我们已经基本完成了对一个Django项目工程化的操作,但要让这个项目在维护时更加方便便捷,还可以添加以下文件

.gitignore

.gitignore

.gitignore就像他的名字描述的那样,符合该文件内描述的规则的文件将不会被加入git仓库内。通过这一文件我们可以避免向仓库内添加重复的静态文件、编译器缓存、IDE临时文件等等,下面是一个jetbrain通用的.gitignore文件例子,你也可以增加自己的规则

# Created by .ignore support plugin (hsz.mobi)
### macOS template
# General
.DS_Store
.AppleDouble
.LSOverride

# Icon must end with two \r
Icon

# Thumbnails
._*

# Files that might appear in the root of a volume
.DocumentRevisions-V100
.fseventsd
.Spotlight-V100
.TemporaryItems
.Trashes
.VolumeIcon.icns
.com.apple.timemachine.donotpresent

# Directories potentially created on remote AFP share
.AppleDB
.AppleDesktop
Network Trash Folder
Temporary Items
.apdisk

### Python template
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
*$py.class

# C extensions
*.so

# Distribution / packaging
.Python
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
pip-wheel-metadata/
share/python-wheels/
*.egg-info/
.installed.cfg
*.egg
MANIFEST

# PyInstaller
#  Usually these files are written by a python script from a template
#  before PyInstaller builds the exe, so as to inject date/other infos into it.
*.manifest
*.spec

# Installer logs
pip-log.txt
pip-delete-this-directory.txt

# Unit test / coverage reports
htmlcov/
.tox/
.nox/
.coverage
.coverage.*
.cache
nosetests.xml
coverage.xml
*.cover
.hypothesis/
.pytest_cache/

# Translations
*.mo
*.pot

# Django stuff:
*.log
local_settings.py
db.sqlite3

# Flask stuff:
instance/
.webassets-cache

# Scrapy stuff:
.scrapy

# Sphinx documentation
docs/_build/

# PyBuilder
target/

# Jupyter Notebook
.ipynb_checkpoints

# IPython
profile_default/
ipython_config.py

# pyenv
.python-version

# pipenv
#   According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
#   However, in case of collaboration, if having platform-specific dependencies or dependencies
#   having no cross-platform support, pipenv may install dependencies that don't work, or not
#   install all needed dependencies.
#Pipfile.lock

# celery beat schedule file
celerybeat-schedule

# SageMath parsed files
*.sage.py

# Environments
.env
.venv
env/
venv/
ENV/
env.bak/
venv.bak/

# Spyder project settings
.spyderproject
.spyproject

# Rope project settings
.ropeproject

# mkdocs documentation
/site

# mypy
.mypy_cache/
.dmypy.json
dmypy.json

# Pyre type checker
.pyre/

### Windows template
# Windows thumbnail cache files
Thumbs.db
Thumbs.db:encryptable
ehthumbs.db
ehthumbs_vista.db

# Dump file
*.stackdump

# Folder config file
[Dd]esktop.ini

# Recycle Bin used on file shares
$RECYCLE.BIN/

# Windows Installer files
*.cab
*.msi
*.msix
*.msm
*.msp

# Windows shortcuts
*.lnk


requirements.txt

需求文件内包含了这个项目需要的包,通常由pip freeze > requirements.txt命令生成。

当我们将项目部署到新的python环境时,执行pip install -r requirements命令即可安装全部依赖

此外,我们也可以像settings一样,为多个不同的环境准备多套依赖描述文件,只需对其内容做拆分即可

# requirements/base.txt
asgiref==3.2.10
Django==3.1
pytz==2020.1
sqlparse==0.3.1
# requirements/prod.txt
-r base.txt # 安装base.txt内的依赖
mysqlclient==1.4.4

此时,我们可以直接通过pip install -r requirements/prod.txt命令来安装全部适用于生产环境下的依赖

题外话:Django作为一个python框架,同样适用python的虚拟环境管理器(pipenv、virtualenv)等,考虑到pipenv对容器支持并不好,而virtualenv结合virtualenvwrapper后十分好用,一般推荐采用virtualenv作为虚拟环境管理器。

总之,以上只是一些个人在使用Django做web开发的一些个人见解。要管理好一个Django项目仍然有很多可以改进的地方,本文只提供了一种相对简单而有条理的方式。python常常因其弱工程化而为人诟病,然而通过合理的项目组织和管理方式,可以在很大程度上提升项目开发的效率。要想更好地维护和管理工程,就需要你创建很多项目,并且持续地改进你的代码

  • 3
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Python Django 是一种流行的Web开发框架,它使用Python语言编写。它提供了很多强大的功能和工具,使开发人员能够更轻松地构建高效、可扩展、安全的Web应用程序。 使用Python Django,我们可以快速构建一个功能完备的网站或Web应用程序。它提供了一个强大的模型-视图-控制器(MVC)架构,帮助我们将应用程序的逻辑和用户界面进行分离,使得代码更加清晰且易于维护。 在Django 中,我们可以定义模型来表示应用程序中的数据结构。通过定义数据库模式和字段属性,Django 可以自动地创建和更新数据库表。这使得我们可以轻松地进行数据库操作,如插入、更新和查询数据。 另外,Django 还提供了一个简洁且强大的模板语言,用于生成用户界面。我们可以创建模板来定义页面的结构和样式,并使用模板语言来动态生成页面的内容。这使得我们能够更好地与前端工程师协作,实现良好的用户体验。 Django 中还集成了一个强大的管理后台,用于管理网站的后台数据。通过定义管理界面,我们可以轻松地进行数据的增删改查,而无需编写额外的代码。 此外,Django 还提供了很多有用的功能和扩展,如用户认证系统、表单处理、国际化支持等等。以及它还有很多社区贡献的第三方库和插件可供选择,使得我们能够更加高效地开发和扩展我们的应用程序。 总的来说,Python Django 是一个功能强大的Web开发框架,它提供了很多方便的工具和功能,使得开发人员能够更轻松地构建高质量的Web应用程序。无论是小型的个人项目还是大型的企业应用,Django 都是一个非常好的选择。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值