Metadata-Version: 2.4
Name: django-app-metadata
Version: 0.1.5
Summary: Django数据字典管理应用。
Author-email: rRR0VrFP <rRR0VrFP@qq.com>
Maintainer-email: rRR0VrFP <rRR0VrFP@qq.com>
License-Expression: Apache-2.0
Project-URL: Homepage, https://gitee.com/rRR0VrFP/django-app-metadata
Project-URL: Repository, https://gitee.com/rRR0VrFP/django-app-metadata
Project-URL: Issues, https://gitee.com/rRR0VrFP/django-app-metadata/issues
Keywords: django-app-metadata,django
Classifier: Development Status :: 5 - Production/Stable
Classifier: Intended Audience :: Developers
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3 :: Only
Classifier: Programming Language :: Python :: 3.8
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Requires-Python: >=3.8
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: django
Requires-Dist: django-data-history
Requires-Dist: django-import-export
Requires-Dist: django-redis
Requires-Dist: django-safe-fields
Requires-Dist: django-model-helper
Requires-Dist: django-environment-settings
Requires-Dist: zenutils
Requires-Dist: null-object
Requires-Dist: PyYAML
Dynamic: license-file

# django-app-metadata

Django 数据字典管理应用。提供配置项管理、分类管理、导入导出等功能。

## 安装

```shell
pip install django-app-metadata
```

`django_app_metadata` 依赖多个 Django app（`import_export`、`django_model_helper`、`django_safe_fields`、`django_data_history`），需要在 `INSTALLED_APPS` 中一并注册。可通过以下两种方式：

### 方式一（推荐）：使用 django-app-requires

安装：

```shell
pip install django-app-requires
```

在 `settings.py` 中添加本应用，并在末尾调用 `patch_all()` 自动补全依赖：

```python
INSTALLED_APPS = [
    ...
    "django_app_metadata",
    ...
]

from django_app_requires import patch_all as django_app_requires_patch_all

django_app_requires_patch_all()
```

> `patch_all()` 会自动补齐 `django_app_metadata` 的间接依赖 app，无需手动逐一添加。

### 方式二：手动注册

```python
INSTALLED_APPS = [
    ...
    "django_app_metadata",
    "import_export",
    "django_model_helper",
    "django_safe_fields",
    "django_data_history",
    ...
]
```

### 数据库迁移

```shell
python manage.py migrate
```

## 配置

所有配置均通过环境变量或 Django `settings.py` 设置，默认值即开箱即用。

| 环境变量 | 默认值 | 说明 |
|---------|--------|------|
| `DJANGO_APP_METADATA_USE_CACHE` | `True` | 是否启用缓存 |
| `DJANGO_APP_METADATA_CACHE_TIMEOUT` | `3600` | 缓存时长（秒），默认 1 小时 |
| `DJANGO_APP_METADATA_MISSING_CONFIG_CACHE_TIMEOUT` | `300` | 缺失配置项缓存时长（秒），默认 5 分钟 |
| `DJANGO_APP_METADATA_CACHE_NAME` | `"default"` | 缓存数据库名称 |
| `DJANGO_APP_METADATA_CACHE_KEY_TEMPLATE` | `"django_app_metadata_cache:{key}"` | 缓存键模板 |

## 使用

### 模型

**Config** — 配置项，支持以下数据类型：

| 类型 | 值 | 说明 |
|------|---|------|
| `YAML` | 10 | YAML 格式（默认） |
| `JSON` | 20 | JSON 格式 |
| `STRING` | 30 | 纯字符串 |
| `NUMBER` | 40 | 数值型 |
| `FILE` | 50 | 文件 |

**Category** — 配置分类，与 Config 为一对多关系。

### 获取配置

```python
from django_app_metadata.models import Config

# 基本用法
value = Config.get("my_key")

# 指定默认值
value = Config.get("my_key", default="默认值")

# 前端接口查询（仅返回已发布的配置，否则抛 AccessToUnpublishedConfigIsForbidden 异常）
value = Config.get("my_key", frontend_flag=True)

# 禁用缓存
value = Config.get("my_key", use_cache=False)

# 自定义缓存时长（秒）
value = Config.get("my_key", cache_timeout=300)
```

### 管理后台

注册后可在 Django Admin 中管理配置项和分类：

- 配置项支持导入/导出（CSV 等格式）
- 配置项支持启用/禁用、发布/取消发布、软删除
- 支持按分类、类型、状态等字段筛选

### 数据历史

`django-data-history` 自动记录 Config 模型的数据变更历史。

## 缓存机制

- 配置项查询结果会自动缓存
- 配置项保存、删除、批量更新时自动清除对应缓存
- 配置项 key 变更时同时清除旧 key 和新 key 的缓存
- 缺失的配置项也会缓存（可配置过期时间），避免缓存穿透

## REST 接口

在项目根 `urls.py` 中引入：

```python
from django.urls import include, path

urlpatterns = [
    ...
    path("api/django-app-metadata/", include("django_app_metadata.urls")),
    ...
]
```

配置 `DJANGO_APP_METADATA_API_KEY`（用于应用间鉴权，为空则不鉴权）。

### 公共接口（浏览器使用）
`GET/POST /api/django-app-metadata/public/getConfigs`

需要用户登录（`login_required`）。支持以下请求方式：

- **GET 单 key**：`?key=my_key`
- **GET 多 key**：`?key=a&key=b` 或 `?keys=a,b`（逗号分割）
- **POST 批量**：`{"keys": ["a", "b"]}`

未发布配置项返回 404，批量中含未发布返回 403。

```shell
# 获取单个配置（需登录）
curl -u user:pass http://host/api/django-app-metadata/public/getConfigs?key=my_key

# 批量获取
curl -u user:pass http://host/api/django-app-metadata/public/getConfigs?keys=key1,key2

curl -u user:pass -X POST -H "Content-Type: application/json" \
  -d '{"keys": ["key1", "key2"]}' \
  http://host/api/django-app-metadata/public/getConfigs
```

响应格式：

```json
// 成功
{"code": 0, "message": "success", "data": [{"key": "my_key", "value": <value>}]}

// 批量
{"code": 0, "message": "success", "data": [{"key": "key1", "value": <value>}, {"key": "key2", "value": <value>}]}

// 失败
{"code": 404, "message": "config not found or not accessible"}
{"code": 403, "message": "contains unpublished config"}
```

### 私有接口（应用间调用）
`GET/POST /api/django-app-metadata/private/getConfigs`

需要提供 API key，支持以下认证方式（配置 `DJANGO_APP_METADATA_API_KEY=my-secret`）：

```shell
# X-Api-Key 头
curl -H "X-Api-Key: my-secret" http://host/api/django-app-metadata/private/getConfigs?key=my_key

# apikey 头
curl -H "apikey: my-secret" http://host/api/django-app-metadata/private/getConfigs?key=my_key

# Bearer 认证
curl -H "Authorization: Bearer my-secret" http://host/api/django-app-metadata/private/getConfigs?key=my_key
```

请求参数与响应格式同公共接口。

## 模型字段说明

### Config

| 字段 | 类型 | 说明 |
|------|------|------|
| `key` | CharField | 配置项唯一标识 |
| `description` | CharField | 配置项说明 |
| `type` | IntegerField | 数据类型（YAML/JSON/STRING/NUMBER/FILE） |
| `data_raw` | SafeTextField | 配置项数据（原始文本） |
| `data_file` | FileField | 配置项文件（类型为 FILE 时必填） |
| `category` | ForeignKey | 所属分类 |
| `is_valid` | BooleanField | 数据解析是否正确（自动计算，只读） |
| `enabled` | BooleanField | 启用状态 |
| `deleted` | BooleanField | 软删除状态 |
| `published` | BooleanField | 发布状态 |
| `add_time` | DateTimeField | 创建时间 |
| `mod_time` | DateTimeField | 修改时间 |

### Category

| 字段 | 类型 | 说明 |
|------|------|------|
| `title` | CharField | 分类名称（唯一） |
| `display_order` | IntegerField | 排序 |
| `add_time` | DateTimeField | 创建时间 |
| `mod_time` | DateTimeField | 修改时间 |

## 版本记录

### v0.1.0

- 添加：版本首发。
- 添加：数据字典管理。
- 添加：数据字典获取支持缓存。

### v0.1.1

- 改进：使用 `django-environment-settings` 获取系统配置以增强应用的兼容性。
- 改进：`AccessToUnpublishedConfigIsForbidden` 添加错误信息，支持中英双语。
- 修正：添加 `django-model-helper` 依赖关系。

### v0.1.2

- 修正：`Config.Meta.permissions` 添加其它基础类的相关 `permissions`。

### v0.1.3

- 改进：配置项管理界面。
- 改进：配置项导出文件中 category 使用 title 取代原来的 id。

### v0.1.4

- 添加：文件类型配置项的支持。

### v0.1.5

- 添加：AGENTS.md 开发助手备忘录。
- 添加：`django-redis` 依赖支持。
- 添加：Redis 缓存测试用例（8 个），覆盖缓存写入、清除、变更等动态过程。
- 添加：新增 22 个测试用例，覆盖假值、FILE 类型、Category、InvalidData、缓存边界等场景，累计 70 个测试用例。
- 改进：迁移至 `pyproject.toml` 构建系统。
- 改进：完善 README 安装说明、配置说明、使用文档及模型字段说明。
- 修正：补充缺失的 `django-data-history` 和 `django-import-export` 依赖。
- 修正：修复 `set_data()` 对 FILE 类型的错误处理、裸 `except:` 等问题。
