valar 1.0.17__py3-none-any.whl → 1.0.19__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.

@@ -1,14 +1,18 @@
1
1
  import datetime
2
2
  from django.apps import apps
3
3
  from django.core.paginator import Paginator
4
- from django.db.models import Manager, QuerySet
4
+ from django.db.models import Manager, QuerySet, FileField
5
5
 
6
+ from .meta_frame import load_meta_frame
7
+ from ..file import minio_remove_path
6
8
  from ..orm.detacher import detach_props, save_detached
7
9
  from ..orm.meta_loader import load_meta, load_view, load_meta_field
8
- from ..models import VModel
10
+ from ..models import VModel, VTree
9
11
  from ..query import Query
10
12
 
11
13
 
14
+ load_meta_frame()
15
+
12
16
  def load_model(entity=None):
13
17
  mapping = {}
14
18
  for mod in apps.get_models():
@@ -21,6 +25,9 @@ def load_model(entity=None):
21
25
  mapping[key] = [mod, verbose_name]
22
26
  return mapping.get(entity) if entity else mapping
23
27
 
28
+
29
+
30
+
24
31
  class OrmDao:
25
32
  def __init__(self, entity):
26
33
  self.entity = entity
@@ -28,17 +35,50 @@ class OrmDao:
28
35
  if param is None:
29
36
  raise Exception('no entity named %s' % entity)
30
37
  self.model = param[0]
38
+ self.isTree = issubclass(self.model, VTree)
31
39
  self.name: str = param[1]
32
40
  self.manager: Manager = self.model.objects
33
41
  self.meta_fields = {}
34
42
  self.model_fields = {}
35
43
  for field in self.model._meta.get_fields():
36
- _field = load_meta_field(field)
44
+ _field = load_meta_field(field, self.isTree)
37
45
  prop = _field['prop']
38
46
  self.model_fields[prop] = field
39
47
  self.meta_fields[prop] = _field
40
48
 
41
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
+
42
82
  def save_one(self, item):
43
83
  _item = detach_props(item, self.meta_fields.values())
44
84
  _id = item.get('id',0)
@@ -46,6 +86,7 @@ class OrmDao:
46
86
  if len(query_set):
47
87
  del item['id']
48
88
  item['modify_time'] = datetime.datetime.now()
89
+ self.__check_remove_file__(query_set,item)
49
90
  query_set.update(**item)
50
91
  bean = query_set.first()
51
92
  else:
@@ -56,18 +97,23 @@ class OrmDao:
56
97
  return bean
57
98
 
58
99
  def update_many(self, query: Query, template):
59
- self.find_many(query).update(**template)
100
+ query_set, total = self.find_many(query)
101
+ query_set.update(**template)
60
102
 
61
103
  def delete_one(self, _id):
62
- self.manager.filter(id=_id).delete()
104
+ query_set = self.manager.filter(id=_id)
105
+ self.__check_remove_file__(query_set)
106
+ query_set.delete()
63
107
 
64
108
  def delete_many(self, query: Query):
65
- self.find_many(query)[0].delete()
109
+ query_set, total = self.find_many(query)
110
+ self.__check_remove_file__(query_set)
111
+ query_set.delete()
66
112
 
67
113
  def find_one(self, _id):
68
114
  return self.manager.filter(id=_id).first()
69
115
 
70
- def find_many(self, query: Query, size=0, page=1)->[QuerySet, int]:
116
+ def find_many(self, query: Query, size=0, page=1):
71
117
  includes, excludes = query.orm_conditions()
72
118
  query_set = self.manager.filter(includes).exclude(excludes).order_by(*query.orm_orders())
73
119
  total = query_set.count()
@@ -78,10 +124,12 @@ class OrmDao:
78
124
 
79
125
 
80
126
  def meta(self, code:str = 'default'):
81
- omit = [ 'sort', 'create_time', 'modify_time']
127
+ omit = [ 'id', 'saved', 'sort', 'create_time', 'modify_time']
82
128
  fields = [ self.meta_fields[prop] for prop in self.meta_fields if prop not in omit]
83
129
  view = load_view(self.entity, code, self.name, fields)
84
- return load_meta(view)
130
+ _view = load_meta(view)
131
+ _view['isTree'] = self.isTree
132
+ return _view
85
133
 
86
134
 
87
135
 
valar/data/orm/meta.py CHANGED
@@ -1,24 +1,99 @@
1
- mf_common = ['prop','name','domain']
1
+ mf_common = ['prop','name']
2
2
 
3
- field_props = {
3
+ meta_props = {
4
4
  'data.Meta': {
5
5
  'default': ('pick', ['entity','name']),
6
6
  },
7
7
  'data.MetaView': {
8
8
  'list': ('pick', ['meta_id','code','view_name']),
9
- 'control':('omit', ['name','meta_id', 'code', 'view_name', 'metafield'])
10
9
  },
11
10
  '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']),
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
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
16
  }
17
17
  }
18
18
 
19
19
 
20
- field_default = {
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
+ },
21
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
+ }
22
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
+ },
23
98
  }
24
99
  }
@@ -0,0 +1,49 @@
1
+ import os
2
+
3
+ from django.db import OperationalError
4
+
5
+ from src.valar.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
+
@@ -2,16 +2,17 @@ from django.db.models import (ManyToOneRel, ForeignKey, ManyToManyRel, ManyToMan
2
2
  OneToOneRel, IntegerField, BooleanField, FloatField, FileField, JSONField, DateField,
3
3
  TextField,DateTimeField, TimeField)
4
4
 
5
- from ..orm.meta import field_props
6
- from ..models import Meta, MetaView, VModel, MetaField
7
-
8
-
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
9
8
 
9
+ from deepmerge import always_merger
10
10
 
11
11
 
12
12
  def __save_model(model):
13
13
  model.save()
14
14
  model.sort = model.id
15
+ model.saved = True
15
16
  model.save()
16
17
 
17
18
 
@@ -26,8 +27,13 @@ def load_view(entity, code, name, fields):
26
27
  view = MetaView(meta=meta, code=code, view_name=code.upper())
27
28
  __save_model(view)
28
29
  if view.metafield_set.count() == 0:
29
- t, p = field_props.get(entity, {}).get(code,('omit',[]))
30
+ t, p = meta_props.get(entity, {}).get(code,('omit',[]))
30
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()
31
37
  for f in _fields:
32
38
  f['view'] = view
33
39
  field = MetaField.objects.create(**f)
@@ -37,7 +43,9 @@ def load_view(entity, code, name, fields):
37
43
  def load_meta(view):
38
44
  _view = view.full
39
45
  _meta = _view['meta']
40
- _fields = _view['metafield_set']
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]
41
49
  clear_item(_view, 'meta_id', 'metafield', 'metafield_set', 'meta')
42
50
  _view['meta_name'] = _meta['name']
43
51
  _view['entity'] = _meta['entity']
@@ -53,13 +61,20 @@ def load_meta(view):
53
61
  def clear_item(item, *keys):
54
62
  del item['saved']
55
63
  del item['sort']
56
- del item['id']
57
64
  del item['create_time']
58
65
  del item['modify_time']
59
66
  for key in keys:
60
67
  del item[key]
61
68
 
62
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
+
63
78
 
64
79
  def get_refer(model, multiple = False):
65
80
  module, name = model.__module__, model.__name__
@@ -68,34 +83,72 @@ def get_refer(model, multiple = False):
68
83
  "entity": entity,
69
84
  "value": "id", "label": 'name', "display": "id",
70
85
  "strict": False, "remote": False, "multiple": multiple,
71
- "includes": {}, "excludes": {}, "root": 0,
86
+ "includes": {}, "excludes": {}, "root": 0, "isTree": issubclass(model, VTree)
72
87
  }
73
88
 
74
89
  def get_align(clazz):
75
- if clazz in [FloatField, IntegerField, ManyToManyRel, ManyToManyField, ManyToOneRel]:
90
+ if clazz in [FloatField, IntegerField]: #, ManyToManyRel, ManyToManyField, ManyToOneRel
76
91
  return 'right'
77
92
  elif clazz in [BooleanField,FileField,JSONField,DateField,DateTimeField,TimeField]:
78
93
  return 'center'
79
94
  return 'left'
80
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
+
81
126
  def get_format(field):
82
127
  clazz = type(field)
128
+ _format = get_default_format()
83
129
  if clazz == CharField:
84
- return {'maxlength': field.max_length, "type": "text"}
130
+ _format['maxlength'] = field.max_length
85
131
  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}
132
+ _format['type'] = "textarea"
133
+ elif clazz == DateTimeField:
134
+ _format['frequency'] = "datetime"
89
135
  elif clazz == IntegerField:
90
- return {'min': None, 'max': None, 'step': 1, 'precision': 0, 'step_strictly': True}
136
+ _format['precision'] = 0
137
+ _format['step_strictly'] = True
91
138
  elif clazz == FileField:
92
- return {'max': 5, 'accept': "*", "width": "800px", "height": "auto", 'locked': False}
93
- else:
94
- return {}
139
+ pass
140
+ return _format
95
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
96
148
 
97
149
 
98
- def load_meta_field(field):
150
+
151
+ def load_meta_field(field, isTree):
99
152
  clazz = type(field)
100
153
  if clazz in [ManyToOneRel, ManyToManyField, ManyToManyRel]:
101
154
  prop = field.name
@@ -119,11 +172,12 @@ def load_meta_field(field):
119
172
  prop = field.name
120
173
  domain = field.get_internal_type()
121
174
  label = field.verbose_name
122
- refer = {}
175
+ refer = get_default_refer()
123
176
  not_null = not field.null
124
177
  align = get_align(clazz)
125
178
  _format = get_format(field)
126
- return {
179
+ column_width = get_field_column_width(field,clazz)
180
+ _field = {
127
181
  "prop": prop,
128
182
  "label":label,
129
183
  "name":label,
@@ -132,4 +186,15 @@ def load_meta_field(field):
132
186
  "format":_format,
133
187
  "not_null":not_null,
134
188
  "align":align,
189
+ "column_width":column_width
135
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
valar/data/orm/values.py CHANGED
@@ -43,6 +43,13 @@ def get_props(model:VModel, code):
43
43
  return simple_props, referred_fields, date_props
44
44
 
45
45
 
46
+ def __get_ref_keys__(related_model):
47
+ """新增功能"""
48
+ return [f.name for f in related_model._meta.get_fields()
49
+ if type(f) not in [ManyToManyField, ManyToOneRel, ManyToManyRel, ForeignKey, OneToOneField, OneToOneRel]
50
+ and f.name not in ['create_time', 'modify_time', 'saved', 'sort']
51
+ ]
52
+
46
53
  def to_dict(query_set: QuerySet, code=None):
47
54
  model = query_set.model
48
55
  simple_props, referred_fields, date_props = get_props(model, code)
@@ -62,8 +69,9 @@ def to_dict(query_set: QuerySet, code=None):
62
69
  keys = {'id', value, display, label}
63
70
  if clazz in [ForeignKey, OneToOneField, OneToOneRel]:
64
71
  related_model = field.related_model
72
+ __keys = __get_ref_keys__(related_model)
65
73
  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)
74
+ related_items = related_model.objects.filter(id__in=related_pks).values(*__keys)
67
75
  mapping = {item['id']: item for item in related_items}
68
76
  for row in results:
69
77
  value = row.get(prop)
@@ -82,7 +90,8 @@ def to_dict(query_set: QuerySet, code=None):
82
90
  array.append(_pk)
83
91
  row_mapping[_id] = array
84
92
  related_model = field.related_model
85
- related_items = related_model.objects.filter(id__in=_pks).values(*keys)
93
+ __keys = __get_ref_keys__(related_model)
94
+ related_items = related_model.objects.filter(id__in=_pks).values(*__keys)
86
95
  mapping = {item['id']: item for item in related_items}
87
96
  for row in results:
88
97
  _id = row.get('id')
valar/data/query.py CHANGED
@@ -1,6 +1,4 @@
1
1
  from functools import reduce
2
-
3
-
4
2
  from django.db.models import Q
5
3
 
6
4
 
@@ -17,15 +15,18 @@ class Query:
17
15
  def __init__(self, body=None):
18
16
  if body is None:
19
17
  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',{})
18
+ self.template = body.get('template', {})
19
+ self.condition = Condition(body.get('condition', {}))
20
+ self.search = [Condition(condition) for condition in body.get('search', [])]
21
+ self.orders = body.get('orders', {})
22
+ self.finder = body.get('finder', {})
23
+ self.page = body.get('page',1)
24
+ self.size = body.get('size', 0)
24
25
 
25
26
  def orm_orders(self):
26
27
  array = []
27
- for key in self.orders :
28
- value = self.orders .get(key)
28
+ for key in self.orders:
29
+ value = self.orders.get(key)
29
30
  prefix = '-' if value == -1 else ''
30
31
  array.append(f'{prefix}{key}')
31
32
  return array
@@ -33,16 +34,15 @@ class Query:
33
34
  def orm_conditions(self):
34
35
  includes, excludes = self.condition.includes, self.condition.excludes
35
36
  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
37
+ inc = [Q(**{**includes, **sea.includes}) for sea in self.search]
38
+ exc = [Q(**{**excludes, **sea.excludes}) for sea in self.search]
39
+ def fun(x, y): return x | y
39
40
  return [reduce(fun, inc), reduce(fun, exc)]
40
41
  else:
41
42
  return [Q(**self.condition.includes), Q(**self.condition.excludes)]
42
43
 
43
44
  def mon_conditions(self):
44
- includes, excludes = self.condition.includes, self.condition.excludes
45
- return {}
46
-
45
+ from .mon.query_translator import MongoQueryTranslator
46
+ return MongoQueryTranslator.translate_query(self)
47
47
 
48
48
  # def _mon_conditions(self):
valar/data/urls.py CHANGED
@@ -1,15 +1,24 @@
1
- from django.urls import path
1
+ from django.urls import path, include
2
2
 
3
3
  from ..data import views
4
4
 
5
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),
6
+ path('<str:db>/<str:entity>/save_one', views.save_one),
7
+ path('<str:db>/<str:entity>/save_many', views.save_many),
8
+ path('<str:db>/<str:entity>/save_file', views.save_file),
9
+
10
+ path('<str:db>/<str:entity>/update_many', views.update_many),
11
+ path('<str:db>/<str:entity>/delete_one', views.delete_one),
12
+ path('<str:db>/<str:entity>/delete_many', views.delete_many),
13
+ path('<str:db>/<str:entity>/find_one', views.find_one),
14
+ path('<str:db>/<str:entity>/find_many', views.find_many),
15
+ path('find_file/<str:bucket_name>/<str:object_name>', views.find_file),
16
+ path('<str:db>/<str:entity>/tree', views.tree),
14
17
 
18
+ # path('data/<str:db>/<str:entity>/', include('src.valar.data.urls')),
19
+
20
+ path('add_fields', views.add_fields),
21
+ path('fields', views.fields),
22
+ path('meta', views.meta),
23
+ path('metas', views.metas),
15
24
  ]