多应用统一目录管理

在实际Django项目开发中,创建工程之后比如demoproj,在工程目录下会存在一个同名的文件夹作为项目的入口(比如,公共配置、URL规则等)和一个manage.py管理文件。

默认创建应用的时候,会在 manage.py 同级目录下创建,随着开发,应用可能越来越多,这个时候建议把所有应用统一放到一个目录下管理,比如都放到apps目录下。

项目结构编程如下

| - demoproj
| - - demoproj
| - - manage.py
| - - apps
| - - - user(app)
| - - - cmdb(app)
| - - - ticket(app)
| - - - ops(app)
| - - - ...

目录结构调整之后,需要修改 settings.py 配置来适配结构

# demoproj/settings.py
import os
import sys

# 
BASE_DIR = Path(__file__).resolve().parent.parent
# 以下是新增
sys.path.insert(0, os.path.join(BASE_DIR, 'apps'))

这个时候,从命令行模式使用角度来说,项目是没有任何问题的。

但是有几个特殊的地方还是需要注意下:

1、创建新的应用app的时候

cd apps
python ../manage.py startapp new_appname

或者在 manage.py 同级目录下创建之后,在手动移动到apps 下,建议前者

2、如果是使用命令行开发、或者 Sublime、Vscode 工具开发,到此就不需要额外配置什么

3、如果是使用 PyCharm 工具开发,需要把 apps 配置成 Source Root ,这由于该工具本身的特性决定的

比如在 cmdb 应用的导入 user应用的User模型

# cmdb/models.py
from user.models import User

这样就不会有错误提示, 不然就会有 Unresolved reference 'user' 这样的错误提示。

具体如何配置可以参考网上教程。

应用之外使用Model

一般Django项目开发中,功能逻辑都是写到某个应用中去的,然后通过Django的URL进行方法。

但是在某些情况下会出现在应用之外使用某个应用中定义的模型来完成一些特性功能。

举个例子,在开发运维管理平台中,定了 CDN 资产模型完成了逻辑功能开发,在项目上线之前,需要做一次数据初始化,一般会开发一个工具脚本,从云厂商接口获取数据写入对应的数据库,数据写入会借助于对应的模型来实现。

该脚本工具肯定是独立在Django应用之外的。但是又要使用 Django 中定义的模型。比如下面结构中的 init_cdn.py

| - demoproj
| - - demoproj
| - - manage.py
| - - apps
| - - - cmdb(app)
| - - - ...
| - - scripts
| - - - init_cdn.py

这个时候就需要在脚本中做特殊配置

# scripts/init_cdn.py
import os
import django

os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'demoproj.settings')
# 很关键的配置
django.setup()

from cmdb.models import CDN
# 其他常规功能逻辑

1、如上的配置需要写到该文件的最开始部分

2、切记需要 django.setup()

晚上很多教程说只要 os.environ.setdefault 这个配置项就行了,但是实际测试中这样是有问题,需要添加上下面一步

扩展1:自定义模型公共部分

一般在Django开发中,每个模型都会id字段、创建时间、更新时间。或者有时候都会有 是否删除和删除时间字段。

既然是每个模型都会有的,那么在每个模型中重复性的把这些字段定义一遍肯定是代码冗余和低效的表现。

1、定义功能抽象模型

# apps/baseModel.py
class BaseModel(models.Model):
    created_time = models.DateTimeField(auto_now_add=True)
    updated_time = models.DateTimeField(auto_now=True)
    deleted_time = models.DateTimeField(default=None, null=True, blank=True, verbose_name="删除时间")
    is_deleted = models.BooleanField(default=False)

    class Meta:
        abstract = True

2、应用模型中继承

# cmdb/models.py

from baseModel import BaseModel

class CDN(BaseModel):
    name = models.CharField(max_length=64, verbose_name="CDN域名")
    ... ...

扩展2: UUID作为模型主键

在定义Django模型的时候,继承了models.Model之后,一般不会显示的定义模型主键,默认会有一个id作为自增的主键

id = models.AutoField(primary_key=True)

所有有时候会使用 UUID 作为主键 相对比较合适些。UUID 是一种全局唯一标识符,通常用32位的字符串来表现,类似 33d1f6b3-ffae-4ebe-9c88-a5becd71a0bc。

实现方式

# apps/baseModel.py

# 需要导入该python库
import uuid

class BaseModel(models.Model): 
    id = models.UUIDField(default=uuid.uuid4, primary_key=True, editable=False)
    ... ...

原文地址: http://www.colinspace.com/blog/post/27/

12-06 05:00