Django init.py 高级应用速记
一、标记 Python 包
markdown
myapp/
__init__.py ← 有此文件,myapp 才是可导入的包
models.py
views.py
没有它,Python 不认识这个目录。Python 3.3+ 引入了隐式命名空间包,但显式 __init__.py 仍是主流实践,因为可以执行初始化代码。
二、控制导出范围(all)
当别人 from myapp import * 时,只导出 __all__ 中声明的符号:
python
# myapp/__init__.py
__all__ = ['UserService', 'OrderService', '__version__']
from .services.user import UserService
from .services.order import OrderService
__version__ = '1.2.3'
def _internal_helper(): # 不在 __all__ 中,_ 前缀暗示私有
pass
三、版本管理
python
# myapp/__init__.py
__version__ = '1.2.3'
VERSION = (1, 2, 3)
setup.py 或 pyproject.toml 也可以直接引用:
python
# setup.py
import myapp
setup(version=myapp.__version__)
四、美化 import 路径(门面模式)
python
# myapp/__init__.py
from .services.auth import login, logout, get_current_user
from .services.order import create_order, cancel_order
from .models import User, Order
from .exceptions import AuthError, PermissionDenied
使用者只需一行:
python
from myapp import login, create_order, User, AuthError
五、延迟导入(懒加载,解决循环引用)
python
# myapp/__init__.py
__all__ = ['UserService', 'send_email']
def __getattr__(name):
"""Python 3.7+ 支持模块级 __getattr__"""
if name == 'UserService':
from .services.user import UserService
return UserService
if name == 'send_email':
from .tasks.email import send_email
return send_email
raise AttributeError(f"module 'myapp' has no attribute '{name}'")
好处:首次访问时才导入,启动快,避免循环导入报错。
六、App 配置与信号注册
python
# myapp/__init__.py
default_app_config = 'myapp.apps.MyAppConfig'
python
# myapp/apps.py
from django.apps import AppConfig
class MyAppConfig(AppConfig):
default_auto_field = 'django.db.models.BigAutoField'
name = 'myapp'
verbose_name = '我的应用'
def ready(self):
# 注册信号
import myapp.signals
# 注册检查项
from .checks import register_checks
register_checks()
# 初始化缓存
from django.core.cache import cache
cache.set('app_started', True)
关键提醒 :ready() 中导入模块放内部,避免在模块级导入时引起循环引用。
七、自定义系统检查(System Checks)
python
# myapp/checks.py
from django.core.checks import register, Warning, Error
def check_redis_connection(app_configs, **kwargs):
errors = []
try:
from django.core.cache import caches
caches['default'].get('test')
except Exception:
errors.append(Error('Redis 连接失败', hint='检查 settings.CACHES', id='myapp.E001'))
return errors
def register_checks():
register(check_redis_connection)
运行 python manage.py check 即可验证------Django 自动扫描。
八、管理后台配置
python
# myapp/admin.py
from django.contrib import admin
from .models import User, Order
@admin.register(User)
class UserAdmin(admin.ModelAdmin):
list_display = ['id', 'username', 'email', 'is_active']
search_fields = ['username', 'email']
admin.site.site_header = '我的管理后台'
admin.site.site_title = '管理后台'
admin.site.index_title = '功能导航'
九、注册全局模板标签与过滤器
python
# myapp/templatetags/__init__.py ← 必须存在
python
# myapp/templatetags/my_filters.py
from django import template
register = template.Library()
@register.filter
def format_price(value):
return f'¥{value:,.2f}'
@register.simple_tag
def current_time(format_string='%Y-%m-%d %H:%M'):
from datetime import datetime
return datetime.now().strftime(format_string)
模板中使用:
lua
{% load my_filters %}
{{ order.price|format_price }}
{% current_time '%H:%M' %}
十、包级日志配置
python
# myapp/__init__.py
import logging
logger = logging.getLogger(__name__)
logger.info(f'{__name__} 模块已加载')
配合 Django settings:
python
LOGGING = {
'loggers': {
'myapp': {
'handlers': ['console'],
'level': 'DEBUG',
'propagate': False,
},
},
}
速查表
| 场景 | 关键文件 | 核心操作 |
|---|---|---|
| 标记包 | __init__.py |
文件存在即可 |
| 导出控制 | __init__.py |
定义 __all__ |
| 版本号 | __init__.py |
定义 __version__ |
| 懒加载 | __init__.py |
实现 __getattr__() |
| 简化导入 | __init__.py |
from .sub import X |
| 信号注册 | apps.py |
ready() 中 import signals |
| 系统检查 | checks.py |
@register 装饰器 |
| 管理后台 | admin.py |
@admin.register 装饰器 |
| 模板标签 | templatetags/ |
template.Library() |
| 日志 | __init__.py |
logging.getLogger(__name__) |
核心思想 :__init__.py 是包的入口和初始化枢纽------标记身份、聚合导出、延迟加载、连接 Django 生命周期。
Django management/commands 自动注册速记
一、核心机制
Django 启动时会遍历 INSTALLED_APPS 中每个 app 的 management/commands/ 目录,该目录下所有非 _ 开头的 .py 文件 自动注册为 manage.py 子命令。
bash
python manage.py my_command ← 对应 myapp/management/commands/my_command.py
自动发现流程:
- Django 加载所有
INSTALLED_APPS - 扫描每个 app 的
management/commands/目录 - 导入每个
.py文件,找到Command类 - 文件名即命令名,加入
manage.py的命令表
二、目录结构(铁律)
markdown
myapp/
management/
__init__.py ← 必须空文件
commands/
__init__.py ← 必须空文件
my_command.py → python manage.py my_command
sync_data.py → python manage.py sync_data
_base.py ← _ 开头不注册(公共基类)
两个 __init__.py 缺一不可------少任何一个 Django 都找不到你的命令。
三、基本命令模板
python
from django.core.management.base import BaseCommand
class Command(BaseCommand):
help = '命令简短描述'
def handle(self, *args, **options):
self.stdout.write(self.style.SUCCESS('执行成功!'))
必须遵守 :类名固定为 Command,继承 BaseCommand,实现 handle()。
四、带参数的命令
python
class Command(BaseCommand):
help = '发送邮件给指定用户'
def add_arguments(self, parser):
# 位置参数
parser.add_argument('email', type=str, help='邮箱地址')
# 可选参数
parser.add_argument('--subject', type=str, default='通知')
# 布尔开关
parser.add_argument('--dry-run', action='store_true')
# 多值参数
parser.add_argument('--cc', nargs='+', type=str)
def handle(self, *args, **options):
email = options['email']
dry_run = options['dry_run']
cc_list = options['cc'] or []
if dry_run:
self.stdout.write(f'[预览] 发送给 {email}, 抄送 {cc_list}')
else:
self.stdout.write(self.style.SUCCESS(f'已发送至 {email}'))
五、输出样式
python
self.stdout.write(self.style.SUCCESS('绿色,成功'))
self.stdout.write(self.style.ERROR('红色,错误'))
self.stdout.write(self.style.WARNING('黄色,警告'))
self.stdout.write(self.style.NOTICE('蓝色,提示'))
self.stdout.write(self.style.MIGRATE_HEADING('加粗,用于迁移'))
六、事务控制
python
from django.db import transaction
try:
with transaction.atomic():
User.objects.create(username='test')
Order.objects.create(user=user, amount=100)
except Exception as e:
self.stderr.write(self.style.ERROR(f'失败:{e}'))
七、进度条
python
for i, user in enumerate(users, 1):
self.stdout.write(f'处理中... {i}/{total}', ending='\r')
self.stdout.flush()
self.stdout.write(self.style.SUCCESS(f'\n完成!共处理 {total} 条'))
八、提取公共基类
python
# _base.py(_ 开头不注册为命令)
class BaseAppCommand(BaseCommand):
def add_arguments(self, parser):
parser.add_argument('--env', default='prod', choices=['dev', 'test', 'prod'])
def handle(self, *args, **options):
self.env = options['env']
self._run(*args, **options)
def _run(self, *args, **options):
raise NotImplementedError('子类必须实现 _run')
子命令:
python
from ._base import BaseAppCommand
class Command(BaseAppCommand):
help = '同步数据'
def _run(self, *args, **options):
self.stdout.write(f'在 {self.env} 环境同步...')
九、子命令(子解析器)
python
class Command(BaseCommand):
help = '用户管理工具'
def add_arguments(self, parser):
subparsers = parser.add_subparsers(dest='action', required=True)
create_parser = subparsers.add_parser('create', help='创建用户')
create_parser.add_argument('username', type=str)
delete_parser = subparsers.add_parser('delete', help='删除用户')
delete_parser.add_argument('username', type=str)
subparsers.add_parser('list', help='列出用户')
def handle(self, *args, **options):
action = options['action']
if action == 'create':
self._create_user(options['username'])
elif action == 'delete':
self._delete_user(options['username'])
elif action == 'list':
self._list_users()
用法:
bash
python manage.py user create alice
python manage.py user delete bob
python manage.py user list
十、执行系统命令
python
import subprocess
result = subprocess.run(['ls', '-la'], capture_output=True, text=True, timeout=10)
if result.returncode == 0:
self.stdout.write(result.stdout)
十一、确认交互
python
def handle(self, *args, **options):
answer = input('确认执行?输入 yes 继续: ')
if answer.lower() != 'yes':
self.stdout.write(self.style.WARNING('已取消'))
return
# 执行操作
速查表
| 需求 | 关键代码 |
|---|---|
| 基础命令 | class Command(BaseCommand): handle() |
| 参数 | parser.add_argument(...) |
| 彩色输出 | self.style.SUCCESS(msg) |
| 进度条 | ending='\r' + self.stdout.flush() |
| 公用基类 | 下划线开头,放 handle 模板逻辑 |
| 子命令 | parser.add_subparsers(dest='action') |
| 事务 | with transaction.atomic(): |
| 调用 shell | subprocess.run([...]) |
核心思想 :文件名即命令名,目录放对即自动注册,Command 类实现 handle() 即开箱可用。
Dockerfile 速记
一、核心指令速查
| 指令 | 用途 | 关键点 |
|---|---|---|
| FROM | 指定基础镜像 | 每个 Dockerfile 第一条有效指令 |
| WORKDIR | 设置工作目录 | 不存在则自动创建 |
| COPY | 复制文件到镜像 | 比 ADD 更明确,仅复制文件 |
| ADD | 复制 + 自动解压 | 仅需要解压 tar 时用,其他用 COPY |
| RUN | 构建时执行命令 | 每条生成一层,用 && 合并减少层数 |
| ENV | 设置环境变量 | 运行时也生效 |
| ARG | 构建参数 | 仅构建时可用,--build-arg 传入 |
| EXPOSE | 声明端口 | 仅声明,-p 才实际映射 |
| CMD | 默认启动命令 | 可被 docker run 的参数覆盖 |
| ENTRYPOINT | 固定入口点 | CMD 的内容成为它的默认参数 |
| VOLUME | 声明匿名卷 | 数据持久化 |
| USER | 切换运行用户 | 不用 root 运行应用 |
| HEALTHCHECK | 健康检查 | 判断容器是否真正就绪 |
| LABEL | 添加元数据 | LABEL maintainer="xxx" |
二、CMD vs ENTRYPOINT
CMD(可覆盖)
dockerfile
CMD ["python", "app.py"]
# docker run myimage → python app.py
# docker run myimage python test.py → python test.py(覆盖 CMD)
ENTRYPOINT(不可覆盖)
dockerfile
ENTRYPOINT ["python"]
CMD ["app.py"]
# docker run myimage → python app.py
# docker run myimage test.py → python test.py(CMD 被替换)
组合(推荐)
dockerfile
ENTRYPOINT ["docker-entrypoint.sh"]
CMD ["nginx", "-g", "daemon off;"]
# 固定入口脚本 + 可替换的默认参数
三、Django 项目标准 Dockerfile
dockerfile
# ---- 构建阶段 ----
FROM python:3.11-slim AS builder
WORKDIR /app
# 安装系统依赖
RUN apt-get update && apt-get install -y --no-install-recommends \
gcc libpq-dev \
&& rm -rf /var/lib/apt/lists/*
# 安装 Python 依赖
COPY requirements.txt .
RUN pip install --user --no-cache-dir -r requirements.txt
# ---- 运行阶段 ----
FROM python:3.11-slim
WORKDIR /app
COPY --from=builder /root/.local /root/.local
ENV PATH=/root/.local/bin:$PATH
COPY . .
RUN useradd -m -u 1000 django && chown -R django:django /app
USER django
EXPOSE 8000
CMD ["gunicorn", "myproject.wsgi:application", "-b", "0.0.0.0:8000"]
四、多阶段构建
dockerfile
# 阶段1:编译
FROM golang:1.21 AS builder
WORKDIR /src
COPY . .
RUN CGO_ENABLED=0 go build -o /app .
# 阶段2:运行(精简镜像)
FROM alpine:3.19
COPY --from=builder /app /app
ENTRYPOINT ["/app"]
好处:最终镜像只含运行时二进制,体积从 800MB 降到 10MB。
五、层缓存优化
❌ 差(每次代码变动都重新安装依赖)
dockerfile
COPY . .
RUN pip install -r requirements.txt
✅ 好(依赖层缓存,代码变动不影响)
dockerfile
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY . .
原则:变动频率低的放前面,变动频率高的放后面。
sql
FROM ← 几乎不变
RUN apt-get ← 很少变
COPY req.txt ← 偶尔变
RUN pip install← 偶尔变
COPY . . ← 经常变
六、.dockerignore
markdown
__pycache__
*.pyc
*.pyo
.pytest_cache
.git
.gitignore
.env
venv/
.venv/
node_modules/
*.md
Dockerfile
docker-compose.yml
*.log
七、HEALTHCHECK
dockerfile
# Django
HEALTHCHECK --interval=30s --timeout=3s --retries=3 \
CMD curl -f http://localhost:8000/health/ || exit 1
# PostgreSQL
HEALTHCHECK --interval=30s --timeout=3s \
CMD pg_isready -U postgres || exit 1
配合 docker-compose:
yaml
services:
web:
depends_on:
db:
condition: service_healthy
八、VOLUME 持久化
dockerfile
VOLUME ["/var/lib/postgresql/data"]
bash
docker run -v my_volume:/var/lib/postgresql/data myimage # 命名卷
docker run -v /host/path:/container/path myimage # 绑定挂载
| 方式 | 命令 | 适用场景 |
|---|---|---|
| 命名卷 | -v vol:/path |
生产环境 |
| 绑定挂载 | -v /host:/container |
开发环境 |
| tmpfs | --tmpfs /path |
临时敏感数据 |
九、环境变量与配置
dockerfile
# 构建时
ARG APP_VERSION=1.0
RUN echo "Building version $APP_VERSION"
# 运行时
ENV PYTHONUNBUFFERED=1 \
PYTHONDONTWRITEBYTECODE=1 \
DJANGO_SETTINGS_MODULE=myproject.settings.production
# 运行时传入
# docker run -e DATABASE_URL=xxx myimage
十、USER 安全
dockerfile
RUN groupadd -r appgroup && useradd -r -g appgroup -u 1000 appuser
COPY --chown=appuser:appgroup . /app
USER appuser
# 此时所有 RUN、CMD、ENTRYPOINT 都以 appuser 身份运行
十一、构建与推送
bash
# 构建
docker build -t username/myapp:1.0 .
# 带构建参数
docker build --build-arg APP_VERSION=2.0 -t myapp:2.0 .
# 推送到仓库
docker push username/myapp:1.0
# 多平台构建+推送
docker buildx build --platform linux/amd64,linux/arm64 \
-t username/myapp:1.0 --push .
十二、Entrypoint 初始化脚本
dockerfile
COPY docker-entrypoint.sh /docker-entrypoint.sh
RUN chmod +x /docker-entrypoint.sh
ENTRYPOINT ["/docker-entrypoint.sh"]
CMD ["gunicorn", "app.wsgi"]
bash
#!/bin/bash
set -e
# 等待数据库就绪
if [ "$DATABASE_URL" ]; then
echo "等待数据库..."
while ! nc -z db 5432; do sleep 1; done
fi
# 执行迁移
python manage.py migrate --noinput
# 执行 CMD
exec "$@"
速查表
| 场景 | 指令/模式 | 关键点 |
|---|---|---|
| 安装依赖 | apt-get ... && rm -rf /var/lib/apt/lists/* |
清理缓存减小体积 |
| Python 依赖 | pip install --no-cache-dir |
先 COPY req.txt 用层缓存 |
| 多阶段构建 | FROM ... AS builder + COPY --from=builder |
最终镜像只含运行时 |
| 默认命令 | CMD ["executable", "param1"] |
JSON 数组形式 |
| 初始化 | entrypoint 脚本 | exec "$@" 保证信号传递 |
| 数据持久化 | VOLUME + -v 挂载 |
容器重启数据不丢 |
| 缩小体积 | 多阶段 + slim/alpine + .dockerignore | 能省则省 |
| 安全 | USER + COPY --chown |
不用 root 运行 |
核心思想:层缓存、多阶段构建、安全最小化 ------ 构建快、镜像小、运行稳。