valar 0.0.12__py3-none-any.whl → 0.0.14__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 +7 -6
- valar/channels/__init__.py +18 -10
- valar/channels/utils.py +43 -0
- valar/channels/views.py +4 -37
- valar/data/handlers.py +28 -0
- valar/data/migrations/0001_initial.py +210 -0
- valar/data/models.py +223 -0
- valar/data/mon/__init__.py +84 -0
- valar/data/orm/__init__.py +87 -0
- valar/data/orm/detacher.py +61 -0
- valar/data/orm/meta.py +24 -0
- valar/data/orm/meta_loader.py +135 -0
- valar/data/orm/values.py +93 -0
- valar/data/query.py +48 -0
- valar/data/urls.py +15 -0
- valar/data/utils.py +70 -0
- valar/data/views.py +76 -0
- {valar-0.0.12.dist-info → valar-0.0.14.dist-info}/METADATA +7 -3
- valar-0.0.14.dist-info/RECORD +24 -0
- {valar-0.0.12.dist-info → valar-0.0.14.dist-info}/WHEEL +1 -1
- valar/dao/migrations/0001_initial.py +0 -22
- valar/dao/models.py +0 -7
- valar/dao/views.py +0 -3
- valar-0.0.12.dist-info/RECORD +0 -13
- /valar/{dao → data}/__init__.py +0 -0
- /valar/{dao → data}/migrations/__init__.py +0 -0
- {valar-0.0.12.dist-info → valar-0.0.14.dist-info/licenses}/LICENSE +0 -0
- {valar-0.0.12.dist-info → valar-0.0.14.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
from bson import ObjectId
|
|
2
|
+
from django.db.models import QuerySet
|
|
3
|
+
from pymongo.results import InsertOneResult, UpdateResult
|
|
4
|
+
|
|
5
|
+
from django.conf import settings
|
|
6
|
+
import pymongo
|
|
7
|
+
|
|
8
|
+
from ..query import Query
|
|
9
|
+
|
|
10
|
+
try:
|
|
11
|
+
MONGO = settings.MONGO_SETTINGS
|
|
12
|
+
except AttributeError:
|
|
13
|
+
MONGO = {
|
|
14
|
+
'host': 'localhost',
|
|
15
|
+
'port': 27017,
|
|
16
|
+
}
|
|
17
|
+
host, port, username, password = MONGO.get('host'), MONGO.get('port'), MONGO.get('username'), MONGO.get('password')
|
|
18
|
+
|
|
19
|
+
if username and password:
|
|
20
|
+
uri = f'mongodb://{username}:{password}@{host}:{port}/'
|
|
21
|
+
else:
|
|
22
|
+
uri = f'mongodb://{host}:{port}/'
|
|
23
|
+
mongo_params = {
|
|
24
|
+
'maxPoolSize': 10,
|
|
25
|
+
'minPoolSize': 0,
|
|
26
|
+
'maxIdleTimeMS': 10000,
|
|
27
|
+
'connectTimeoutMS': 10000,
|
|
28
|
+
'socketTimeoutMS': 10000,
|
|
29
|
+
'serverSelectionTimeoutMS': 10000,
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
def get_mongo_client():
|
|
33
|
+
client = pymongo.MongoClient(uri, **mongo_params)
|
|
34
|
+
client['admin'].command('ping')
|
|
35
|
+
return client
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
class MongoDao:
|
|
40
|
+
def __init__(self, ref):
|
|
41
|
+
self.ref = ref
|
|
42
|
+
db_name = settings.BASE_APP
|
|
43
|
+
col_name = ref.replace('.', '_')
|
|
44
|
+
self.client = get_mongo_client()
|
|
45
|
+
self.collection = self.client[db_name][col_name]
|
|
46
|
+
def save_one(self, item):
|
|
47
|
+
_id = item.get('id', None)
|
|
48
|
+
_id = None if isinstance(_id, int) else _id
|
|
49
|
+
if _id is None:
|
|
50
|
+
bean:InsertOneResult = self.collection.insert_one(item)
|
|
51
|
+
_id = bean.inserted_id
|
|
52
|
+
self.collection.update_one({'_id': _id}, {'$set': {'sort':str(_id)}})
|
|
53
|
+
else:
|
|
54
|
+
del item['id']
|
|
55
|
+
_id = ObjectId(_id)
|
|
56
|
+
self.collection.update_one({'_id': _id}, {'$set': item})
|
|
57
|
+
return self.collection.find_one({'_id': _id})
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
def update_many(self, query, template):
|
|
61
|
+
self.collection.update_many(query.mon_conditions(), {'$set': template})
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
def delete_one(self, _id):
|
|
65
|
+
self.collection.delete_one({'_id': ObjectId(_id)})
|
|
66
|
+
|
|
67
|
+
def delete_many(self, query):
|
|
68
|
+
self.collection.delete_many(query.mon_conditions())
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
def find_one(self, _id):
|
|
72
|
+
return self.collection.find_one({'_id': ObjectId(_id)})
|
|
73
|
+
|
|
74
|
+
def find_many(self, query: Query, size=0, page=1) -> [QuerySet, int]:
|
|
75
|
+
skip = (page - 1) * size
|
|
76
|
+
condition = query.mon_conditions()
|
|
77
|
+
total = self.collection.count_documents(condition)
|
|
78
|
+
cursor = self.collection.find(condition).sort(query.orders).skip(skip).limit(size)
|
|
79
|
+
return [cursor, total]
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
def meta(self):
|
|
83
|
+
one = self.collection.find_one()
|
|
84
|
+
return one
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import datetime
|
|
2
|
+
from django.apps import apps
|
|
3
|
+
from django.core.paginator import Paginator
|
|
4
|
+
from django.db.models import Manager, QuerySet
|
|
5
|
+
|
|
6
|
+
from ..orm.detacher import detach_props, save_detached
|
|
7
|
+
from ..orm.meta_loader import load_meta, load_view, load_meta_field
|
|
8
|
+
from ..models import VModel
|
|
9
|
+
from ..query import Query
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def load_model(entity=None):
|
|
13
|
+
mapping = {}
|
|
14
|
+
for mod in apps.get_models():
|
|
15
|
+
if issubclass(mod, VModel):
|
|
16
|
+
path, name = mod.__module__, mod.__name__
|
|
17
|
+
print(path)
|
|
18
|
+
app = path.replace('.models', '').replace('src.valar.','')
|
|
19
|
+
key = '%s.%s' % (app, name)
|
|
20
|
+
verbose_name = mod._meta.verbose_name
|
|
21
|
+
mapping[key] = [mod, verbose_name]
|
|
22
|
+
return mapping.get(entity) if entity else mapping
|
|
23
|
+
|
|
24
|
+
class OrmDao:
|
|
25
|
+
def __init__(self, entity):
|
|
26
|
+
self.entity = entity
|
|
27
|
+
param = load_model(entity)
|
|
28
|
+
if param is None:
|
|
29
|
+
raise Exception('no entity named %s' % entity)
|
|
30
|
+
self.model = param[0]
|
|
31
|
+
self.name: str = param[1]
|
|
32
|
+
self.manager: Manager = self.model.objects
|
|
33
|
+
self.meta_fields = {}
|
|
34
|
+
self.model_fields = {}
|
|
35
|
+
for field in self.model._meta.get_fields():
|
|
36
|
+
_field = load_meta_field(field)
|
|
37
|
+
prop = _field['prop']
|
|
38
|
+
self.model_fields[prop] = field
|
|
39
|
+
self.meta_fields[prop] = _field
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
def save_one(self, item):
|
|
43
|
+
_item = detach_props(item, self.meta_fields.values())
|
|
44
|
+
_id = item.get('id',0)
|
|
45
|
+
query_set = self.manager.filter(id=_id)
|
|
46
|
+
if len(query_set):
|
|
47
|
+
del item['id']
|
|
48
|
+
item['modify_time'] = datetime.datetime.now()
|
|
49
|
+
query_set.update(**item)
|
|
50
|
+
bean = query_set.first()
|
|
51
|
+
else:
|
|
52
|
+
bean = self.manager.create(**item)
|
|
53
|
+
bean.sort = bean.id
|
|
54
|
+
bean.save()
|
|
55
|
+
save_detached(bean, _item, self.model_fields)
|
|
56
|
+
return bean
|
|
57
|
+
|
|
58
|
+
def update_many(self, query: Query, template):
|
|
59
|
+
self.find_many(query).update(**template)
|
|
60
|
+
|
|
61
|
+
def delete_one(self, _id):
|
|
62
|
+
self.manager.filter(id=_id).delete()
|
|
63
|
+
|
|
64
|
+
def delete_many(self, query: Query):
|
|
65
|
+
self.find_many(query)[0].delete()
|
|
66
|
+
|
|
67
|
+
def find_one(self, _id):
|
|
68
|
+
return self.manager.filter(id=_id).first()
|
|
69
|
+
|
|
70
|
+
def find_many(self, query: Query, size=0, page=1)->[QuerySet, int]:
|
|
71
|
+
includes, excludes = query.orm_conditions()
|
|
72
|
+
query_set = self.manager.filter(includes).exclude(excludes).order_by(*query.orm_orders())
|
|
73
|
+
total = query_set.count()
|
|
74
|
+
if size:
|
|
75
|
+
paginator = Paginator(query_set, size)
|
|
76
|
+
query_set = paginator.page(page).object_list
|
|
77
|
+
return query_set, total
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
def meta(self, code:str = 'default'):
|
|
81
|
+
omit = [ 'sort', 'create_time', 'modify_time', 'saved']
|
|
82
|
+
fields = [ self.meta_fields[prop] for prop in self.meta_fields if prop not in omit]
|
|
83
|
+
view = load_view(self.entity, code, self.name, fields)
|
|
84
|
+
return load_meta(view)
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
|
|
@@ -0,0 +1,61 @@
|
|
|
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
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
mf_common = ['prop','name','domain']
|
|
2
|
+
|
|
3
|
+
field_props = {
|
|
4
|
+
'data.Meta': {
|
|
5
|
+
'default': ('pick', ['entity','name']),
|
|
6
|
+
},
|
|
7
|
+
'data.MetaView': {
|
|
8
|
+
'list': ('pick', ['meta_id','code','view_name']),
|
|
9
|
+
'control':('omit', ['name','meta_id', 'code', 'view_name', 'metafield'])
|
|
10
|
+
},
|
|
11
|
+
'data.MetaField': {
|
|
12
|
+
'tool': ('pick',[*mf_common,'tool','refer','format']),
|
|
13
|
+
'rest': ('pick',[*mf_common,'not_null','read_only','unit','sortable','allow_search','allow_download','allow_upload','allow_update']),
|
|
14
|
+
'table': ('pick',[*mf_common,'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
|
+
field_default = {
|
|
21
|
+
'data.MetaField':{
|
|
22
|
+
|
|
23
|
+
}
|
|
24
|
+
}
|
|
@@ -0,0 +1,135 @@
|
|
|
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 ..orm.meta import field_props
|
|
6
|
+
from ..models import Meta, MetaView, VModel, MetaField
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def __save_model(model):
|
|
13
|
+
model.save()
|
|
14
|
+
model.sort = model.id
|
|
15
|
+
model.save()
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def load_view(entity, code, name, fields):
|
|
20
|
+
meta = Meta.objects.filter(entity=entity).first()
|
|
21
|
+
if meta is None:
|
|
22
|
+
meta = Meta(entity=entity, name=name)
|
|
23
|
+
__save_model(meta)
|
|
24
|
+
view = MetaView.objects.filter(meta__entity=entity, code=code).first()
|
|
25
|
+
if view is None:
|
|
26
|
+
view = MetaView(meta=meta, code=code, view_name=code.upper())
|
|
27
|
+
__save_model(view)
|
|
28
|
+
if view.metafield_set.count() == 0:
|
|
29
|
+
t, p = field_props.get(entity, {}).get(code,('omit',[]))
|
|
30
|
+
_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]
|
|
31
|
+
for f in _fields:
|
|
32
|
+
f['view'] = view
|
|
33
|
+
field = MetaField.objects.create(**f)
|
|
34
|
+
__save_model(field)
|
|
35
|
+
return view
|
|
36
|
+
|
|
37
|
+
def load_meta(view):
|
|
38
|
+
_view = view.full
|
|
39
|
+
_meta = _view['meta']
|
|
40
|
+
_fields = _view['metafield_set']
|
|
41
|
+
clear_item(_view, 'meta_id', 'metafield', 'metafield_set', 'meta')
|
|
42
|
+
_view['meta_name'] = _meta['name']
|
|
43
|
+
_view['entity'] = _meta['entity']
|
|
44
|
+
_view['fields'] = {}
|
|
45
|
+
for _field in _fields:
|
|
46
|
+
clear_item(_field, 'view_id')
|
|
47
|
+
prop = _field['prop']
|
|
48
|
+
_view['fields'][prop] = _field
|
|
49
|
+
return _view
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
def clear_item(item, *keys):
|
|
54
|
+
del item['saved']
|
|
55
|
+
del item['sort']
|
|
56
|
+
del item['id']
|
|
57
|
+
del item['create_time']
|
|
58
|
+
del item['modify_time']
|
|
59
|
+
for key in keys:
|
|
60
|
+
del item[key]
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
def get_refer(model, multiple = False):
|
|
65
|
+
module, name = model.__module__, model.__name__
|
|
66
|
+
entity = '%s.%s' % (module.replace('.models', '').split('.')[-1], name)
|
|
67
|
+
return {
|
|
68
|
+
"entity": entity,
|
|
69
|
+
"value": "id", "label": 'name', "display": "id",
|
|
70
|
+
"strict": False, "remote": False, "multiple": multiple,
|
|
71
|
+
"includes": {}, "excludes": {}, "root": 0,
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
def get_align(clazz):
|
|
75
|
+
if clazz in [FloatField, IntegerField, ManyToManyRel, ManyToManyField, ManyToOneRel]:
|
|
76
|
+
return 'right'
|
|
77
|
+
elif clazz in [BooleanField,FileField,JSONField,DateField,DateTimeField,TimeField]:
|
|
78
|
+
return 'center'
|
|
79
|
+
return 'left'
|
|
80
|
+
|
|
81
|
+
def get_format(field):
|
|
82
|
+
clazz = type(field)
|
|
83
|
+
if clazz == CharField:
|
|
84
|
+
return {'maxlength': field.max_length, "type": "text"}
|
|
85
|
+
if clazz == TextField:
|
|
86
|
+
return {'maxlength': None, "type": "textarea"}
|
|
87
|
+
elif clazz == FloatField:
|
|
88
|
+
return {'min': None, 'max': None, 'step': 1, 'precision': None, 'step_strictly': False}
|
|
89
|
+
elif clazz == IntegerField:
|
|
90
|
+
return {'min': None, 'max': None, 'step': 1, 'precision': 0, 'step_strictly': True}
|
|
91
|
+
elif clazz == FileField:
|
|
92
|
+
return {'max': 5, 'accept': "*", "width": "800px", "height": "auto", 'locked': False}
|
|
93
|
+
else:
|
|
94
|
+
return {}
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
def load_meta_field(field):
|
|
99
|
+
clazz = type(field)
|
|
100
|
+
if clazz in [ManyToOneRel, ManyToManyField, ManyToManyRel]:
|
|
101
|
+
prop = field.name
|
|
102
|
+
domain = clazz.__name__
|
|
103
|
+
model: VModel= field.related_model
|
|
104
|
+
label = model._meta.verbose_name
|
|
105
|
+
refer = get_refer(model, True)
|
|
106
|
+
elif clazz in [ForeignKey]:
|
|
107
|
+
prop = field.name + "_id"
|
|
108
|
+
domain = field.get_internal_type()
|
|
109
|
+
model: VModel = field.related_model
|
|
110
|
+
label = field.verbose_name
|
|
111
|
+
refer = get_refer(model)
|
|
112
|
+
elif clazz in [OneToOneRel, OneToOneField]:
|
|
113
|
+
prop = field.name + "_id"
|
|
114
|
+
domain = clazz.__name__
|
|
115
|
+
model: VModel = field.related_model
|
|
116
|
+
label = model._meta.verbose_name
|
|
117
|
+
refer = get_refer(model)
|
|
118
|
+
else:
|
|
119
|
+
prop = field.name
|
|
120
|
+
domain = field.get_internal_type()
|
|
121
|
+
label = field.verbose_name
|
|
122
|
+
refer = {}
|
|
123
|
+
not_null = not field.null
|
|
124
|
+
align = get_align(clazz)
|
|
125
|
+
_format = get_format(field)
|
|
126
|
+
return {
|
|
127
|
+
"prop": prop,
|
|
128
|
+
"label":label,
|
|
129
|
+
"name":label,
|
|
130
|
+
"domain":domain,
|
|
131
|
+
"refer":refer,
|
|
132
|
+
"format":_format,
|
|
133
|
+
"not_null":not_null,
|
|
134
|
+
"align":align,
|
|
135
|
+
}
|
valar/data/orm/values.py
ADDED
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
from django.db.models import (ManyToOneRel, ManyToManyRel, OneToOneField, CharField,ManyToManyField,
|
|
2
|
+
OneToOneRel, IntegerField, BooleanField, FloatField, FileField, JSONField, DateField,
|
|
3
|
+
DateTimeField, TimeField, TextField, QuerySet)
|
|
4
|
+
from django.db.models.fields.related import ForeignKey
|
|
5
|
+
|
|
6
|
+
from ..models import VModel, MetaField
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def get_props(model:VModel, code):
|
|
10
|
+
|
|
11
|
+
simple_props, referred_fields, date_props = [], {}, {}
|
|
12
|
+
fields = model._meta.get_fields()
|
|
13
|
+
for field in fields:
|
|
14
|
+
clazz = type(field)
|
|
15
|
+
prop = field.name
|
|
16
|
+
if clazz in [ForeignKey,ManyToOneRel,
|
|
17
|
+
ManyToManyRel,ManyToManyField,
|
|
18
|
+
OneToOneRel, OneToOneField]:
|
|
19
|
+
referred_fields[prop] = {
|
|
20
|
+
'value': 'id', 'label': 'name', 'display': 'id',
|
|
21
|
+
'field': field
|
|
22
|
+
}
|
|
23
|
+
else:
|
|
24
|
+
simple_props.append(prop)
|
|
25
|
+
if clazz in [ForeignKey, OneToOneField, OneToOneRel]:
|
|
26
|
+
simple_props.append(prop)
|
|
27
|
+
if clazz in [DateField, DateTimeField]:
|
|
28
|
+
date_props[prop] = clazz
|
|
29
|
+
|
|
30
|
+
module, name = model.__module__, model.__name__
|
|
31
|
+
entity = '%s.%s' % (module.replace('.models', '').split('.')[-1], name)
|
|
32
|
+
if code:
|
|
33
|
+
field_set = MetaField.objects.filter(view__code=code, view__meta__entity=entity)
|
|
34
|
+
customs = field_set.filter(domain='Custom').values('prop')
|
|
35
|
+
for row in customs:
|
|
36
|
+
simple_props.append(row['prop'])
|
|
37
|
+
refers =field_set.filter(prop__in=referred_fields.keys()).values('prop','refer__value','refer__label','refer__display')
|
|
38
|
+
for row in refers:
|
|
39
|
+
prop, value, label, display = row['prop'], row['refer__value'], row['refer__label'], row['refer__display']
|
|
40
|
+
referred_fields[prop]['value'] = value
|
|
41
|
+
referred_fields[prop]['label'] = label
|
|
42
|
+
referred_fields[prop]['display'] = display
|
|
43
|
+
return simple_props, referred_fields, date_props
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
def to_dict(query_set: QuerySet, code=None):
|
|
47
|
+
model = query_set.model
|
|
48
|
+
simple_props, referred_fields, date_props = get_props(model, code)
|
|
49
|
+
values = query_set.values(*[*simple_props]) if len(query_set) else []
|
|
50
|
+
results = list(values)
|
|
51
|
+
pks = []
|
|
52
|
+
for row in results:
|
|
53
|
+
pks.append(row['id'])
|
|
54
|
+
for prop in date_props:
|
|
55
|
+
formating = '%Y-%m-%d' if date_props[prop] == DateField else '%Y-%m-%d %H:%M:%S'
|
|
56
|
+
val = row[prop]
|
|
57
|
+
row[prop] =val.strftime(formating) if val else val
|
|
58
|
+
for prop in referred_fields:
|
|
59
|
+
_field = referred_fields[prop]
|
|
60
|
+
value, label, display, field = _field['value'], _field['label'], _field['display'], _field['field']
|
|
61
|
+
clazz = type(field)
|
|
62
|
+
keys = {'id', value, display, label}
|
|
63
|
+
if clazz in [ForeignKey, OneToOneField, OneToOneRel]:
|
|
64
|
+
related_model = field.related_model
|
|
65
|
+
related_pks = set([row.get(prop) for row in results if row.get(prop)])
|
|
66
|
+
related_items = related_model.objects.filter(id__in=related_pks).values(*keys)
|
|
67
|
+
mapping = {item['id']: item for item in related_items}
|
|
68
|
+
for row in results:
|
|
69
|
+
value = row.get(prop)
|
|
70
|
+
if value:
|
|
71
|
+
row[prop] = mapping[value]
|
|
72
|
+
row[f'{prop}_id'] = value
|
|
73
|
+
elif clazz in [ ManyToManyField, ManyToOneRel, ManyToManyRel]:
|
|
74
|
+
_prop = f'{prop}__id'
|
|
75
|
+
linkage = model.objects.filter(id__in=pks).exclude(**{f'{_prop}__isnull':True}).values('id',_prop)
|
|
76
|
+
row_mapping = {}
|
|
77
|
+
_pks = set()
|
|
78
|
+
for link in linkage:
|
|
79
|
+
_id, _pk = link['id'], link[_prop]
|
|
80
|
+
_pks.add(_pk)
|
|
81
|
+
array = row_mapping.get(_id,[])
|
|
82
|
+
array.append(_pk)
|
|
83
|
+
row_mapping[_id] = array
|
|
84
|
+
related_model = field.related_model
|
|
85
|
+
related_items = related_model.objects.filter(id__in=_pks).values(*keys)
|
|
86
|
+
mapping = {item['id']: item for item in related_items}
|
|
87
|
+
for row in results:
|
|
88
|
+
_id = row.get('id')
|
|
89
|
+
__ids = row_mapping.get(_id, [])
|
|
90
|
+
__set = [ mapping[__id] for __id in __ids]
|
|
91
|
+
row[prop] = __ids
|
|
92
|
+
row[f'{prop}_set'] = __set
|
|
93
|
+
return results
|
valar/data/query.py
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
from functools import reduce
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
from django.db.models import Q
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class Condition:
|
|
10
|
+
def __init__(self, condition):
|
|
11
|
+
self.includes = condition.get('includes', {})
|
|
12
|
+
self.excludes = condition.get('excludes', {})
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class Query:
|
|
17
|
+
def __init__(self, body=None):
|
|
18
|
+
if body is None:
|
|
19
|
+
body = {}
|
|
20
|
+
self.template = body.get('template',{})
|
|
21
|
+
self.condition = Condition(body.get('condition',{}))
|
|
22
|
+
self.search = [ Condition(condition) for condition in body.get('search',[])]
|
|
23
|
+
self.orders = body.get('orders',{})
|
|
24
|
+
|
|
25
|
+
def orm_orders(self):
|
|
26
|
+
array = []
|
|
27
|
+
for key in self.orders :
|
|
28
|
+
value = self.orders .get(key)
|
|
29
|
+
prefix = '-' if value == -1 else ''
|
|
30
|
+
array.append(f'{prefix}{key}')
|
|
31
|
+
return array
|
|
32
|
+
|
|
33
|
+
def orm_conditions(self):
|
|
34
|
+
includes, excludes = self.condition.includes, self.condition.excludes
|
|
35
|
+
if len(self.search):
|
|
36
|
+
inc = [ Q(**{**includes, **sea.includes}) for sea in self.search]
|
|
37
|
+
exc = [ Q(**{**excludes, **sea.excludes}) for sea in self.search]
|
|
38
|
+
def fun(x, y):return x | y
|
|
39
|
+
return [reduce(fun, inc), reduce(fun, exc)]
|
|
40
|
+
else:
|
|
41
|
+
return [Q(**self.condition.includes), Q(**self.condition.excludes)]
|
|
42
|
+
|
|
43
|
+
def mon_conditions(self):
|
|
44
|
+
includes, excludes = self.condition.includes, self.condition.excludes
|
|
45
|
+
return {}
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
# def _mon_conditions(self):
|
valar/data/urls.py
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
from django.urls import path
|
|
2
|
+
|
|
3
|
+
from ..data import views
|
|
4
|
+
|
|
5
|
+
urlpatterns = [
|
|
6
|
+
path('save_one', views.save_one),
|
|
7
|
+
path('save_many', views.save_many),
|
|
8
|
+
path('update_many', views.update_many),
|
|
9
|
+
path('delete_one', views.delete_one),
|
|
10
|
+
path('delete_many', views.delete_many),
|
|
11
|
+
path('find_one', views.find_one),
|
|
12
|
+
path('find_many', views.find_many),
|
|
13
|
+
path('meta', views.meta),
|
|
14
|
+
|
|
15
|
+
]
|
valar/data/utils.py
ADDED
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
from django.db.models import QuerySet
|
|
2
|
+
from pymongo.synchronous.cursor import Cursor
|
|
3
|
+
|
|
4
|
+
from .orm.values import to_dict
|
|
5
|
+
from ..data.mon import MongoDao
|
|
6
|
+
from ..data.orm import OrmDao
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def get_dao(db,entity):
|
|
14
|
+
if db == 'orm':
|
|
15
|
+
return OrmDao(entity)
|
|
16
|
+
elif db == 'mon':
|
|
17
|
+
return MongoDao(entity)
|
|
18
|
+
else:
|
|
19
|
+
raise ValueError('Invalid database %s' % db)
|
|
20
|
+
|
|
21
|
+
def transform(db, results, code=None):
|
|
22
|
+
if isinstance(results, Cursor):
|
|
23
|
+
return [to_item(db, bean) for bean in results]
|
|
24
|
+
elif isinstance(results, QuerySet):
|
|
25
|
+
return to_dict(results, code)
|
|
26
|
+
else:
|
|
27
|
+
return to_item(db, results)
|
|
28
|
+
|
|
29
|
+
def to_item(db, bean):
|
|
30
|
+
if db == 'orm':
|
|
31
|
+
return bean.full
|
|
32
|
+
elif db == 'mon':
|
|
33
|
+
bean['id'] = str(bean['_id'])
|
|
34
|
+
del bean['_id']
|
|
35
|
+
return bean
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
def array2tree(data, mapping):
|
|
39
|
+
mapping = mapping or {}
|
|
40
|
+
lookup = {}
|
|
41
|
+
for array in data:
|
|
42
|
+
for i in range(len(array)):
|
|
43
|
+
key = '/'.join(array[0:i+1])
|
|
44
|
+
item = mapping.get(key, {})
|
|
45
|
+
value = item.get('value', array[i])
|
|
46
|
+
label = item.get('label', value)
|
|
47
|
+
display = item.get('display')
|
|
48
|
+
item = lookup.get(key, {'value': value,'label':label,'display':display})
|
|
49
|
+
if i < len(array) -1:
|
|
50
|
+
item['children'] = item.get('children', [])
|
|
51
|
+
lookup[key] = item
|
|
52
|
+
if i > 0:
|
|
53
|
+
parent = '/'.join(array[0:i])
|
|
54
|
+
lookup[parent]['children'].append(lookup[key])
|
|
55
|
+
return [lookup[root] for root in [*set([array[0] for array in data])]]
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
# for parent, child in data:
|
|
60
|
+
# if parent not in lookup:
|
|
61
|
+
# lookup[parent] = {'label': parent, 'value':parent, 'children': []}
|
|
62
|
+
# if child not in lookup:
|
|
63
|
+
# lookup[child] = {'label': child, 'value':child, 'children': []}
|
|
64
|
+
# lookup[parent]['children'].append(lookup[child])
|
|
65
|
+
# children_set = {child for _, child in data}
|
|
66
|
+
# root_nodes = [node for name, node in lookup.items() if name not in children_set]
|
|
67
|
+
# return root_nodes
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
|