labull-framework 0.1.32__tar.gz → 0.1.34__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {labull_framework-0.1.32/labull_framework.egg-info → labull_framework-0.1.34}/PKG-INFO +77 -1
- {labull_framework-0.1.32 → labull_framework-0.1.34}/README-pypi.md +76 -0
- {labull_framework-0.1.32 → labull_framework-0.1.34}/labull_framework/canvas/__init__.py +5 -1
- {labull_framework-0.1.32 → labull_framework-0.1.34}/labull_framework/canvas/data.py +391 -71
- {labull_framework-0.1.32 → labull_framework-0.1.34}/labull_framework/canvas/gitinfo.py +126 -3
- {labull_framework-0.1.32 → labull_framework-0.1.34}/labull_framework/canvas/shape_ast.py +307 -30
- {labull_framework-0.1.32 → labull_framework-0.1.34}/labull_framework/canvas/static/canvas.css +64 -0
- {labull_framework-0.1.32 → labull_framework-0.1.34}/labull_framework/canvas/static/canvas.js +289 -20
- {labull_framework-0.1.32 → labull_framework-0.1.34}/labull_framework/env.py +6 -0
- {labull_framework-0.1.32 → labull_framework-0.1.34}/labull_framework/magic_block/devkit.py +1202 -1123
- {labull_framework-0.1.32 → labull_framework-0.1.34}/labull_framework/magic_block/export.py +116 -4
- {labull_framework-0.1.32 → labull_framework-0.1.34}/labull_framework/magic_block/service.py +26 -2
- {labull_framework-0.1.32 → labull_framework-0.1.34}/labull_framework/management/commands/labull_contract.py +10 -1
- labull_framework-0.1.34/labull_framework/models.py +252 -0
- labull_framework-0.1.34/labull_framework/virtual.py +277 -0
- {labull_framework-0.1.32 → labull_framework-0.1.34/labull_framework.egg-info}/PKG-INFO +77 -1
- {labull_framework-0.1.32 → labull_framework-0.1.34}/labull_framework.egg-info/SOURCES.txt +1 -0
- {labull_framework-0.1.32 → labull_framework-0.1.34}/pyproject.toml +1 -1
- labull_framework-0.1.32/labull_framework/models.py +0 -123
- {labull_framework-0.1.32 → labull_framework-0.1.34}/LICENSE +0 -0
- {labull_framework-0.1.32 → labull_framework-0.1.34}/MANIFEST.in +0 -0
- {labull_framework-0.1.32 → labull_framework-0.1.34}/labull_framework/__init__.py +0 -0
- {labull_framework-0.1.32 → labull_framework-0.1.34}/labull_framework/admin.py +0 -0
- {labull_framework-0.1.32 → labull_framework-0.1.34}/labull_framework/apps.py +0 -0
- {labull_framework-0.1.32 → labull_framework-0.1.34}/labull_framework/auth/__init__.py +0 -0
- {labull_framework-0.1.32 → labull_framework-0.1.34}/labull_framework/auth/backend.py +0 -0
- {labull_framework-0.1.32 → labull_framework-0.1.34}/labull_framework/auth/bootstrap.py +0 -0
- {labull_framework-0.1.32 → labull_framework-0.1.34}/labull_framework/auth/sso.py +0 -0
- {labull_framework-0.1.32 → labull_framework-0.1.34}/labull_framework/auth/views.py +0 -0
- {labull_framework-0.1.32 → labull_framework-0.1.34}/labull_framework/canvas/static/page.html +0 -0
- {labull_framework-0.1.32 → labull_framework-0.1.34}/labull_framework/canvas/views.py +0 -0
- {labull_framework-0.1.32 → labull_framework-0.1.34}/labull_framework/jsonio.py +0 -0
- {labull_framework-0.1.32 → labull_framework-0.1.34}/labull_framework/magic_block/__init__.py +0 -0
- {labull_framework-0.1.32 → labull_framework-0.1.34}/labull_framework/magic_block/blockpackage.py +0 -0
- {labull_framework-0.1.32 → labull_framework-0.1.34}/labull_framework/magic_block/deepcheck.py +0 -0
- {labull_framework-0.1.32 → labull_framework-0.1.34}/labull_framework/magic_block/dispatch.py +0 -0
- {labull_framework-0.1.32 → labull_framework-0.1.34}/labull_framework/magic_block/health.py +0 -0
- {labull_framework-0.1.32 → labull_framework-0.1.34}/labull_framework/magic_block/parallel.py +0 -0
- {labull_framework-0.1.32 → labull_framework-0.1.34}/labull_framework/magic_block/registry.py +0 -0
- {labull_framework-0.1.32 → labull_framework-0.1.34}/labull_framework/magic_block/sdk.py +0 -0
- {labull_framework-0.1.32 → labull_framework-0.1.34}/labull_framework/magic_block/subproc.py +0 -0
- {labull_framework-0.1.32 → labull_framework-0.1.34}/labull_framework/magic_block/validate.py +0 -0
- {labull_framework-0.1.32 → labull_framework-0.1.34}/labull_framework/magic_block/views.py +0 -0
- {labull_framework-0.1.32 → labull_framework-0.1.34}/labull_framework/management/__init__.py +0 -0
- {labull_framework-0.1.32 → labull_framework-0.1.34}/labull_framework/management/commands/__init__.py +0 -0
- {labull_framework-0.1.32 → labull_framework-0.1.34}/labull_framework/migrations/0001_initial.py +0 -0
- {labull_framework-0.1.32 → labull_framework-0.1.34}/labull_framework/migrations/0002_remove_magicblock_prev_files_and_more.py +0 -0
- {labull_framework-0.1.32 → labull_framework-0.1.34}/labull_framework/migrations/0003_magicblock_tags.py +0 -0
- {labull_framework-0.1.32 → labull_framework-0.1.34}/labull_framework/migrations/0004_magicblock_detail.py +0 -0
- {labull_framework-0.1.32 → labull_framework-0.1.34}/labull_framework/migrations/__init__.py +0 -0
- {labull_framework-0.1.32 → labull_framework-0.1.34}/labull_framework/settings.py +0 -0
- {labull_framework-0.1.32 → labull_framework-0.1.34}/labull_framework/urls.py +0 -0
- {labull_framework-0.1.32 → labull_framework-0.1.34}/labull_framework.egg-info/dependency_links.txt +0 -0
- {labull_framework-0.1.32 → labull_framework-0.1.34}/labull_framework.egg-info/requires.txt +0 -0
- {labull_framework-0.1.32 → labull_framework-0.1.34}/labull_framework.egg-info/top_level.txt +0 -0
- {labull_framework-0.1.32 → labull_framework-0.1.34}/setup.cfg +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: labull-framework
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.34
|
|
4
4
|
Summary: Labull Framework: a pluggable Django app with Authing OIDC login and magic blocks
|
|
5
5
|
Author: Labull Framework
|
|
6
6
|
License-Expression: MIT
|
|
@@ -134,6 +134,82 @@ class Order:
|
|
|
134
134
|
|
|
135
135
|
配置:环境变量里**带 `BLOCK_` 前缀**的才会进 `ctx.config`(`BLOCK_OCR_KEY=a` ⇒ `ctx.config['OCR_KEY']`)。
|
|
136
136
|
|
|
137
|
+
## 虚拟类(`@virtual_class`)
|
|
138
|
+
|
|
139
|
+
几张表共有同一批列时,写一个**虚拟类**:一个**不建表的抽象模型**,自己那几列会被继承到子表上。
|
|
140
|
+
|
|
141
|
+
```python
|
|
142
|
+
from django.db import models
|
|
143
|
+
from labull_framework.virtual import virtual_class, VirtualModel
|
|
144
|
+
|
|
145
|
+
|
|
146
|
+
@virtual_class
|
|
147
|
+
class Contact(VirtualModel):
|
|
148
|
+
"""联系人:个人与单位共有的那几列。"""
|
|
149
|
+
name = models.CharField('名称', max_length=64)
|
|
150
|
+
|
|
151
|
+
class Meta:
|
|
152
|
+
abstract = True # 🔴 必须有(见下)
|
|
153
|
+
|
|
154
|
+
|
|
155
|
+
class Person(Contact):
|
|
156
|
+
birthday = models.DateField('生日', null=True, blank=True)
|
|
157
|
+
|
|
158
|
+
|
|
159
|
+
class Company(Contact):
|
|
160
|
+
tax_no = models.CharField('税号', max_length=32, blank=True, default='')
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
`Person` / `Company` 的表里**真的有** `name` 这一列(Django 把抽象基类的字段复制进子类);
|
|
164
|
+
而 `makemigrations` **只为这两张具体表建表** —— `Contact` 在库里没有对应的表。
|
|
165
|
+
|
|
166
|
+
两条会真的出错的判据:
|
|
167
|
+
|
|
168
|
+
1. **`class Meta: abstract = True` 不能省**(`@virtual_class` 替不了它:Django 在 `ModelBase` 里
|
|
169
|
+
读的是**类体那个 `Meta`**,读完就把非抽象模型登记进 app registry 了)。漏了会让这个类**真的建一张表**,
|
|
170
|
+
所以装饰器发现这件事时**当场抛 `TypeError`** 并把该补的那一行写给你。
|
|
171
|
+
2. **`@virtual_class` 写在所有装饰器的最上面**(它执行时那个类必须已经是一个 Django 模型);
|
|
172
|
+
另外**外键不能指向虚拟类**(抽象模型没有 `objects`,Django 在 `manage.py check` 就拦下)。
|
|
173
|
+
|
|
174
|
+
`LABULL_SCHEMA_CANVAS=on` 时打开 `/`:虚拟类是一张带 `◇` 的虚线卡片(写着"不建表"与"谁在继承它"),
|
|
175
|
+
继承它的表表头挂着「**◇ 泛化 · Contact**」—— 鼠标停一下看泛化名与整条链,点一下跳过去。
|
|
176
|
+
改动(含"哪张表的泛化父类变了")与表一样进画布那份差异。
|
|
177
|
+
|
|
178
|
+
### 平台自带:WorkflowModel(流转记录)
|
|
179
|
+
|
|
180
|
+
要记"这件事是谁、什么时候、怎么走过来的"的表,**继承它就行**(不用自己写抽象基类):
|
|
181
|
+
|
|
182
|
+
```python
|
|
183
|
+
from django.db import models
|
|
184
|
+
from labull_framework.models import WorkflowModel
|
|
185
|
+
|
|
186
|
+
|
|
187
|
+
class PurchaseOrder(WorkflowModel):
|
|
188
|
+
"""采购申请:全过程记在继承来的 log 那一列里。"""
|
|
189
|
+
title = models.CharField('标题', max_length=128)
|
|
190
|
+
|
|
191
|
+
class Meta:
|
|
192
|
+
verbose_name = '采购申请' # 🔴 一定要自己写(不然继承来的是基类那个名字)
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
它给子表带上三列:`log`(流转日志,JSON 数组)、`created_at`(创建时间)与 `updated_at`(自动时间)。
|
|
196
|
+
读写走类上的助手,别在调用点自己拼字典:
|
|
197
|
+
|
|
198
|
+
```python
|
|
199
|
+
WorkflowModel.append_log(row, 'submit', actor=user.name, note='提交审批')
|
|
200
|
+
row.save(update_fields=['log'])
|
|
201
|
+
WorkflowModel.log_of(row) # → [{'at': ..., 'action': 'submit', ...}, ...]
|
|
202
|
+
WorkflowModel.last_log(row, 'approve') # → 最后一次批准(没有就 None)
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
画布上它是一张带 `◇` 的**虚拟卡片**(在 `labull_framework` 模块里),
|
|
206
|
+
继承它的表表头挂着「◇ 泛化 · WorkflowModel」。
|
|
207
|
+
|
|
208
|
+
- **当前状态用列**(要能筛选、能索引),`log` 只回答"怎么走到这一步的"。
|
|
209
|
+
- `log` 是**一列 JSON、不是一张子表**(刻意取舍):代价是跨表查流水要全表扫 JSON ——
|
|
210
|
+
真到那一步就该给它建一张真表。
|
|
211
|
+
- 🔴 **块后端不要 import 它**(平台内部模型),开发包的清单里也不会给出那句 import 提示。
|
|
212
|
+
|
|
137
213
|
## 运行环境
|
|
138
214
|
|
|
139
215
|
- Python ≥ 3.10
|
|
@@ -106,6 +106,82 @@ class Order:
|
|
|
106
106
|
|
|
107
107
|
配置:环境变量里**带 `BLOCK_` 前缀**的才会进 `ctx.config`(`BLOCK_OCR_KEY=a` ⇒ `ctx.config['OCR_KEY']`)。
|
|
108
108
|
|
|
109
|
+
## 虚拟类(`@virtual_class`)
|
|
110
|
+
|
|
111
|
+
几张表共有同一批列时,写一个**虚拟类**:一个**不建表的抽象模型**,自己那几列会被继承到子表上。
|
|
112
|
+
|
|
113
|
+
```python
|
|
114
|
+
from django.db import models
|
|
115
|
+
from labull_framework.virtual import virtual_class, VirtualModel
|
|
116
|
+
|
|
117
|
+
|
|
118
|
+
@virtual_class
|
|
119
|
+
class Contact(VirtualModel):
|
|
120
|
+
"""联系人:个人与单位共有的那几列。"""
|
|
121
|
+
name = models.CharField('名称', max_length=64)
|
|
122
|
+
|
|
123
|
+
class Meta:
|
|
124
|
+
abstract = True # 🔴 必须有(见下)
|
|
125
|
+
|
|
126
|
+
|
|
127
|
+
class Person(Contact):
|
|
128
|
+
birthday = models.DateField('生日', null=True, blank=True)
|
|
129
|
+
|
|
130
|
+
|
|
131
|
+
class Company(Contact):
|
|
132
|
+
tax_no = models.CharField('税号', max_length=32, blank=True, default='')
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
`Person` / `Company` 的表里**真的有** `name` 这一列(Django 把抽象基类的字段复制进子类);
|
|
136
|
+
而 `makemigrations` **只为这两张具体表建表** —— `Contact` 在库里没有对应的表。
|
|
137
|
+
|
|
138
|
+
两条会真的出错的判据:
|
|
139
|
+
|
|
140
|
+
1. **`class Meta: abstract = True` 不能省**(`@virtual_class` 替不了它:Django 在 `ModelBase` 里
|
|
141
|
+
读的是**类体那个 `Meta`**,读完就把非抽象模型登记进 app registry 了)。漏了会让这个类**真的建一张表**,
|
|
142
|
+
所以装饰器发现这件事时**当场抛 `TypeError`** 并把该补的那一行写给你。
|
|
143
|
+
2. **`@virtual_class` 写在所有装饰器的最上面**(它执行时那个类必须已经是一个 Django 模型);
|
|
144
|
+
另外**外键不能指向虚拟类**(抽象模型没有 `objects`,Django 在 `manage.py check` 就拦下)。
|
|
145
|
+
|
|
146
|
+
`LABULL_SCHEMA_CANVAS=on` 时打开 `/`:虚拟类是一张带 `◇` 的虚线卡片(写着"不建表"与"谁在继承它"),
|
|
147
|
+
继承它的表表头挂着「**◇ 泛化 · Contact**」—— 鼠标停一下看泛化名与整条链,点一下跳过去。
|
|
148
|
+
改动(含"哪张表的泛化父类变了")与表一样进画布那份差异。
|
|
149
|
+
|
|
150
|
+
### 平台自带:WorkflowModel(流转记录)
|
|
151
|
+
|
|
152
|
+
要记"这件事是谁、什么时候、怎么走过来的"的表,**继承它就行**(不用自己写抽象基类):
|
|
153
|
+
|
|
154
|
+
```python
|
|
155
|
+
from django.db import models
|
|
156
|
+
from labull_framework.models import WorkflowModel
|
|
157
|
+
|
|
158
|
+
|
|
159
|
+
class PurchaseOrder(WorkflowModel):
|
|
160
|
+
"""采购申请:全过程记在继承来的 log 那一列里。"""
|
|
161
|
+
title = models.CharField('标题', max_length=128)
|
|
162
|
+
|
|
163
|
+
class Meta:
|
|
164
|
+
verbose_name = '采购申请' # 🔴 一定要自己写(不然继承来的是基类那个名字)
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
它给子表带上三列:`log`(流转日志,JSON 数组)、`created_at`(创建时间)与 `updated_at`(自动时间)。
|
|
168
|
+
读写走类上的助手,别在调用点自己拼字典:
|
|
169
|
+
|
|
170
|
+
```python
|
|
171
|
+
WorkflowModel.append_log(row, 'submit', actor=user.name, note='提交审批')
|
|
172
|
+
row.save(update_fields=['log'])
|
|
173
|
+
WorkflowModel.log_of(row) # → [{'at': ..., 'action': 'submit', ...}, ...]
|
|
174
|
+
WorkflowModel.last_log(row, 'approve') # → 最后一次批准(没有就 None)
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
画布上它是一张带 `◇` 的**虚拟卡片**(在 `labull_framework` 模块里),
|
|
178
|
+
继承它的表表头挂着「◇ 泛化 · WorkflowModel」。
|
|
179
|
+
|
|
180
|
+
- **当前状态用列**(要能筛选、能索引),`log` 只回答"怎么走到这一步的"。
|
|
181
|
+
- `log` 是**一列 JSON、不是一张子表**(刻意取舍):代价是跨表查流水要全表扫 JSON ——
|
|
182
|
+
真到那一步就该给它建一张真表。
|
|
183
|
+
- 🔴 **块后端不要 import 它**(平台内部模型),开发包的清单里也不会给出那句 import 提示。
|
|
184
|
+
|
|
109
185
|
## 运行环境
|
|
110
186
|
|
|
111
187
|
- Python ≥ 3.10
|
|
@@ -2,7 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
**没有前端工程、没有构建、没有生成物、不读任何项目文件**:
|
|
4
4
|
"当前长什么样"直接读 Django 的模型元数据(进程内的 `_meta`),
|
|
5
|
-
"上一版长什么样"
|
|
5
|
+
"上一版长什么样"是**从那个提交的源码现算的**(`ast` 解析那个提交里的 `models.py`,
|
|
6
|
+
起不来时退回提交里那份契约 JSON)—— 见 `gitinfo.py` 的文件头,那里是这一条的真源。
|
|
6
7
|
|
|
7
8
|
🔴 默认**关**:一个环境变量打开(`LABULL_SCHEMA_CANVAS` = `on` / `auto` / `off`)。
|
|
8
9
|
这一页把全部表名、字段名、关联、备注摊在一个 URL 上 —— 那是业务结构本身,
|
|
@@ -11,6 +12,9 @@
|
|
|
11
12
|
🔴 **打开之后这一页不看身份**(不需要登录,也不要求 staff):它是开发期调模型用的工具,
|
|
12
13
|
每次看一眼都要先去 Authing 转一圈太碍事。所以那道**开关就是唯一的边界**:
|
|
13
14
|
只在开发机上开 `on`,公网要么别开、要么在反向代理那一层加 Basic 认证 / IP 白名单。
|
|
15
|
+
|
|
16
|
+
🔴 图上有**两类节点**:库里的**表**,以及**虚拟类**(`@virtual_class` 的抽象模型,不建表 ——
|
|
17
|
+
见 `labull_framework/virtual.py` 的文件头)。两份都是"从真源算出来的",这里不需要额外维护什么。
|
|
14
18
|
"""
|
|
15
19
|
|
|
16
20
|
from __future__ import annotations
|