valar 1.1.4__py3-none-any.whl → 1.2.1__py3-none-any.whl

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.

Potentially problematic release.


This version of valar might be problematic. Click here for more details.

Files changed (47) hide show
  1. valar/apps.py +6 -9
  2. valar/channels/consumer.py +10 -12
  3. valar/channels/executer.py +7 -6
  4. valar/channels/sender.py +95 -43
  5. valar/channels/views.py +2 -3
  6. valar/classes/{auto_migration_mixin.py → app_mixins/auto_migration_mixin.py} +2 -2
  7. valar/classes/{auto_urlpatterns_mixin.py → app_mixins/auto_urlpatterns_mixin.py} +3 -3
  8. valar/classes/valar_minio.py +80 -0
  9. valar/classes/valar_response.py +2 -1
  10. valar/dao/__init__.py +45 -0
  11. valar/dao/abstract.py +106 -0
  12. valar/dao/defaults/__init__.py +0 -0
  13. valar/dao/defaults/field_keys_default.py +48 -0
  14. valar/dao/defaults/field_values_default.py +135 -0
  15. valar/dao/defaults/view_defaults.py +26 -0
  16. valar/dao/engine.py +80 -0
  17. valar/dao/frame.py +189 -0
  18. valar/dao/meta.py +128 -0
  19. valar/dao/mon_dao.py +113 -0
  20. valar/dao/mon_field.py +23 -0
  21. valar/dao/orm_dao.py +304 -0
  22. valar/dao/orm_field.py +142 -0
  23. valar/dao/query.py +36 -0
  24. valar/migrations/0001_initial.py +25 -17
  25. valar/models/core.py +16 -10
  26. valar/models/frame.py +4 -7
  27. valar/models/meta.py +19 -16
  28. valar/urls.py +22 -0
  29. valar/views/file.py +49 -0
  30. valar/views/handler.py +33 -0
  31. valar/views/meta.py +150 -0
  32. valar/views/rest.py +90 -0
  33. {valar-1.1.4.dist-info → valar-1.2.1.dist-info}/METADATA +9 -14
  34. valar-1.2.1.dist-info/RECORD +54 -0
  35. {valar-1.1.4.dist-info → valar-1.2.1.dist-info}/top_level.txt +1 -0
  36. vtest/__init__.py +0 -0
  37. vtest/apps.py +17 -0
  38. vtest/handlers.py +15 -0
  39. vtest/migrations/0001_initial.py +155 -0
  40. vtest/migrations/__init__.py +0 -0
  41. vtest/models.py +59 -0
  42. vtest/views.py +8 -0
  43. valar-1.1.4.dist-info/RECORD +0 -28
  44. /valar/{classes → channels}/counter.py +0 -0
  45. /valar/{frame → classes/app_mixins}/__init__.py +0 -0
  46. {valar-1.1.4.dist-info → valar-1.2.1.dist-info}/WHEEL +0 -0
  47. {valar-1.1.4.dist-info → valar-1.2.1.dist-info}/licenses/LICENSE +0 -0
valar/dao/mon_field.py ADDED
@@ -0,0 +1,23 @@
1
+ from ..dao.abstract import AbstractField
2
+ from ..dao.frame import meta_field_tool_mapping
3
+
4
+
5
+ class MonField(AbstractField):
6
+
7
+ def __init__(self, entity, prop, domain, tool):
8
+ self.db = 'mon'
9
+ self.entity = entity
10
+ self.prop = prop
11
+ self.label = prop
12
+ self.domain = domain
13
+ self.tool = tool
14
+
15
+ def to_dict(self):
16
+ _field = {
17
+ "prop": self.prop,
18
+ "label": self.label,
19
+ "name": self.label,
20
+ "domain": self.domain,
21
+ 'tool': self.tool,
22
+ }
23
+ return _field
valar/dao/orm_dao.py ADDED
@@ -0,0 +1,304 @@
1
+ import datetime
2
+ import json
3
+
4
+ from django.core.paginator import Paginator
5
+
6
+ from .abstract import AbstractDao
7
+ from .query import Query
8
+ from django.db.models import ManyToOneRel, ForeignKey, ManyToManyRel, ManyToManyField, OneToOneField, OneToOneRel
9
+ from django.db.models import QuerySet
10
+ from django.db.models import Manager
11
+ from django.db.models.fields.files import FieldFile
12
+ from django.forms import FileField
13
+
14
+ from ..dao.orm_field import OrmField
15
+ from ..models.core import VTree, VModel
16
+ from ..models.meta import MetaField
17
+
18
+
19
+ class OrmDao(AbstractDao):
20
+
21
+ def __init__(self, entity):
22
+ model = self.engine.get_orm_model(entity)
23
+ meta = getattr(model, '_meta')
24
+ self.minio = self.engine.get_minio_bucket(entity)
25
+ self.db = 'orm'
26
+ self.entity = entity
27
+ self.name = meta.verbose_name
28
+ self.is_tree = issubclass(model, VTree)
29
+ self.manager: Manager = model.objects
30
+ fields = {}
31
+ model_fields = meta.get_fields()
32
+ for model_field in model_fields:
33
+ meta_field = OrmField(entity, model_field, self.is_tree)
34
+ fields[meta_field.prop] = meta_field
35
+ self.fields = fields
36
+
37
+ def save_many(self, array: list):
38
+ pass
39
+
40
+ def values(self, conditions, props: list):
41
+ query_set, _ = self.find(conditions)
42
+ if 'id' not in props:
43
+ props.append('id')
44
+ return list(query_set.values(*props))
45
+
46
+ def save_one(self, item, with_id=False):
47
+ oid, simple_item, complex_item = self.__detach_item__(item)
48
+ query_set = self.manager.filter(id=oid) if oid else []
49
+ if len(query_set):
50
+ simple_item['modify_time'] = datetime.datetime.now()
51
+ query_set.update(**simple_item)
52
+ bean = query_set.first()
53
+ else:
54
+ if oid:
55
+ simple_item.update({'id': oid})
56
+ bean = self.manager.create(**simple_item)
57
+ if simple_item.get('sort') is None:
58
+ bean.sort = bean.id
59
+ bean.save()
60
+ self.__save_complex_field__(complex_item, bean)
61
+ bean.save()
62
+ return bean
63
+
64
+ def delete_one(self, _id):
65
+ oid = self.object_id(_id)
66
+ flag = oid is not None
67
+ if flag:
68
+ query_set = self.manager.filter(id=oid)
69
+ paths = self.__get_file_paths__(query_set)
70
+ for path in paths:
71
+ self.minio.remove(path)
72
+ query_set.delete()
73
+ return flag
74
+
75
+ def find_one(self, _id):
76
+ oid = self.object_id(_id)
77
+ return self.manager.filter(id=oid).first() if oid is not None else None
78
+
79
+ def find(self, conditions=None, orders=None, size=0, page=1):
80
+ includes, excludes, orders = Query(conditions, orders).orm()
81
+ query_set = self.manager.filter(includes).exclude(excludes).order_by(*orders)
82
+ total = query_set.count()
83
+ if size:
84
+ paginator = Paginator(query_set, size)
85
+ query_set = paginator.page(page).object_list
86
+ return query_set, total
87
+
88
+ def update(self, template, conditions):
89
+ flag = template is not None and len(template.keys())
90
+ if flag:
91
+ oid, simple_item, complex_item = self.__detach_item__(template)
92
+ query_set, total = self.find(conditions)
93
+ query_set.update(**simple_item)
94
+ return flag
95
+
96
+ def delete(self, conditions=None) -> list:
97
+ query_set, total = self.find(conditions)
98
+ query_set.delete()
99
+ return self.__get_file_paths__(query_set)
100
+
101
+ def serialize(self, o, code=None):
102
+ return self.__to_dict__(o, code) if isinstance(o, QuerySet) else o.full()
103
+
104
+ def tree(self, root, conditions=None):
105
+ all_set, _ = self.find()
106
+ if Query(conditions).is_empty:
107
+ return all_set
108
+ values = all_set.values('id', 'pid')
109
+ mapping = {item['id']: item['pid'] for item in values}
110
+ results, _ = self.find(conditions)
111
+ id_set = {root}
112
+ for item in results:
113
+ _id = item.id
114
+ route = []
115
+ while _id is not None:
116
+ route.append(_id)
117
+ _id = mapping.get(_id)
118
+ if root in route:
119
+ id_set.update(route)
120
+ return all_set.filter(id__in=id_set).order_by('-sort')
121
+
122
+ """ 以下为私有方法 """
123
+
124
+ def __detach_item__(self, item):
125
+ _id = item.get('id')
126
+ if _id:
127
+ del item['id']
128
+ simple_item = {}
129
+ complex_item = {}
130
+ for prop in item:
131
+ meta_field = self.fields.get(prop)
132
+ if meta_field:
133
+ value = item.get(prop)
134
+ if meta_field.domain in ['ManyToOneRel', 'ManyToManyField', 'ManyToManyRel']:
135
+ complex_item[prop] = value
136
+ elif meta_field.domain in ['OneToOneRel', 'OneToOneField', 'FileField']:
137
+ complex_item[prop] = value
138
+ else:
139
+ simple_item[prop] = value
140
+ return self.object_id(_id), simple_item, complex_item
141
+
142
+ def __save_complex_field__(self, complex_item, bean):
143
+ for prop in complex_item:
144
+ value = complex_item[prop]
145
+ model_field = self.fields[prop].model_field
146
+ clazz = type(model_field)
147
+ if clazz == ManyToManyField:
148
+ m2m = getattr(bean, prop)
149
+ m2m.clear()
150
+ m2m.add(*value)
151
+ elif clazz == ManyToOneRel:
152
+ getattr(bean, model_field.get_accessor_name()).clear()
153
+ remote_model: VModel = model_field.related_model
154
+ new_set: QuerySet = remote_model.objects.filter(id__in=value)
155
+ remote_field: ForeignKey = model_field.remote_field
156
+ k = remote_field.get_attname()
157
+ new_set.update(**{k: bean.id})
158
+ elif clazz == ManyToManyRel:
159
+ getattr(bean, model_field.get_accessor_name()).clear()
160
+ remote_model: VModel = model_field.related_model
161
+ remote_items: QuerySet = remote_model.objects.filter(id__in=value)
162
+ remote_field: ManyToManyField = model_field.remote_field
163
+ remote_field_prop = remote_field.get_attname()
164
+ for _bean in remote_items:
165
+ bean_set = getattr(_bean, remote_field_prop)
166
+ bean_set.add(bean)
167
+ elif clazz == OneToOneRel and value is not None:
168
+ remote_model: VModel = model_field.related_model
169
+ remote_field: OneToOneField = model_field.remote_field
170
+ remote_field_prop = remote_field.get_attname()
171
+ _bean = remote_model.objects.get(id=value)
172
+ __bean = remote_model.objects.filter(**{remote_field_prop: bean.id}).first()
173
+ if __bean:
174
+ setattr(__bean, remote_field_prop, None)
175
+ __bean.save()
176
+ setattr(_bean, remote_field_prop, bean.id)
177
+ _bean.save()
178
+ elif clazz == OneToOneField and value is not None:
179
+ __bean = model_field.model.objects.filter(**{prop: value}).first()
180
+ if __bean:
181
+ setattr(__bean, prop, None)
182
+ __bean.save()
183
+ setattr(bean, prop, value)
184
+ elif clazz == FileField:
185
+ file_name, _bytes = value
186
+ field_file: FieldFile = getattr(bean, prop)
187
+ if field_file:
188
+ path = field_file.name
189
+ self.minio.remove(path)
190
+ object_name = self.minio.get_object_name(bean.id, prop, file_name)
191
+ path = self.minio.upload(object_name, _bytes) if _bytes else None
192
+ setattr(bean, prop, path)
193
+
194
+ def __get_file_paths__(self, query_set: QuerySet):
195
+ props = self.props('FileField')
196
+ if len(props):
197
+ items = query_set.values(*props)
198
+ paths = []
199
+ for item in items:
200
+ paths += [i for i in item.values() if i]
201
+ return [path for path in paths if path]
202
+ return []
203
+
204
+ def __to_dict__(self, query_set: QuerySet, code=None):
205
+ meta_fields = self.fields.values()
206
+ # 简单字段取值
207
+ simple_props = [field.prop for field in meta_fields if field.domain not in __referred_domains__]
208
+ custom_props = __get_custom_props__(self.entity, code)
209
+ results = list(query_set.filter().values(*[*simple_props, *custom_props]))
210
+ __set_simple_values__(meta_fields, results)
211
+ # 关系型字段取值
212
+ mapping = {row['id']: row for row in results}
213
+ referred_fields = [field for field in meta_fields if field.domain in __referred_domains__]
214
+ pks = mapping.keys()
215
+ for meta_field in referred_fields:
216
+ manager: Manager = query_set.model.objects
217
+ qs = manager.filter(id__in=pks)
218
+ __linkage__(meta_field, qs, mapping)
219
+ return results
220
+
221
+
222
+ """ 以下为静态方法和变量 """
223
+
224
+ __multiple_domains__ = ['ManyToOneRel', 'ManyToManyField', 'ManyToManyRel']
225
+ __referred_domains__ = [*__multiple_domains__, 'OneToOneRel', 'OneToOneField', 'ForeignKey']
226
+ __omit_field_props__ = ['create_time', 'modify_time', 'saved', 'sort']
227
+ __data_props_formatting__ = {'DateField': '%Y-%m-%d', 'DateTimeField': '%Y-%m-%d %H:%M:%S', 'TimeField': '%H:%M:%S'}
228
+
229
+
230
+ def __get_custom_props__(entity, code='default'):
231
+ field_set = MetaField.objects.filter(view__code=code, view__meta__entity=entity, domain='Custom').values('prop')
232
+ return [item['prop'] for item in field_set if item['prop'] is not None]
233
+
234
+
235
+ def __set_simple_values__(fields, values):
236
+ date_props_mapping = {}
237
+ json_props = []
238
+ for field in fields:
239
+ if isinstance(field, OrmField):
240
+ prop = field.prop
241
+ domain = field.domain
242
+ else:
243
+ prop = field.name
244
+ domain = type(field).__name__
245
+ if domain in __data_props_formatting__.keys():
246
+ date_props_mapping[prop] = __data_props_formatting__[domain]
247
+ elif domain == 'JSONField':
248
+ json_props.append(prop)
249
+ for row in values:
250
+ for prop, formating in date_props_mapping.items():
251
+ if row.get(prop):
252
+ row[prop] = row[prop].strftime(formating)
253
+ for prop in json_props:
254
+ row[prop] = json.loads(row[prop]) if type(row[prop]) is str else row[prop]
255
+
256
+
257
+ def __get_related_props__(fields):
258
+ def fun(field): return type(field).__name__ not in __referred_domains__ and field.name not in __omit_field_props__
259
+
260
+ return [field.name for field in fields if fun(field)]
261
+
262
+
263
+ def __linkage__(meta_field: OrmField, query_set: QuerySet, mapping):
264
+ model_field = meta_field.model_field
265
+ prop = model_field.name
266
+ multiple = meta_field.domain in __multiple_domains__
267
+
268
+ # 获取级联关系的键索引
269
+ ref_prop = f'{prop}__id'
270
+ edges = query_set.exclude(**{f'{ref_prop}__isnull': True}).values('id', ref_prop)
271
+ if multiple:
272
+ related_primary_keys = set()
273
+ results_mapping = {}
274
+ for edge in edges:
275
+ _id, rid = edge['id'], edge[ref_prop]
276
+ related_primary_keys.add(rid)
277
+ array = results_mapping.get(_id, [])
278
+ array.append(rid)
279
+ results_mapping[_id] = array
280
+ else:
281
+ results_mapping = {row['id']: row[ref_prop] for row in edges if row[ref_prop]}
282
+ related_primary_keys = set(results_mapping.values())
283
+
284
+ # 获取级联关系从属方的数据
285
+ related_model = model_field.related_model
286
+ related_fields = related_model._meta.get_fields()
287
+ related_props = __get_related_props__(related_fields)
288
+ related_values = list(related_model.objects.filter(id__in=related_primary_keys).values(*related_props))
289
+ __set_simple_values__(related_fields, related_values)
290
+ related_mapping = {item['id']: item for item in related_values}
291
+
292
+ # 将从属方的数据绑定在主数据上
293
+ for _id in mapping:
294
+ row = mapping[_id]
295
+ if multiple:
296
+ keys = results_mapping.get(_id, [])
297
+ items = [related_mapping[pid] for pid in keys]
298
+ row[prop] = keys
299
+ row[f'{prop}_set'] = items
300
+ else:
301
+ key = results_mapping.get(_id)
302
+ item = related_mapping.get(key) if key else None
303
+ row[prop] = item
304
+ row[f'{prop}_id'] = key
valar/dao/orm_field.py ADDED
@@ -0,0 +1,142 @@
1
+ from deepmerge import always_merger
2
+ from django.db.models import ManyToOneRel, ForeignKey, ManyToManyRel, ManyToManyField, OneToOneField, OneToOneRel
3
+ from django.db.models import IntegerField, BooleanField, FloatField, TextField, CharField
4
+ from django.db.models import FileField, JSONField
5
+ from django.db.models import DateTimeField, TimeField, DateField
6
+ from django.db.models.options import Options
7
+
8
+ from ..dao.abstract import AbstractField
9
+ from ..dao.frame import meta_field_domain_mapping, meta_field_tool_mapping
10
+ from ..models.core import VTree
11
+
12
+
13
+ class OrmField(AbstractField):
14
+
15
+ def __init__(self, entity, model_field, is_tree):
16
+ self.db = 'orm'
17
+ self.entity = entity
18
+ self.model_field = model_field
19
+ self.is_tree = is_tree
20
+ self.not_null = not model_field.null
21
+ self.clazz = type(model_field)
22
+ self.multiple = self.clazz in [ManyToOneRel, ManyToManyField, ManyToManyRel]
23
+ self.prop = self.__prop__()
24
+ self.domain = self.__domain__()
25
+ self.model = self.__model__()
26
+ self.label = self.__label__()
27
+ self.tool = meta_field_domain_mapping.get(self.domain, 'none')
28
+ self.column_width = column_width(self.domain, self.tool)
29
+ self.refer = self.__refer__()
30
+ self.format = self.__formating__()
31
+
32
+ def to_dict(self):
33
+ _field = {
34
+ "prop": self.prop,
35
+ "label": self.label,
36
+ "name": self.label,
37
+ "domain": self.domain,
38
+ "refer": self.refer,
39
+ "format": self.format,
40
+ "not_null": self.not_null,
41
+ "column_width": self.column_width,
42
+ "tool": self.tool,
43
+ "disabled": False,
44
+ }
45
+ if self.is_tree:
46
+ if self.prop in ['pid', 'isLeaf']:
47
+ # _field['hide_on_table'] = True
48
+ _field['hide_on_form'] = True
49
+ _field['hide_on_form_branch'] = True
50
+ _field['hide_on_form_leaf'] = True
51
+ elif self.prop in ['icon']:
52
+ _field['tool'] = 'icon'
53
+ elif self.refer['isTree']:
54
+ _field['tool'] = 'tree'
55
+ return _field
56
+
57
+ def __label__(self):
58
+ return self.model._meta.verbose_name \
59
+ if self.clazz in [ManyToOneRel, ManyToManyField, ManyToManyRel, OneToOneRel, OneToOneField] \
60
+ else self.model_field.verbose_name
61
+
62
+ def __model__(self):
63
+ return self.model_field.related_model \
64
+ if self.clazz in [ManyToOneRel, ManyToManyField, ManyToManyRel, OneToOneRel, OneToOneField, ForeignKey] \
65
+ else None
66
+
67
+ def __domain__(self):
68
+ return self.clazz.__name__ \
69
+ if self.clazz in [ManyToOneRel, ManyToManyField, ManyToManyRel, OneToOneRel, OneToOneField] \
70
+ else self.model_field.get_internal_type()
71
+
72
+ def __prop__(self):
73
+ return self.model_field.name + "_id" \
74
+ if self.clazz in [ForeignKey, OneToOneRel, OneToOneField] \
75
+ else self.model_field.name
76
+
77
+ def __refer__(self):
78
+ refer = {
79
+ "entity": None, "db": self.db,
80
+ "value": "id", "label": 'name', "display": "id",
81
+ "multiple": self.multiple, "strict": False, "remote": False,
82
+ "includes": {}, "excludes": {},
83
+ "root": 0, "isTree": False
84
+ }
85
+ if self.model:
86
+ meta: Options = getattr(self.model, '_meta')
87
+
88
+ refer['entity'] = '%s.%s' % (meta.app_label, self.model.__name__)
89
+ refer['isTree'] = issubclass(self.model, VTree)
90
+ return refer
91
+
92
+ def __formating__(self):
93
+ _format = {
94
+ # 文本
95
+ "maxlength": None,
96
+ "type": 'text',
97
+
98
+ # 数值
99
+ "min": None,
100
+ "max": None,
101
+ "step": 1,
102
+ "precision": None,
103
+ "step_strictly": False,
104
+
105
+ # 日期
106
+ "frequency": "date",
107
+
108
+ # 文件
109
+ "maximum": 5,
110
+ "accept": [],
111
+ "width": 800,
112
+ "height": None,
113
+ "file_name_field": None,
114
+ "locked": False,
115
+
116
+ # 集合
117
+ "set": {},
118
+ "multiple": False
119
+ }
120
+ if self.clazz == CharField:
121
+ _format['maxlength'] = self.model_field.max_length
122
+ _format['$maxlength'] = self.model_field.max_length
123
+ if self.clazz == TextField:
124
+ _format['type'] = "textarea"
125
+ elif self.clazz == DateTimeField:
126
+ _format['frequency'] = "datetime"
127
+ elif self.clazz == IntegerField:
128
+ _format['precision'] = 0
129
+ _format['step_strictly'] = True
130
+ return _format
131
+
132
+
133
+ def column_width(domain, tool):
134
+ if domain in ['BooleanField', 'FileField', 'JSONField']:
135
+ return 80
136
+ elif domain in ['DateField', 'DateTimeField', 'TimeField']:
137
+ return 120
138
+ elif domain in ['ManyToManyRel', 'ManyToManyRel', 'ManyToOneRel']:
139
+ return 80
140
+ elif domain in ['TextField']:
141
+ return 80 if tool == 'rich' else 0
142
+ return 0
valar/dao/query.py ADDED
@@ -0,0 +1,36 @@
1
+ from django.db.models import Q
2
+ from functools import reduce
3
+
4
+
5
+ class Query:
6
+
7
+ def __init__(self, conditions: list, orders=None):
8
+ self.is_empty = conditions is None or len(conditions) == 0
9
+ self.orders = orders or {'sort': -1}
10
+ self.conditions = [{'includes': {}, 'excludes': {}}] if self.is_empty else conditions
11
+
12
+ def orm(self):
13
+ orders = __translate_orders__(self.orders)
14
+ includes = __translate_orm_condition__(self.conditions, 'includes')
15
+ excludes = __translate_orm_condition__(self.conditions, 'excludes')
16
+ return includes, excludes, orders
17
+
18
+ def mon(self):
19
+ finder = {}
20
+ return finder, self.orders
21
+
22
+
23
+ def __fun__(x, y): return x | y
24
+
25
+
26
+ def __translate_orders__(orders):
27
+ array = []
28
+ for key in orders:
29
+ value = orders.get(key)
30
+ prefix = '-' if value == -1 else ''
31
+ array.append(f'{prefix}{key}')
32
+ return array
33
+
34
+
35
+ def __translate_orm_condition__(conditions, _type):
36
+ return reduce(__fun__, [Q(**cond.get(_type, {})) for cond in conditions])
@@ -1,4 +1,4 @@
1
- # Generated by Django 4.2.23 on 2025-07-15 18:11
1
+ # Generated by Django 4.2.23 on 2025-08-28 10:15
2
2
 
3
3
  from django.db import migrations, models
4
4
  import django.db.models.deletion
@@ -19,10 +19,12 @@ class Migration(migrations.Migration):
19
19
  ('sort', models.BigIntegerField(null=True, verbose_name='序号')),
20
20
  ('create_time', models.DateTimeField(auto_now_add=True, null=True, verbose_name='创建时间')),
21
21
  ('modify_time', models.DateTimeField(auto_now=True, null=True, verbose_name='修改时间')),
22
- ('saved', models.BooleanField(default=False)),
22
+ ('disabled', models.BooleanField(default=False, verbose_name='禁用')),
23
+ ('saved', models.BooleanField(default=False, verbose_name='已保存')),
23
24
  ('db', models.CharField(max_length=100, null=True, verbose_name='数据库')),
24
25
  ('entity', models.CharField(max_length=100, null=True, verbose_name='数据源')),
25
26
  ('name', models.CharField(max_length=50, null=True, verbose_name='实体别名')),
27
+ ('tree', models.BooleanField(default=False, verbose_name='是否树形')),
26
28
  ],
27
29
  options={
28
30
  'verbose_name': '数据实体',
@@ -36,12 +38,14 @@ class Migration(migrations.Migration):
36
38
  ('sort', models.BigIntegerField(null=True, verbose_name='序号')),
37
39
  ('create_time', models.DateTimeField(auto_now_add=True, null=True, verbose_name='创建时间')),
38
40
  ('modify_time', models.DateTimeField(auto_now=True, null=True, verbose_name='修改时间')),
39
- ('saved', models.BooleanField(default=False)),
41
+ ('disabled', models.BooleanField(default=False, verbose_name='禁用')),
42
+ ('saved', models.BooleanField(default=False, verbose_name='已保存')),
40
43
  ('pid', models.IntegerField(default=0, verbose_name='父节点')),
41
44
  ('isLeaf', models.BooleanField(default=False, verbose_name='叶子节点')),
42
45
  ('icon', models.CharField(max_length=255, null=True, verbose_name='图标')),
43
46
  ('name', models.CharField(max_length=255, null=True, verbose_name='名称')),
44
47
  ('code', models.CharField(max_length=100, null=True, unique=True, verbose_name='代码')),
48
+ ('align', models.CharField(max_length=10, null=True, verbose_name='对齐方式')),
45
49
  ],
46
50
  options={
47
51
  'verbose_name': '元数据字段工具',
@@ -54,20 +58,24 @@ class Migration(migrations.Migration):
54
58
  ('sort', models.BigIntegerField(null=True, verbose_name='序号')),
55
59
  ('create_time', models.DateTimeField(auto_now_add=True, null=True, verbose_name='创建时间')),
56
60
  ('modify_time', models.DateTimeField(auto_now=True, null=True, verbose_name='修改时间')),
57
- ('saved', models.BooleanField(default=False)),
61
+ ('disabled', models.BooleanField(default=False, verbose_name='禁用')),
62
+ ('saved', models.BooleanField(default=False, verbose_name='已保存')),
63
+ ('property', models.JSONField(default=dict, verbose_name='属性')),
58
64
  ('code', models.CharField(default='default ', max_length=50, verbose_name='类视图')),
59
65
  ('name', models.CharField(max_length=50, null=True, verbose_name='视图名称')),
60
- ('form_width', models.IntegerField(default=0, verbose_name='表单宽度')),
61
- ('form_height', models.IntegerField(default=0, verbose_name='表单高度')),
62
- ('table_width', models.IntegerField(default=0, verbose_name='表格宽度')),
63
- ('table_height', models.IntegerField(default=0, verbose_name='表格高度')),
66
+ ('lock', models.BooleanField(default=False, verbose_name='锁定元数据')),
64
67
  ('enable', models.BooleanField(default=True, verbose_name='是否启用')),
65
- ('show_header', models.BooleanField(default=True, verbose_name='展示头部')),
68
+ ('form_width', models.IntegerField(null=True, verbose_name='表单宽度')),
69
+ ('form_height', models.IntegerField(null=True, verbose_name='表单高度')),
70
+ ('table_width', models.IntegerField(null=True, verbose_name='表格宽度')),
71
+ ('table_height', models.IntegerField(null=True, verbose_name='表格高度')),
66
72
  ('allow_search', models.BooleanField(default=True, verbose_name='检索功能')),
67
- ('allow_sort', models.BooleanField(default=True, verbose_name='移动功能')),
68
73
  ('allow_order', models.BooleanField(default=True, verbose_name='排序功能')),
69
74
  ('allow_insert', models.BooleanField(default=True, verbose_name='新增功能')),
70
75
  ('allow_edit', models.BooleanField(default=True, verbose_name='编辑功能')),
76
+ ('allow_edit_on_form', models.BooleanField(default=True, verbose_name='表单编辑')),
77
+ ('allow_edit_on_cell', models.BooleanField(default=True, verbose_name='表内编辑')),
78
+ ('allow_edit_on_sort', models.BooleanField(default=True, verbose_name='移动功能')),
71
79
  ('allow_remove', models.BooleanField(default=True, verbose_name='删除功能')),
72
80
  ('allow_download', models.BooleanField(default=True, verbose_name='下载功能')),
73
81
  ('allow_upload', models.BooleanField(default=True, verbose_name='上传功能')),
@@ -85,11 +93,10 @@ class Migration(migrations.Migration):
85
93
  ('sort', models.BigIntegerField(null=True, verbose_name='序号')),
86
94
  ('create_time', models.DateTimeField(auto_now_add=True, null=True, verbose_name='创建时间')),
87
95
  ('modify_time', models.DateTimeField(auto_now=True, null=True, verbose_name='修改时间')),
88
- ('saved', models.BooleanField(default=False)),
96
+ ('disabled', models.BooleanField(default=False, verbose_name='禁用')),
97
+ ('saved', models.BooleanField(default=False, verbose_name='已保存')),
89
98
  ('name', models.CharField(max_length=255, null=True, unique=True, verbose_name='名称')),
90
- ('align', models.CharField(max_length=10, null=True, verbose_name='对齐方式')),
91
99
  ('default', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to='valar.metafieldtool', verbose_name='默认工具')),
92
- ('search', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to='valar.metafieldtool', verbose_name='搜索工具')),
93
100
  ('tools', models.ManyToManyField(to='valar.metafieldtool', verbose_name='工具集')),
94
101
  ],
95
102
  options={
@@ -103,7 +110,7 @@ class Migration(migrations.Migration):
103
110
  ('sort', models.BigIntegerField(null=True, verbose_name='序号')),
104
111
  ('create_time', models.DateTimeField(auto_now_add=True, null=True, verbose_name='创建时间')),
105
112
  ('modify_time', models.DateTimeField(auto_now=True, null=True, verbose_name='修改时间')),
106
- ('saved', models.BooleanField(default=False)),
113
+ ('saved', models.BooleanField(default=False, verbose_name='已保存')),
107
114
  ('prop', models.CharField(max_length=100, verbose_name='字段名称')),
108
115
  ('label', models.CharField(max_length=100, verbose_name='字段标签')),
109
116
  ('name', models.CharField(max_length=100, verbose_name='字段别名')),
@@ -111,16 +118,17 @@ class Migration(migrations.Migration):
111
118
  ('tool', models.CharField(default='default', max_length=100, verbose_name='工具组件')),
112
119
  ('refer', models.JSONField(default=dict, verbose_name='索引')),
113
120
  ('format', models.JSONField(default=dict, verbose_name='格式')),
121
+ ('disabled', models.BooleanField(default=False, verbose_name='禁用')),
114
122
  ('not_null', models.BooleanField(default=False, verbose_name='不为空')),
115
123
  ('allow_edit', models.BooleanField(default=True, verbose_name='可编辑')),
116
124
  ('allow_order', models.BooleanField(default=True, verbose_name='可排序')),
117
125
  ('allow_search', models.BooleanField(default=True, verbose_name='可搜索')),
118
126
  ('allow_download', models.BooleanField(default=True, verbose_name='可下载')),
119
- ('allow_upload', models.BooleanField(default=False, verbose_name='可上传')),
120
- ('allow_update', models.BooleanField(default=False, verbose_name='可更新')),
127
+ ('allow_upload', models.BooleanField(default=True, verbose_name='可上传')),
128
+ ('allow_update', models.BooleanField(default=True, verbose_name='可更新')),
121
129
  ('unit', models.CharField(max_length=55, null=True, verbose_name='单位符')),
122
130
  ('column_width', models.FloatField(default=0, verbose_name='表头宽度')),
123
- ('align', models.CharField(default='left', max_length=55, verbose_name='对齐方式')),
131
+ ('align', models.CharField(max_length=55, null=True, verbose_name='对齐方式')),
124
132
  ('fixed', models.CharField(max_length=100, null=True, verbose_name='固定位置')),
125
133
  ('header_color', models.CharField(max_length=55, null=True, verbose_name='表头颜色')),
126
134
  ('cell_color', models.CharField(max_length=55, null=True, verbose_name='单元颜色')),