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
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import pymongo
|
|
2
|
+
from django.conf import settings
|
|
3
|
+
|
|
4
|
+
from .model_mon import MonModel
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class MonEngine:
|
|
8
|
+
|
|
9
|
+
def __init__(self):
|
|
10
|
+
uri = f'mongodb://localhost:27017/'
|
|
11
|
+
mongo = settings.MONGO
|
|
12
|
+
if mongo:
|
|
13
|
+
param = ['host', 'port', 'username', 'password']
|
|
14
|
+
host, port, username, password = [mongo.get(p) for p in param]
|
|
15
|
+
uri = f'mongodb://{username}:{password}@{host}:{port}/'
|
|
16
|
+
|
|
17
|
+
client = pymongo.MongoClient(uri, **{
|
|
18
|
+
'maxPoolSize': 10,
|
|
19
|
+
'minPoolSize': 0,
|
|
20
|
+
'maxIdleTimeMS': 10000,
|
|
21
|
+
'connectTimeoutMS': 10000,
|
|
22
|
+
'socketTimeoutMS': 10000,
|
|
23
|
+
'serverSelectionTimeoutMS': 10000,
|
|
24
|
+
})
|
|
25
|
+
database = client[settings.BASE_APP]
|
|
26
|
+
self.uri = uri
|
|
27
|
+
self.client = client
|
|
28
|
+
self.database = database
|
|
29
|
+
|
|
30
|
+
def get_mapping(self):
|
|
31
|
+
return {col['name']: self.database[col['name']] for col in self.database.list_collections()}
|
|
32
|
+
|
|
33
|
+
def get_model(self,entity)->MonModel:
|
|
34
|
+
return MonModel(self.database, entity)
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
from django.apps import apps
|
|
2
|
+
|
|
3
|
+
from .model_orm import OrmModel
|
|
4
|
+
from ..valar_models import VModel
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class OrmEngine:
|
|
8
|
+
|
|
9
|
+
def __init__(self):
|
|
10
|
+
mapping = {}
|
|
11
|
+
for model in apps.get_models():
|
|
12
|
+
if issubclass(model, VModel):
|
|
13
|
+
path, name = model.__module__, model.__name__
|
|
14
|
+
prefix = 'src.valar.' if path.startswith('src') else 'valar.'
|
|
15
|
+
app = path.replace('.models', '').replace(prefix, '')
|
|
16
|
+
entity = '%s.%s' % (app, name)
|
|
17
|
+
mapping[entity] = model
|
|
18
|
+
self.mapping = mapping
|
|
19
|
+
|
|
20
|
+
def get_mapping(self)->dict:
|
|
21
|
+
return self.mapping
|
|
22
|
+
|
|
23
|
+
def get_model(self,entity)->OrmModel:
|
|
24
|
+
mod = self.mapping.get(entity)
|
|
25
|
+
return OrmModel(mod, entity)
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
from bson import ObjectId
|
|
2
|
+
from bson.errors import InvalidId
|
|
3
|
+
from pymongo.synchronous.collection import Collection
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class MonModel:
|
|
7
|
+
|
|
8
|
+
def __init__(self, database, entity):
|
|
9
|
+
self.entity = entity
|
|
10
|
+
self.name = entity.replace('.', '_')
|
|
11
|
+
self.manager: Collection = database[self.name]
|
|
12
|
+
|
|
13
|
+
@staticmethod
|
|
14
|
+
def object_id(_id):
|
|
15
|
+
try:
|
|
16
|
+
return ObjectId(_id)
|
|
17
|
+
except(InvalidId, TypeError):
|
|
18
|
+
return None
|
|
19
|
+
|
|
20
|
+
def detach_item(self, item):
|
|
21
|
+
_id = item.get('id')
|
|
22
|
+
if _id:
|
|
23
|
+
del item['id']
|
|
24
|
+
return self.object_id(_id), item
|
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
from deepmerge import always_merger
|
|
2
|
+
from django.db.models import ManyToOneRel, ForeignKey, ManyToManyRel, ManyToManyField, OneToOneField, OneToOneRel
|
|
3
|
+
from django.db.models import QuerySet
|
|
4
|
+
from django.db.models import Manager
|
|
5
|
+
from django.db.models.fields.files import FieldFile
|
|
6
|
+
from django.forms import FileField
|
|
7
|
+
|
|
8
|
+
from .engine_minio import MinioEngine
|
|
9
|
+
from .utils_orm import OrmUtils
|
|
10
|
+
from ..meta.defaults.field_keys_default import meta_field_key_defaults
|
|
11
|
+
from ..meta.defaults.field_values_default import meta_field_value_defaults
|
|
12
|
+
from ..meta.field_orm import OrmField
|
|
13
|
+
from ..meta.init_meta_frame import init_meta_frame
|
|
14
|
+
from ..valar_models import VModel, VTree
|
|
15
|
+
from ...data.models import MetaFieldDomain
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class OrmModel:
|
|
19
|
+
|
|
20
|
+
def __init__(self, mod, entity):
|
|
21
|
+
self.entity = entity
|
|
22
|
+
self.model = mod
|
|
23
|
+
meta = getattr(mod, '_meta')
|
|
24
|
+
self.name = meta.verbose_name
|
|
25
|
+
self.is_tree = issubclass(mod, VTree)
|
|
26
|
+
self.manager: Manager = mod.objects
|
|
27
|
+
fields = meta.get_fields()
|
|
28
|
+
mapping = {}
|
|
29
|
+
for f in fields:
|
|
30
|
+
field = OrmField(entity, f, self.is_tree)
|
|
31
|
+
mapping[field.prop] = field
|
|
32
|
+
self.mapping = mapping
|
|
33
|
+
self.minio = MinioEngine()
|
|
34
|
+
self.bucket_name = self.minio.get_bucket_name(entity)
|
|
35
|
+
|
|
36
|
+
@staticmethod
|
|
37
|
+
def object_id(_id):
|
|
38
|
+
return _id if isinstance(_id, int) and _id else None
|
|
39
|
+
|
|
40
|
+
def props(self, domain=None):
|
|
41
|
+
array = []
|
|
42
|
+
for prop in self.mapping:
|
|
43
|
+
field: OrmField = self.mapping[prop]
|
|
44
|
+
if field.domain == domain or domain is None:
|
|
45
|
+
array.append(prop)
|
|
46
|
+
return array
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
def meta_frame(self):
|
|
50
|
+
query_set = MetaFieldDomain.objects.all()
|
|
51
|
+
if query_set.count() == 0:
|
|
52
|
+
query_set = init_meta_frame()
|
|
53
|
+
values = query_set.values('name', 'default__code', 'align')
|
|
54
|
+
return {
|
|
55
|
+
vs['name']: {
|
|
56
|
+
"tool": vs['default__code'],
|
|
57
|
+
"align": vs['align'],
|
|
58
|
+
}
|
|
59
|
+
for vs in values
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
def initial_fields(self, code):
|
|
66
|
+
props = self.props()
|
|
67
|
+
default_keys = meta_field_key_defaults.get(self.entity,{})
|
|
68
|
+
method, array = default_keys.get(code, ('omit',[]))
|
|
69
|
+
def fun(prop): return prop not in array if method == 'omit' else prop in array
|
|
70
|
+
props = [prop for prop in props if fun(prop)]
|
|
71
|
+
|
|
72
|
+
default_values = meta_field_value_defaults.get(self.entity, {})
|
|
73
|
+
init_values = default_values.get('__init__', {})
|
|
74
|
+
code_values = default_values.get(code, {})
|
|
75
|
+
default_fields = always_merger.merge(init_values, code_values)
|
|
76
|
+
|
|
77
|
+
meta_frame = self.meta_frame()
|
|
78
|
+
fields = []
|
|
79
|
+
for prop in props:
|
|
80
|
+
field = self.get_field(prop)
|
|
81
|
+
field_json = field.json()
|
|
82
|
+
frame = meta_frame.get(field.domain, {})
|
|
83
|
+
field_json.update(frame)
|
|
84
|
+
default_field = default_fields.get(prop, {})
|
|
85
|
+
always_merger.merge(field_json, default_field)
|
|
86
|
+
fields.append(field_json)
|
|
87
|
+
|
|
88
|
+
fields.reverse()
|
|
89
|
+
return fields
|
|
90
|
+
|
|
91
|
+
def get_field(self, prop)->OrmField:
|
|
92
|
+
return self.mapping[prop]
|
|
93
|
+
|
|
94
|
+
def detach_item(self, item):
|
|
95
|
+
_id = item.get('id')
|
|
96
|
+
if _id:
|
|
97
|
+
del item['id']
|
|
98
|
+
simple_item = {}
|
|
99
|
+
complex_item = {}
|
|
100
|
+
for prop in item:
|
|
101
|
+
field = self.get_field(prop)
|
|
102
|
+
value = item.get(prop)
|
|
103
|
+
if field.domain in ['ManyToOneRel', 'ManyToManyField', 'ManyToManyRel', 'OneToOneRel', 'OneToOneField','FileField']:
|
|
104
|
+
complex_item[prop] = value
|
|
105
|
+
else:
|
|
106
|
+
simple_item[prop] = value
|
|
107
|
+
return self.object_id(_id), simple_item, complex_item
|
|
108
|
+
|
|
109
|
+
def get_file_paths(self, query_set: QuerySet):
|
|
110
|
+
props = self.props('FileField')
|
|
111
|
+
items = query_set.values(*props)
|
|
112
|
+
array = []
|
|
113
|
+
for item in items:
|
|
114
|
+
array += [i for i in item.values() if i]
|
|
115
|
+
return array
|
|
116
|
+
|
|
117
|
+
def remove_files(self, query_set: QuerySet):
|
|
118
|
+
paths = self.get_file_paths(query_set)
|
|
119
|
+
for path in paths:
|
|
120
|
+
self.minio.remove_path(path)
|
|
121
|
+
|
|
122
|
+
def save_complex_field(self, complex_item, bean):
|
|
123
|
+
for prop in complex_item:
|
|
124
|
+
value = complex_item[prop]
|
|
125
|
+
field = self.get_field(prop).model_field
|
|
126
|
+
clazz = type(field)
|
|
127
|
+
if clazz == ManyToManyField:
|
|
128
|
+
m2m = getattr(bean, prop)
|
|
129
|
+
m2m.clear()
|
|
130
|
+
m2m.add(*value)
|
|
131
|
+
elif clazz == ManyToOneRel:
|
|
132
|
+
getattr(bean, field.get_accessor_name()).clear()
|
|
133
|
+
remote_model: VModel = field.related_model
|
|
134
|
+
new_set: QuerySet = remote_model.objects.filter(id__in=value)
|
|
135
|
+
remote_field: ForeignKey = field.remote_field
|
|
136
|
+
k = remote_field.get_attname()
|
|
137
|
+
new_set.update(**{k: bean.id})
|
|
138
|
+
elif clazz == ManyToManyRel:
|
|
139
|
+
getattr(bean, field.get_accessor_name()).clear()
|
|
140
|
+
remote_model: VModel = field.related_model
|
|
141
|
+
remote_items: QuerySet = remote_model.objects.filter(id__in=value)
|
|
142
|
+
remote_field: ManyToManyField = field.remote_field
|
|
143
|
+
remote_field_prop = remote_field.get_attname()
|
|
144
|
+
for _bean in remote_items:
|
|
145
|
+
bean_set = getattr(_bean, remote_field_prop)
|
|
146
|
+
bean_set.add(bean)
|
|
147
|
+
elif clazz == OneToOneRel:
|
|
148
|
+
remote_model: VModel = field.related_model
|
|
149
|
+
remote_field: OneToOneField = field.remote_field
|
|
150
|
+
remote_field_prop = remote_field.get_attname()
|
|
151
|
+
_bean = remote_model.objects.get(id=value)
|
|
152
|
+
__bean = remote_model.objects.filter(**{remote_field_prop: bean.id}).first()
|
|
153
|
+
if __bean:
|
|
154
|
+
setattr(__bean, remote_field_prop, None)
|
|
155
|
+
__bean.save()
|
|
156
|
+
setattr(_bean, remote_field_prop, bean.id)
|
|
157
|
+
_bean.save()
|
|
158
|
+
elif clazz == OneToOneField:
|
|
159
|
+
__bean = field.model.objects.filter(**{prop: value}).first()
|
|
160
|
+
if __bean:
|
|
161
|
+
setattr(__bean, prop, None)
|
|
162
|
+
__bean.save()
|
|
163
|
+
setattr(bean, prop, value)
|
|
164
|
+
elif clazz == FileField:
|
|
165
|
+
file_name, _bytes = value
|
|
166
|
+
field_file: FieldFile = getattr(bean, prop)
|
|
167
|
+
if field_file:
|
|
168
|
+
path = field_file.name
|
|
169
|
+
self.minio.remove_path(path)
|
|
170
|
+
object_name = self.minio.get_object_name(bean.id, prop, file_name)
|
|
171
|
+
path = self.minio.upload(self.bucket_name, object_name, _bytes) if _bytes else None
|
|
172
|
+
setattr(bean, prop, path)
|
|
173
|
+
|
|
174
|
+
|
|
175
|
+
|
|
176
|
+
|
|
177
|
+
def to_dict(self, query_set: QuerySet, code=None):
|
|
178
|
+
# query_set = query_set.filter(saved=True)
|
|
179
|
+
utils = OrmUtils()
|
|
180
|
+
orm_fields = self.mapping.values()
|
|
181
|
+
# 简单字段取值
|
|
182
|
+
simple_props = [field.prop for field in orm_fields if field.domain not in utils.referred_domains]
|
|
183
|
+
custom_props = utils.custom_props(self.entity, code)
|
|
184
|
+
results = list(query_set.values(*[*simple_props, *custom_props]))
|
|
185
|
+
utils.date_values(orm_fields, results)
|
|
186
|
+
# 关系型字段取值
|
|
187
|
+
mapping = { row['id']: row for row in results}
|
|
188
|
+
referred_fields = [field for field in orm_fields if field.domain in utils.referred_domains]
|
|
189
|
+
for field in referred_fields:
|
|
190
|
+
utils.linkage(field, query_set, mapping)
|
|
191
|
+
return results
|
|
192
|
+
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
|
|
2
|
+
def __translate_finder__(conditions):
|
|
3
|
+
return {}
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class MonQuery:
|
|
7
|
+
|
|
8
|
+
def __init__(self, conditions: list, orders = None):
|
|
9
|
+
self.orders = orders or {'sort': -1}
|
|
10
|
+
conditions = conditions if len(conditions) else [{'includes':{},'excludes':{}}]
|
|
11
|
+
self.finder = __translate_finder__(conditions)
|
|
12
|
+
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
from django.db.models import Q
|
|
2
|
+
from functools import reduce
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
def __fun__(x, y): return x | y
|
|
7
|
+
def __translate_orders__(orders):
|
|
8
|
+
array = []
|
|
9
|
+
for key in orders:
|
|
10
|
+
value = orders.get(key)
|
|
11
|
+
prefix = '-' if value == -1 else ''
|
|
12
|
+
array.append(f'{prefix}{key}')
|
|
13
|
+
return array
|
|
14
|
+
def __translate_condition__(conditions, _type):
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
return reduce(__fun__, [Q(**cond[_type]) for cond in conditions])
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
class OrmQuery:
|
|
22
|
+
|
|
23
|
+
def __init__(self, conditions: list, orders = None):
|
|
24
|
+
self.orders = __translate_orders__(orders or {'sort': -1})
|
|
25
|
+
conditions = conditions if len(conditions) else [{'includes':{},'excludes':{}}]
|
|
26
|
+
self.includes = __translate_condition__(conditions,'includes')
|
|
27
|
+
self.excludes = __translate_condition__(conditions, 'excludes')
|
|
28
|
+
|
|
29
|
+
@staticmethod
|
|
30
|
+
def is_empty(conditions):
|
|
31
|
+
if conditions and len(conditions):
|
|
32
|
+
temp = {}
|
|
33
|
+
for cond in conditions:
|
|
34
|
+
temp.update(cond)
|
|
35
|
+
return len(temp.keys()) >0
|
|
36
|
+
else:
|
|
37
|
+
return True
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
from ..valar_models import VModel
|
|
2
|
+
from ...core.meta.field_orm import OrmField
|
|
3
|
+
from ...data.models import MetaField
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class OrmUtils:
|
|
7
|
+
def __init__(self):
|
|
8
|
+
self.multiple_domains = ['ManyToOneRel', 'ManyToManyField', 'ManyToManyRel']
|
|
9
|
+
self.referred_domains = [*self.multiple_domains, 'OneToOneRel', 'OneToOneField', 'ForeignKey']
|
|
10
|
+
self.omit_field_props = ['create_time', 'modify_time', 'saved', 'sort']
|
|
11
|
+
self.data_props_formatting = {'DateField': '%Y-%m-%d', 'DateTimeField': '%Y-%m-%d %H:%M:%S', 'TimeField': '%H:%M:%S'}
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
@staticmethod
|
|
15
|
+
def json(bean: VModel):
|
|
16
|
+
pass
|
|
17
|
+
|
|
18
|
+
@staticmethod
|
|
19
|
+
def custom_props(entity, code='default'):
|
|
20
|
+
field_set = MetaField.objects.filter(view__code=code, view__meta__entity=entity, domain='Custom').values('prop')
|
|
21
|
+
return [item['prop'] for item in field_set if item['prop']]
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def linkage(self, field, query_set, mapping):
|
|
25
|
+
model_field = field.model_field
|
|
26
|
+
prop = model_field.name
|
|
27
|
+
multiple = field.domain in self.multiple_domains
|
|
28
|
+
|
|
29
|
+
# 获取级联关系的键索引
|
|
30
|
+
ref_prop = f'{prop}__id'
|
|
31
|
+
edges = query_set.exclude(**{f'{ref_prop}__isnull': True}).values('id', ref_prop)
|
|
32
|
+
if multiple:
|
|
33
|
+
related_primary_keys = set()
|
|
34
|
+
results_mapping = {}
|
|
35
|
+
for edge in edges:
|
|
36
|
+
_id, rid = edge['id'], edge[ref_prop]
|
|
37
|
+
related_primary_keys.add(rid)
|
|
38
|
+
array = results_mapping.get(_id, [])
|
|
39
|
+
array.append(rid)
|
|
40
|
+
results_mapping[_id] = array
|
|
41
|
+
else:
|
|
42
|
+
results_mapping = {row['id']: row[ref_prop] for row in edges if row[ref_prop]}
|
|
43
|
+
related_primary_keys = set(results_mapping.values())
|
|
44
|
+
|
|
45
|
+
# 获取级联关系从属方的数据
|
|
46
|
+
related_model = model_field.related_model
|
|
47
|
+
related_fields = related_model._meta.get_fields()
|
|
48
|
+
related_props = self.__get_related_props__(related_fields)
|
|
49
|
+
related_values = list(related_model.objects.filter(id__in=related_primary_keys).values(*related_props))
|
|
50
|
+
self.date_values(related_fields, related_values)
|
|
51
|
+
related_mapping = {item['id']: item for item in related_values}
|
|
52
|
+
|
|
53
|
+
# 将从属方的数据绑定在主数据上
|
|
54
|
+
for _id in mapping:
|
|
55
|
+
row = mapping[_id]
|
|
56
|
+
if multiple:
|
|
57
|
+
keys = results_mapping.get(_id, [])
|
|
58
|
+
items = [related_mapping[pid] for pid in keys]
|
|
59
|
+
row[prop] = keys
|
|
60
|
+
row[f'{prop}_set'] = items
|
|
61
|
+
else:
|
|
62
|
+
key = results_mapping.get(_id)
|
|
63
|
+
item = related_mapping.get(key) if key else None
|
|
64
|
+
row[prop] = item
|
|
65
|
+
row[f'{prop}_id'] = key
|
|
66
|
+
|
|
67
|
+
def __get_related_props__(self,fields):
|
|
68
|
+
def fun(field): return type(field).__name__ not in self.referred_domains and field.name not in self.omit_field_props
|
|
69
|
+
return [field.name for field in fields if fun(field)]
|
|
70
|
+
|
|
71
|
+
def date_values(self, fields, values):
|
|
72
|
+
date_props_mapping = {}
|
|
73
|
+
for field in fields:
|
|
74
|
+
if isinstance(field, OrmField):
|
|
75
|
+
prop = field.prop
|
|
76
|
+
domain = field.domain
|
|
77
|
+
else:
|
|
78
|
+
prop = field.name
|
|
79
|
+
domain = type(field).__name__
|
|
80
|
+
if domain in self.data_props_formatting.keys():
|
|
81
|
+
date_props_mapping[prop] = self.data_props_formatting[domain]
|
|
82
|
+
for row in values:
|
|
83
|
+
for prop, formating in date_props_mapping.items():
|
|
84
|
+
if row.get(prop):
|
|
85
|
+
row[prop] = row[prop].strftime(formating)
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
from abc import ABC, abstractmethod
|
|
2
|
+
|
|
3
|
+
class AbstractDao(ABC):
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
@abstractmethod
|
|
7
|
+
def get_model(self):
|
|
8
|
+
pass
|
|
9
|
+
|
|
10
|
+
@abstractmethod
|
|
11
|
+
def save_one(self, item):
|
|
12
|
+
pass
|
|
13
|
+
|
|
14
|
+
@abstractmethod
|
|
15
|
+
def delete_one(self, _id):
|
|
16
|
+
pass
|
|
17
|
+
|
|
18
|
+
@abstractmethod
|
|
19
|
+
def find_one(self, _id):
|
|
20
|
+
pass
|
|
21
|
+
|
|
22
|
+
@abstractmethod
|
|
23
|
+
def find(self, conditions=None, orders=None, size=0, page=1):
|
|
24
|
+
pass
|
|
25
|
+
|
|
26
|
+
@abstractmethod
|
|
27
|
+
def update(self, template, conditions):
|
|
28
|
+
pass
|
|
29
|
+
|
|
30
|
+
@abstractmethod
|
|
31
|
+
def delete(self, conditions):
|
|
32
|
+
pass
|
|
33
|
+
|
|
34
|
+
@abstractmethod
|
|
35
|
+
def transform(self, o, code=None):
|
|
36
|
+
pass
|
|
37
|
+
|
|
38
|
+
@abstractmethod
|
|
39
|
+
def tree(self, root, conditions=None):
|
|
40
|
+
pass
|
|
41
|
+
|
|
42
|
+
def search(self, includes=None, excludes=None, orders=None):
|
|
43
|
+
conditions = [{
|
|
44
|
+
"includes": includes or {},
|
|
45
|
+
"excludes": excludes or {}
|
|
46
|
+
}]
|
|
47
|
+
query_set, _ = self.find(conditions, orders)
|
|
48
|
+
return query_set
|
|
49
|
+
|
|
50
|
+
# @abstractmethod
|
|
51
|
+
# def values(self, props, conditions, orders=None):
|
|
52
|
+
# pass
|
|
53
|
+
#
|
|
54
|
+
# @abstractmethod
|
|
55
|
+
# def group(self, props, conditions, orders=None):
|
|
56
|
+
# pass
|
|
57
|
+
#
|
|
58
|
+
# @abstractmethod
|
|
59
|
+
# def count(self, props, conditions):
|
|
60
|
+
# pass
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
|
|
File without changes
|
|
File without changes
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
__mf_common__ = ['prop','name']
|
|
2
|
+
|
|
3
|
+
meta_field_key_defaults = {
|
|
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
|
+
}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
|
|
2
|
+
meta_field_value_defaults = {
|
|
3
|
+
'data.MetaFieldDomain':{
|
|
4
|
+
"__init__":{
|
|
5
|
+
"default_id":{
|
|
6
|
+
"tool":"tree"
|
|
7
|
+
},
|
|
8
|
+
"search_id":{
|
|
9
|
+
"tool":"tree"
|
|
10
|
+
},
|
|
11
|
+
"tools":{
|
|
12
|
+
"tool":"tree",
|
|
13
|
+
"refer": {
|
|
14
|
+
"display":"code"
|
|
15
|
+
}
|
|
16
|
+
},
|
|
17
|
+
"align":{
|
|
18
|
+
"tool":"set",
|
|
19
|
+
"format":{
|
|
20
|
+
"set": {
|
|
21
|
+
'left':'左对齐',
|
|
22
|
+
'right':'右对齐',
|
|
23
|
+
'center':'剧中对齐',
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
},
|
|
29
|
+
'data.MetaField':{
|
|
30
|
+
"__init__":{
|
|
31
|
+
"column_width":{
|
|
32
|
+
'unit':'px'
|
|
33
|
+
},
|
|
34
|
+
"fixed":{
|
|
35
|
+
"tool":"set",
|
|
36
|
+
"format":{
|
|
37
|
+
"set": {
|
|
38
|
+
'left':'左侧固定',
|
|
39
|
+
'right':'右侧固定',
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
},
|
|
43
|
+
"align":{
|
|
44
|
+
"tool":"set",
|
|
45
|
+
"format":{
|
|
46
|
+
"set": {
|
|
47
|
+
'left':'左对齐',
|
|
48
|
+
'right':'右对齐',
|
|
49
|
+
'center':'剧中对齐',
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
},
|
|
53
|
+
"prop":{
|
|
54
|
+
'allow_edit': False,
|
|
55
|
+
'column_width': 120
|
|
56
|
+
},
|
|
57
|
+
"domain":{
|
|
58
|
+
'allow_edit': False,
|
|
59
|
+
'column_width': 120,
|
|
60
|
+
},
|
|
61
|
+
"tool":{
|
|
62
|
+
'column_width': 100,
|
|
63
|
+
'tool': 'tree',
|
|
64
|
+
'refer': {
|
|
65
|
+
'entity':'data.MetaFieldTool',
|
|
66
|
+
'includes': {'metafielddomain__name':'$domain'},
|
|
67
|
+
'value': 'code'
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
},
|
|
71
|
+
"span":{
|
|
72
|
+
'column_width': 100,
|
|
73
|
+
"format": { "min": 0, "max": 24, "step": 1, "precision": 0, "step_strictly": True }
|
|
74
|
+
},
|
|
75
|
+
"refer":{
|
|
76
|
+
'allow_edit': False,
|
|
77
|
+
'column_width': 80
|
|
78
|
+
},
|
|
79
|
+
"format":{
|
|
80
|
+
'allow_edit': False,
|
|
81
|
+
'column_width': 80
|
|
82
|
+
},
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
}
|