valar 1.0.20__py3-none-any.whl → 1.0.22__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.
- valar/__init__.py +0 -26
- valar/channels/__init__.py +1 -107
- valar/channels/consumer.py +48 -0
- valar/channels/executer.py +13 -0
- valar/channels/mapping.py +21 -0
- valar/channels/sender.py +60 -0
- valar/channels/views.py +6 -11
- valar/core/__init__.py +0 -0
- valar/core/counter.py +9 -0
- valar/core/dao/__init__.py +0 -0
- valar/core/dao/_mon_array2tree.py +18 -0
- valar/core/dao/dao_base.py +50 -0
- valar/core/dao/dao_mon.py +76 -0
- valar/core/dao/dao_orm.py +96 -0
- valar/core/dao/engine.py +12 -0
- valar/core/dao/engine_minio.py +90 -0
- valar/core/dao/engine_mon.py +34 -0
- valar/core/dao/engine_orm.py +25 -0
- valar/core/dao/model_mon.py +24 -0
- valar/core/dao/model_orm.py +192 -0
- valar/core/dao/query_mon.py +12 -0
- valar/core/dao/query_orm.py +43 -0
- valar/core/dao/utils_orm.py +85 -0
- valar/core/dao_abstract.py +63 -0
- valar/core/meta/__init__.py +0 -0
- valar/core/meta/defaults/__init__.py +0 -0
- valar/core/meta/defaults/field_keys_default.py +17 -0
- valar/core/meta/defaults/field_values_default.py +85 -0
- valar/core/meta/defaults/frame_defaults.py +136 -0
- valar/core/meta/defaults/view_defaults.py +7 -0
- valar/core/meta/field_orm.py +144 -0
- valar/core/meta/init_meta_frame.py +30 -0
- valar/core/meta/meta_orm.py +69 -0
- valar/core/middleware.py +20 -0
- valar/core/response.py +7 -0
- valar/core/singleton_meta.py +6 -0
- valar/core/valar_models.py +82 -0
- valar/data/apps.py +22 -0
- valar/data/migrations/0001_initial.py +1 -98
- valar/data/models.py +2 -122
- valar/data/urls.py +15 -21
- valar/data/views/__init__.py +0 -0
- valar/data/views/handler.py +41 -0
- valar/data/views/rest.py +86 -0
- {valar-1.0.20.dist-info → valar-1.0.22.dist-info}/METADATA +1 -1
- valar-1.0.22.dist-info/RECORD +51 -0
- {valar-1.0.20.dist-info → valar-1.0.22.dist-info}/WHEEL +1 -1
- valar/channels/utils.py +0 -43
- valar/data/file/__init__.py +0 -91
- valar/data/handlers.py +0 -28
- valar/data/mon/__init__.py +0 -123
- valar/data/mon/query_translator.py +0 -91
- valar/data/orm/__init__.py +0 -135
- valar/data/orm/detacher.py +0 -61
- valar/data/orm/meta.py +0 -99
- valar/data/orm/meta_frame.py +0 -49
- valar/data/orm/meta_loader.py +0 -200
- valar/data/orm/values.py +0 -102
- valar/data/query.py +0 -48
- valar/data/utils.py +0 -70
- valar/data/views.py +0 -173
- valar-1.0.20.dist-info/RECORD +0 -27
- {valar-1.0.20.dist-info → valar-1.0.22.dist-info}/licenses/LICENSE +0 -0
- {valar-1.0.20.dist-info → valar-1.0.22.dist-info}/top_level.txt +0 -0
|
@@ -1,91 +0,0 @@
|
|
|
1
|
-
class MongoQueryTranslator:
|
|
2
|
-
# 将Django ORM查询操作符映射到MongoDB操作符的字典
|
|
3
|
-
MONGO_OPERATORS = {
|
|
4
|
-
'exact': lambda v, e: {'$ne': v} if e else v,
|
|
5
|
-
'iexact': lambda v, e: {'$not': {'$regex': f'^{v}$', '$options': 'i'}} if e else {'$regex': f'^{v}$', '$options': 'i'},
|
|
6
|
-
'contains': lambda v, e: {'$not': {'$regex': f'{v}'}} if e else {'$regex': f'{v}'},
|
|
7
|
-
'icontains': lambda v, e: {'$not': {'$regex': f'{v}', '$options': 'i'}} if e else {'$regex': f'{v}', '$options': 'i'},
|
|
8
|
-
'startswith': lambda v, e: {'$not': {'$regex': f'^{v}'}} if e else {'$regex': f'^{v}'},
|
|
9
|
-
'istartswith': lambda v, e: {'$not': {'$regex': f'^{v}', '$options': 'i'}} if e else {'$regex': f'^{v}', '$options': 'i'},
|
|
10
|
-
'endswith': lambda v, e: {'$not': {'$regex': f'{v}$'}} if e else {'$regex': f'{v}$'},
|
|
11
|
-
'iendswith': lambda v, e: {'$not': {'$regex': f'{v}$', '$options': 'i'}} if e else {'$regex': f'{v}$', '$options': 'i'},
|
|
12
|
-
'gt': lambda v, e: {'$not': {'$gt': v}} if e else {'$gt': v},
|
|
13
|
-
'gte': lambda v, e: {'$not': {'$gte': v}} if e else {'$gte': v},
|
|
14
|
-
'lt': lambda v, e: {'$not': {'$lt': v}} if e else {'$lt': v},
|
|
15
|
-
'lte': lambda v, e: {'$not': {'$lte': v}} if e else {'$lte': v},
|
|
16
|
-
'in': lambda v, e: {'$nin': v} if e else {'$in': v},
|
|
17
|
-
'exists': lambda v, e: {'$eq': None} if (e and bool(v)) or (not e and not bool(v)) else {'$ne': None},
|
|
18
|
-
'isnull': lambda v, e: {'$ne': None} if e else {'$eq': None},
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
@classmethod
|
|
22
|
-
def process_field_query(cls, key, value, is_exclude=False):
|
|
23
|
-
"""处理单个字段查询"""
|
|
24
|
-
if '__' in key:
|
|
25
|
-
field, op = key.split('__', 1)
|
|
26
|
-
if op in cls.MONGO_OPERATORS:
|
|
27
|
-
return field, cls.MONGO_OPERATORS[op](value, is_exclude)
|
|
28
|
-
return key, {'$ne': value} if is_exclude else value
|
|
29
|
-
|
|
30
|
-
@classmethod
|
|
31
|
-
def process_condition(cls, condition_dict, is_exclude=False):
|
|
32
|
-
"""处理条件字典,返回MongoDB查询条件"""
|
|
33
|
-
return {field: query for field, query in
|
|
34
|
-
[cls.process_field_query(k, v, is_exclude) for k, v in condition_dict.items()]}
|
|
35
|
-
|
|
36
|
-
@classmethod
|
|
37
|
-
def process_finder(cls, finder):
|
|
38
|
-
"""处理finder字段,转换为MongoDB查询条件"""
|
|
39
|
-
if not finder:
|
|
40
|
-
return {}
|
|
41
|
-
mongo_query = {}
|
|
42
|
-
if 'term' in finder and finder['term'] and isinstance(finder['term'], str):
|
|
43
|
-
term = finder['term']
|
|
44
|
-
fields = finder.get('fields', [])
|
|
45
|
-
if fields:
|
|
46
|
-
mongo_query['$or'] = [{field: {'$regex': term, '$options': 'i'}} for field in fields]
|
|
47
|
-
else:
|
|
48
|
-
mongo_query['$text'] = {'$search': term}
|
|
49
|
-
if 'range' in finder:
|
|
50
|
-
for field, ranges in finder['range'].items():
|
|
51
|
-
field_query = {f'${op}': val for op, val in ranges.items() if op in ['gt', 'gte', 'lt', 'lte']}
|
|
52
|
-
if field_query:
|
|
53
|
-
mongo_query[field] = field_query
|
|
54
|
-
for query_type, operator in [('match', None), ('exists', '$ne')]:
|
|
55
|
-
if query_type in finder:
|
|
56
|
-
for field, value in finder[query_type].items():
|
|
57
|
-
if operator == '$ne':
|
|
58
|
-
# 处理exists查询,检查字段是否为空
|
|
59
|
-
mongo_query[field] = {'$ne': None} if bool(value) else {'$eq': None}
|
|
60
|
-
else:
|
|
61
|
-
mongo_query[field] = value
|
|
62
|
-
return mongo_query
|
|
63
|
-
|
|
64
|
-
@classmethod
|
|
65
|
-
def translate_query(cls, query_obj):
|
|
66
|
-
"""
|
|
67
|
-
将Query对象转换为MongoDB查询
|
|
68
|
-
Args:
|
|
69
|
-
query_obj: Query对象,包含condition, search和finder
|
|
70
|
-
Returns:
|
|
71
|
-
转换后的MongoDB查询条件
|
|
72
|
-
"""
|
|
73
|
-
query = {}
|
|
74
|
-
query.update(cls.process_condition(query_obj.condition.includes))
|
|
75
|
-
query.update(cls.process_condition(query_obj.condition.excludes, True))
|
|
76
|
-
# 处理搜索条件
|
|
77
|
-
if query_obj.search:
|
|
78
|
-
or_conditions = []
|
|
79
|
-
for sea in query_obj.search:
|
|
80
|
-
search_query = {}
|
|
81
|
-
search_query.update(cls.process_condition(sea.includes))
|
|
82
|
-
search_query.update(cls.process_condition(sea.excludes, True))
|
|
83
|
-
if search_query:
|
|
84
|
-
or_conditions.append(search_query)
|
|
85
|
-
if or_conditions:
|
|
86
|
-
query["$or"] = or_conditions
|
|
87
|
-
# 处理和合并finder条件
|
|
88
|
-
finder_query = cls.process_finder(query_obj.finder)
|
|
89
|
-
if finder_query and query:
|
|
90
|
-
return {"$and": [query, finder_query]}
|
|
91
|
-
return finder_query or query
|
valar/data/orm/__init__.py
DELETED
|
@@ -1,135 +0,0 @@
|
|
|
1
|
-
import datetime
|
|
2
|
-
from django.apps import apps
|
|
3
|
-
from django.core.paginator import Paginator
|
|
4
|
-
from django.db.models import Manager, QuerySet, FileField
|
|
5
|
-
|
|
6
|
-
from .meta_frame import load_meta_frame
|
|
7
|
-
from ..file import minio_remove_path
|
|
8
|
-
from ..orm.detacher import detach_props, save_detached
|
|
9
|
-
from ..orm.meta_loader import load_meta, load_view, load_meta_field
|
|
10
|
-
from ..models import VModel, VTree
|
|
11
|
-
from ..query import Query
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
load_meta_frame()
|
|
15
|
-
|
|
16
|
-
def load_model(entity=None):
|
|
17
|
-
mapping = {}
|
|
18
|
-
for mod in apps.get_models():
|
|
19
|
-
if issubclass(mod, VModel):
|
|
20
|
-
path, name = mod.__module__, mod.__name__
|
|
21
|
-
__old = 'src.valar.' if path.startswith('src') else 'valar.'
|
|
22
|
-
app = path.replace('.models', '').replace(__old,'')
|
|
23
|
-
key = '%s.%s' % (app, name)
|
|
24
|
-
verbose_name = mod._meta.verbose_name
|
|
25
|
-
mapping[key] = [mod, verbose_name]
|
|
26
|
-
return mapping.get(entity) if entity else mapping
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
class OrmDao:
|
|
32
|
-
def __init__(self, entity):
|
|
33
|
-
self.entity = entity
|
|
34
|
-
param = load_model(entity)
|
|
35
|
-
if param is None:
|
|
36
|
-
raise Exception('no entity named %s' % entity)
|
|
37
|
-
self.model = param[0]
|
|
38
|
-
self.isTree = issubclass(self.model, VTree)
|
|
39
|
-
self.name: str = param[1]
|
|
40
|
-
self.manager: Manager = self.model.objects
|
|
41
|
-
self.meta_fields = {}
|
|
42
|
-
self.model_fields = {}
|
|
43
|
-
for field in self.model._meta.get_fields():
|
|
44
|
-
_field = load_meta_field(field, self.isTree)
|
|
45
|
-
prop = _field['prop']
|
|
46
|
-
self.model_fields[prop] = field
|
|
47
|
-
self.meta_fields[prop] = _field
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
def tree(self, query: Query, root_id = 0):
|
|
51
|
-
all_set, _ = self.find_many(Query())
|
|
52
|
-
includes, excludes = query.orm_conditions()
|
|
53
|
-
if not len(includes) + len(excludes) + root_id:
|
|
54
|
-
return all_set
|
|
55
|
-
values = all_set.values('id','pid')
|
|
56
|
-
mapping = {item['id']: item['pid'] for item in values}
|
|
57
|
-
results, _ = self.find_many(query)
|
|
58
|
-
id_set = {root_id}
|
|
59
|
-
for item in results:
|
|
60
|
-
_id = item.id
|
|
61
|
-
route = []
|
|
62
|
-
while _id is not None:
|
|
63
|
-
route.append(_id)
|
|
64
|
-
_id = mapping.get(_id)
|
|
65
|
-
if root_id in route:
|
|
66
|
-
id_set.update(route)
|
|
67
|
-
return all_set.filter(id__in=id_set).order_by('-sort')
|
|
68
|
-
|
|
69
|
-
def __check_remove_file__(self, query_set, template:dict = None):
|
|
70
|
-
props = [key for key in self.model_fields if type(self.model_fields[key]) == FileField]
|
|
71
|
-
keys = [ key for key in props if template.get(key, 1) is None] if template else props
|
|
72
|
-
if len(keys):
|
|
73
|
-
values = query_set.values(*props)
|
|
74
|
-
for row in values:
|
|
75
|
-
for path in row.values():
|
|
76
|
-
if path:
|
|
77
|
-
print(path)
|
|
78
|
-
minio_remove_path(path)
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
def save_one(self, item):
|
|
83
|
-
_item = detach_props(item, self.meta_fields.values())
|
|
84
|
-
_id = item.get('id',0)
|
|
85
|
-
query_set = self.manager.filter(id=_id)
|
|
86
|
-
if len(query_set):
|
|
87
|
-
del item['id']
|
|
88
|
-
item['modify_time'] = datetime.datetime.now()
|
|
89
|
-
self.__check_remove_file__(query_set,item)
|
|
90
|
-
query_set.update(**item)
|
|
91
|
-
bean = query_set.first()
|
|
92
|
-
else:
|
|
93
|
-
bean = self.manager.create(**item)
|
|
94
|
-
bean.sort = bean.id
|
|
95
|
-
bean.save()
|
|
96
|
-
save_detached(bean, _item, self.model_fields)
|
|
97
|
-
return bean
|
|
98
|
-
|
|
99
|
-
def update_many(self, query: Query, template):
|
|
100
|
-
query_set, total = self.find_many(query)
|
|
101
|
-
query_set.update(**template)
|
|
102
|
-
|
|
103
|
-
def delete_one(self, _id):
|
|
104
|
-
query_set = self.manager.filter(id=_id)
|
|
105
|
-
self.__check_remove_file__(query_set)
|
|
106
|
-
query_set.delete()
|
|
107
|
-
|
|
108
|
-
def delete_many(self, query: Query):
|
|
109
|
-
query_set, total = self.find_many(query)
|
|
110
|
-
self.__check_remove_file__(query_set)
|
|
111
|
-
query_set.delete()
|
|
112
|
-
|
|
113
|
-
def find_one(self, _id):
|
|
114
|
-
return self.manager.filter(id=_id).first()
|
|
115
|
-
|
|
116
|
-
def find_many(self, query: Query, size=0, page=1):
|
|
117
|
-
includes, excludes = query.orm_conditions()
|
|
118
|
-
query_set = self.manager.filter(includes).exclude(excludes).order_by(*query.orm_orders())
|
|
119
|
-
total = query_set.count()
|
|
120
|
-
if size:
|
|
121
|
-
paginator = Paginator(query_set, size)
|
|
122
|
-
query_set = paginator.page(page).object_list
|
|
123
|
-
return query_set, total
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
def meta(self, code:str = 'default'):
|
|
127
|
-
omit = [ 'id', 'saved', 'sort', 'create_time', 'modify_time']
|
|
128
|
-
fields = [ self.meta_fields[prop] for prop in self.meta_fields if prop not in omit]
|
|
129
|
-
view = load_view(self.entity, code, self.name, fields)
|
|
130
|
-
_view = load_meta(view)
|
|
131
|
-
_view['isTree'] = self.isTree
|
|
132
|
-
return _view
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
valar/data/orm/detacher.py
DELETED
|
@@ -1,61 +0,0 @@
|
|
|
1
|
-
from django.db.models import (ManyToOneRel, ForeignKey, ManyToManyRel, ManyToManyField, OneToOneField, CharField,
|
|
2
|
-
OneToOneRel, IntegerField, BooleanField, FloatField, FileField, JSONField, DateField,
|
|
3
|
-
DateTimeField, TimeField, QuerySet)
|
|
4
|
-
|
|
5
|
-
from ..models import VModel
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
def detach_props(item, fields):
|
|
9
|
-
keys = [field['prop'] for field in fields if
|
|
10
|
-
field['domain'] in ['ManyToOneRel', 'ManyToManyField', 'ManyToManyRel', 'OneToOneRel', 'OneToOneField']]
|
|
11
|
-
_item = {}
|
|
12
|
-
for key in keys:
|
|
13
|
-
value = item.get(key)
|
|
14
|
-
if value is not None:
|
|
15
|
-
_item[key] = value
|
|
16
|
-
del item[key]
|
|
17
|
-
return _item
|
|
18
|
-
|
|
19
|
-
def save_detached(bean, _item, model_fields ):
|
|
20
|
-
for prop in _item:
|
|
21
|
-
value = _item[prop]
|
|
22
|
-
field = model_fields.get(prop)
|
|
23
|
-
clazz = type(field)
|
|
24
|
-
if clazz == ManyToManyField:
|
|
25
|
-
m2m = getattr(bean, prop)
|
|
26
|
-
m2m.clear()
|
|
27
|
-
m2m.add(*value)
|
|
28
|
-
elif clazz == ManyToOneRel:
|
|
29
|
-
getattr(bean, field.get_accessor_name()).clear()
|
|
30
|
-
remote_model: VModel = field.related_model
|
|
31
|
-
new_set: QuerySet = remote_model.objects.filter(id__in=value)
|
|
32
|
-
remote_field: ForeignKey = field.remote_field
|
|
33
|
-
k = remote_field.get_attname()
|
|
34
|
-
new_set.update(**{k: bean.id})
|
|
35
|
-
elif clazz == ManyToManyRel:
|
|
36
|
-
getattr(bean, field.get_accessor_name()).clear()
|
|
37
|
-
remote_model: VModel = field.related_model
|
|
38
|
-
remote_items: QuerySet = remote_model.objects.filter(id__in=value)
|
|
39
|
-
remote_field: ManyToManyField = field.remote_field
|
|
40
|
-
remote_field_prop = remote_field.get_attname()
|
|
41
|
-
for _bean in remote_items:
|
|
42
|
-
bean_set = getattr(_bean, remote_field_prop)
|
|
43
|
-
bean_set.add(bean)
|
|
44
|
-
elif clazz == OneToOneRel:
|
|
45
|
-
remote_model: VModel = field.related_model
|
|
46
|
-
remote_field: OneToOneField = field.remote_field
|
|
47
|
-
remote_field_prop = remote_field.get_attname()
|
|
48
|
-
_bean = remote_model.objects.get(id=value)
|
|
49
|
-
__bean = remote_model.objects.filter(**{remote_field_prop: bean.id}).first()
|
|
50
|
-
if __bean:
|
|
51
|
-
setattr(__bean, remote_field_prop, None)
|
|
52
|
-
__bean.save()
|
|
53
|
-
setattr(_bean, remote_field_prop, bean.id)
|
|
54
|
-
_bean.save()
|
|
55
|
-
elif clazz == OneToOneField:
|
|
56
|
-
__bean = field.model.objects.filter(**{prop: value}).first()
|
|
57
|
-
if __bean:
|
|
58
|
-
setattr(__bean, prop, None)
|
|
59
|
-
__bean.save()
|
|
60
|
-
setattr(bean, prop, value)
|
|
61
|
-
bean.save()
|
valar/data/orm/meta.py
DELETED
|
@@ -1,99 +0,0 @@
|
|
|
1
|
-
mf_common = ['prop','name']
|
|
2
|
-
|
|
3
|
-
meta_props = {
|
|
4
|
-
'data.Meta': {
|
|
5
|
-
'default': ('pick', ['entity','name']),
|
|
6
|
-
},
|
|
7
|
-
'data.MetaView': {
|
|
8
|
-
'list': ('pick', ['meta_id','code','view_name']),
|
|
9
|
-
},
|
|
10
|
-
'data.MetaField': {
|
|
11
|
-
'add': ('pick',['prop','domain','name']),
|
|
12
|
-
'tool': ('pick',[*mf_common,'domain','tool','refer','format']),
|
|
13
|
-
'rest': ('pick',[*mf_common,'not_null','allow_edit','allow_sort','allow_search','allow_download','allow_upload','allow_update']),
|
|
14
|
-
'table': ('pick',[*mf_common,'unit','column_width','fixed','align','edit_on_table','hide_on_table','header_color','cell_color']),
|
|
15
|
-
'form': ('pick',[*mf_common,'hide_on_form','hide_on_form_insert','hide_on_form_edit','hide_on_form_branch','hide_on_form_leaf','span']),
|
|
16
|
-
}
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
meta_defaults = {
|
|
21
|
-
'data.MetaFieldDomain':{
|
|
22
|
-
"default_id":{
|
|
23
|
-
"tool":"tree"
|
|
24
|
-
},
|
|
25
|
-
"search_id":{
|
|
26
|
-
"tool":"tree"
|
|
27
|
-
},
|
|
28
|
-
"tools":{
|
|
29
|
-
"tool":"tree",
|
|
30
|
-
"refer": {
|
|
31
|
-
"display":"code"
|
|
32
|
-
}
|
|
33
|
-
},
|
|
34
|
-
"align":{
|
|
35
|
-
"tool":"set",
|
|
36
|
-
"format":{
|
|
37
|
-
"set": {
|
|
38
|
-
'left':'左对齐',
|
|
39
|
-
'right':'右对齐',
|
|
40
|
-
'center':'剧中对齐',
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
},
|
|
45
|
-
'data.MetaField':{
|
|
46
|
-
"column_width":{
|
|
47
|
-
'unit':'px'
|
|
48
|
-
},
|
|
49
|
-
"fixed":{
|
|
50
|
-
"tool":"set",
|
|
51
|
-
"format":{
|
|
52
|
-
"set": {
|
|
53
|
-
'left':'左侧固定',
|
|
54
|
-
'right':'右侧固定',
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
},
|
|
58
|
-
"align":{
|
|
59
|
-
"tool":"set",
|
|
60
|
-
"format":{
|
|
61
|
-
"set": {
|
|
62
|
-
'left':'左对齐',
|
|
63
|
-
'right':'右对齐',
|
|
64
|
-
'center':'剧中对齐',
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
},
|
|
68
|
-
"prop":{
|
|
69
|
-
'allow_edit': False,
|
|
70
|
-
'column_width': 120
|
|
71
|
-
},
|
|
72
|
-
"domain":{
|
|
73
|
-
'allow_edit': False,
|
|
74
|
-
'column_width': 120,
|
|
75
|
-
},
|
|
76
|
-
"tool":{
|
|
77
|
-
'column_width': 100,
|
|
78
|
-
'tool': 'tree',
|
|
79
|
-
'refer': {
|
|
80
|
-
'entity':'data.MetaFieldTool',
|
|
81
|
-
'includes': {'metafielddomain__name':'$domain'},
|
|
82
|
-
'value': 'code'
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
},
|
|
86
|
-
"span":{
|
|
87
|
-
'column_width': 100,
|
|
88
|
-
"format": { "min": 0, "max": 24, "step": 1, "precision": 0, "step_strictly": True }
|
|
89
|
-
},
|
|
90
|
-
"refer":{
|
|
91
|
-
'allow_edit': False,
|
|
92
|
-
'column_width': 80
|
|
93
|
-
},
|
|
94
|
-
"format":{
|
|
95
|
-
'allow_edit': False,
|
|
96
|
-
'column_width': 80
|
|
97
|
-
},
|
|
98
|
-
}
|
|
99
|
-
}
|
valar/data/orm/meta_frame.py
DELETED
|
@@ -1,49 +0,0 @@
|
|
|
1
|
-
import os
|
|
2
|
-
|
|
3
|
-
from django.db import OperationalError
|
|
4
|
-
|
|
5
|
-
from ...data.models import MetaFieldDomain, MetaFieldTool
|
|
6
|
-
import pandas as pd
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
def load_meta_frame():
|
|
10
|
-
try:
|
|
11
|
-
MetaFieldTool.objects.all().delete()
|
|
12
|
-
MetaFieldDomain.objects.all().delete()
|
|
13
|
-
project_root = os.path.dirname(os.path.abspath(__file__))
|
|
14
|
-
file_path = os.path.join(project_root, 'meta_frame.xlsx')
|
|
15
|
-
array = pd.read_excel(file_path, sheet_name='tool').to_dict("records")
|
|
16
|
-
for row in array:
|
|
17
|
-
row['saved'] = True
|
|
18
|
-
MetaFieldTool.objects.create(**row)
|
|
19
|
-
array = pd.read_excel(file_path, sheet_name='domain').to_dict("records")
|
|
20
|
-
for row in array:
|
|
21
|
-
row['saved'] = True
|
|
22
|
-
tools = row.get('tools', '').split(';')
|
|
23
|
-
del row['tools']
|
|
24
|
-
item = MetaFieldDomain.objects.create(**row)
|
|
25
|
-
for tk in tools:
|
|
26
|
-
item.tools.add(tk)
|
|
27
|
-
except OperationalError as e:
|
|
28
|
-
print('initialization')
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
def convert_meta_fields(fields, entity):
|
|
32
|
-
values = MetaFieldDomain.objects.all().values('name', 'default__code', 'align')
|
|
33
|
-
mapping = {vs['name']: {
|
|
34
|
-
"tool": vs['default__code'],
|
|
35
|
-
"align": vs['align']
|
|
36
|
-
} for vs in values}
|
|
37
|
-
array = []
|
|
38
|
-
for field in fields:
|
|
39
|
-
node = mapping[field.domain]
|
|
40
|
-
_field = field.json
|
|
41
|
-
if field.tool == 'default':
|
|
42
|
-
_field['tool'] = node['tool']
|
|
43
|
-
_field['align'] = node['align']
|
|
44
|
-
_field['entity'] = entity
|
|
45
|
-
array.append(_field)
|
|
46
|
-
return array
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
valar/data/orm/meta_loader.py
DELETED
|
@@ -1,200 +0,0 @@
|
|
|
1
|
-
from django.db.models import (ManyToOneRel, ForeignKey, ManyToManyRel, ManyToManyField, OneToOneField, CharField,
|
|
2
|
-
OneToOneRel, IntegerField, BooleanField, FloatField, FileField, JSONField, DateField,
|
|
3
|
-
TextField,DateTimeField, TimeField)
|
|
4
|
-
|
|
5
|
-
from .meta_frame import convert_meta_fields
|
|
6
|
-
from ..orm.meta import meta_props, meta_defaults
|
|
7
|
-
from ..models import Meta, MetaView, VModel, MetaField, VTree
|
|
8
|
-
|
|
9
|
-
from deepmerge import always_merger
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
def __save_model(model):
|
|
13
|
-
model.save()
|
|
14
|
-
model.sort = model.id
|
|
15
|
-
model.saved = True
|
|
16
|
-
model.save()
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
def load_view(entity, code, name, fields):
|
|
21
|
-
meta = Meta.objects.filter(entity=entity).first()
|
|
22
|
-
if meta is None:
|
|
23
|
-
meta = Meta(entity=entity, name=name)
|
|
24
|
-
__save_model(meta)
|
|
25
|
-
view = MetaView.objects.filter(meta__entity=entity, code=code).first()
|
|
26
|
-
if view is None:
|
|
27
|
-
view = MetaView(meta=meta, code=code, view_name=code.upper())
|
|
28
|
-
__save_model(view)
|
|
29
|
-
if view.metafield_set.count() == 0:
|
|
30
|
-
t, p = meta_props.get(entity, {}).get(code,('omit',[]))
|
|
31
|
-
_fields = [f for f in fields if f['prop'] not in p] if t=='omit' else [f for f in fields if f['prop'] in p]
|
|
32
|
-
defaults = meta_defaults.get(entity,{})
|
|
33
|
-
for _field in _fields:
|
|
34
|
-
prop = _field['prop']
|
|
35
|
-
_field = always_merger.merge(_field,defaults.get(prop,{}))
|
|
36
|
-
_fields.reverse()
|
|
37
|
-
for f in _fields:
|
|
38
|
-
f['view'] = view
|
|
39
|
-
field = MetaField.objects.create(**f)
|
|
40
|
-
__save_model(field)
|
|
41
|
-
return view
|
|
42
|
-
|
|
43
|
-
def load_meta(view):
|
|
44
|
-
_view = view.full
|
|
45
|
-
_meta = _view['meta']
|
|
46
|
-
fields = view.metafield_set.all().order_by('-sort')
|
|
47
|
-
_fields = convert_meta_fields(fields,_meta['entity'])
|
|
48
|
-
# _fields = [f.json for f in fields]
|
|
49
|
-
clear_item(_view, 'meta_id', 'metafield', 'metafield_set', 'meta')
|
|
50
|
-
_view['meta_name'] = _meta['name']
|
|
51
|
-
_view['entity'] = _meta['entity']
|
|
52
|
-
_view['fields'] = {}
|
|
53
|
-
for _field in _fields:
|
|
54
|
-
clear_item(_field, 'view_id')
|
|
55
|
-
prop = _field['prop']
|
|
56
|
-
_view['fields'][prop] = _field
|
|
57
|
-
return _view
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
def clear_item(item, *keys):
|
|
62
|
-
del item['saved']
|
|
63
|
-
del item['sort']
|
|
64
|
-
del item['create_time']
|
|
65
|
-
del item['modify_time']
|
|
66
|
-
for key in keys:
|
|
67
|
-
del item[key]
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
def get_default_refer():
|
|
71
|
-
return {
|
|
72
|
-
"entity": None,
|
|
73
|
-
"value": "name", "label": 'name', "display": "id",
|
|
74
|
-
"strict": False, "remote": False, "multiple": False,
|
|
75
|
-
"includes": {}, "excludes": {}, "root": 0, "isTree": False
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
def get_refer(model, multiple = False):
|
|
80
|
-
module, name = model.__module__, model.__name__
|
|
81
|
-
entity = '%s.%s' % (module.replace('.models', '').split('.')[-1], name)
|
|
82
|
-
return {
|
|
83
|
-
"entity": entity,
|
|
84
|
-
"value": "id", "label": 'name', "display": "id",
|
|
85
|
-
"strict": False, "remote": False, "multiple": multiple,
|
|
86
|
-
"includes": {}, "excludes": {}, "root": 0, "isTree": issubclass(model, VTree)
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
def get_align(clazz):
|
|
90
|
-
if clazz in [FloatField, IntegerField]: #, ManyToManyRel, ManyToManyField, ManyToOneRel
|
|
91
|
-
return 'right'
|
|
92
|
-
elif clazz in [BooleanField,FileField,JSONField,DateField,DateTimeField,TimeField]:
|
|
93
|
-
return 'center'
|
|
94
|
-
return 'left'
|
|
95
|
-
|
|
96
|
-
def get_default_format():
|
|
97
|
-
return {
|
|
98
|
-
# 文本
|
|
99
|
-
"maxlength": 0,
|
|
100
|
-
"type": 'text',
|
|
101
|
-
|
|
102
|
-
# 数值
|
|
103
|
-
"min": None,
|
|
104
|
-
"max": None,
|
|
105
|
-
"step": 1,
|
|
106
|
-
"precision": None,
|
|
107
|
-
"step_strictly": False,
|
|
108
|
-
|
|
109
|
-
# 日期
|
|
110
|
-
"frequency": "date",
|
|
111
|
-
|
|
112
|
-
# 文件
|
|
113
|
-
"maximum": 5,
|
|
114
|
-
"width": 800,
|
|
115
|
-
"height": 0,
|
|
116
|
-
"accept": [],
|
|
117
|
-
"file_name_field":None,
|
|
118
|
-
"locked": False,
|
|
119
|
-
|
|
120
|
-
#集合
|
|
121
|
-
"set": {}
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
def get_format(field):
|
|
127
|
-
clazz = type(field)
|
|
128
|
-
_format = get_default_format()
|
|
129
|
-
if clazz == CharField:
|
|
130
|
-
_format['maxlength'] = field.max_length
|
|
131
|
-
if clazz == TextField:
|
|
132
|
-
_format['type'] = "textarea"
|
|
133
|
-
elif clazz == DateTimeField:
|
|
134
|
-
_format['frequency'] = "datetime"
|
|
135
|
-
elif clazz == IntegerField:
|
|
136
|
-
_format['precision'] = 0
|
|
137
|
-
_format['step_strictly'] = True
|
|
138
|
-
elif clazz == FileField:
|
|
139
|
-
pass
|
|
140
|
-
return _format
|
|
141
|
-
|
|
142
|
-
def get_field_column_width(field,clazz):
|
|
143
|
-
if clazz in [BooleanField, FileField, JSONField]:
|
|
144
|
-
return 100
|
|
145
|
-
elif clazz in [ DateField, DateTimeField, TimeField]:
|
|
146
|
-
return 120
|
|
147
|
-
return 0
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
def load_meta_field(field, isTree):
|
|
152
|
-
clazz = type(field)
|
|
153
|
-
if clazz in [ManyToOneRel, ManyToManyField, ManyToManyRel]:
|
|
154
|
-
prop = field.name
|
|
155
|
-
domain = clazz.__name__
|
|
156
|
-
model: VModel= field.related_model
|
|
157
|
-
label = model._meta.verbose_name
|
|
158
|
-
refer = get_refer(model, True)
|
|
159
|
-
elif clazz in [ForeignKey]:
|
|
160
|
-
prop = field.name + "_id"
|
|
161
|
-
domain = field.get_internal_type()
|
|
162
|
-
model: VModel = field.related_model
|
|
163
|
-
label = field.verbose_name
|
|
164
|
-
refer = get_refer(model)
|
|
165
|
-
elif clazz in [OneToOneRel, OneToOneField]:
|
|
166
|
-
prop = field.name + "_id"
|
|
167
|
-
domain = clazz.__name__
|
|
168
|
-
model: VModel = field.related_model
|
|
169
|
-
label = model._meta.verbose_name
|
|
170
|
-
refer = get_refer(model)
|
|
171
|
-
else:
|
|
172
|
-
prop = field.name
|
|
173
|
-
domain = field.get_internal_type()
|
|
174
|
-
label = field.verbose_name
|
|
175
|
-
refer = get_default_refer()
|
|
176
|
-
not_null = not field.null
|
|
177
|
-
align = get_align(clazz)
|
|
178
|
-
_format = get_format(field)
|
|
179
|
-
column_width = get_field_column_width(field,clazz)
|
|
180
|
-
_field = {
|
|
181
|
-
"prop": prop,
|
|
182
|
-
"label":label,
|
|
183
|
-
"name":label,
|
|
184
|
-
"domain":domain,
|
|
185
|
-
"refer":refer,
|
|
186
|
-
"format":_format,
|
|
187
|
-
"not_null":not_null,
|
|
188
|
-
"align":align,
|
|
189
|
-
"column_width":column_width
|
|
190
|
-
}
|
|
191
|
-
|
|
192
|
-
if isTree:
|
|
193
|
-
if prop in ['pid','isLeaf']:
|
|
194
|
-
_field['hide_on_table'] = True
|
|
195
|
-
_field['hide_on_form'] = True
|
|
196
|
-
_field['hide_on_form_branch'] = True
|
|
197
|
-
_field['hide_on_form_leaf'] = True
|
|
198
|
-
elif prop in ['icon']:
|
|
199
|
-
_field['tool'] = 'icon'
|
|
200
|
-
return _field
|