valar 1.0.18__tar.gz → 1.0.20__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


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

Files changed (35) hide show
  1. {valar-1.0.18/src/valar.egg-info → valar-1.0.20}/PKG-INFO +33 -11
  2. {valar-1.0.18 → valar-1.0.20}/README.md +28 -10
  3. {valar-1.0.18 → valar-1.0.20}/setup.py +11 -2
  4. valar-1.0.20/src/valar/data/file/__init__.py +91 -0
  5. valar-1.0.20/src/valar/data/migrations/0001_initial.py +238 -0
  6. {valar-1.0.18 → valar-1.0.20}/src/valar/data/models.py +15 -6
  7. {valar-1.0.18 → valar-1.0.20}/src/valar/data/orm/__init__.py +33 -8
  8. valar-1.0.20/src/valar/data/orm/meta.py +99 -0
  9. valar-1.0.20/src/valar/data/orm/meta_frame.py +49 -0
  10. {valar-1.0.18 → valar-1.0.20}/src/valar/data/orm/meta_loader.py +70 -19
  11. {valar-1.0.18 → valar-1.0.20}/src/valar/data/orm/values.py +11 -2
  12. {valar-1.0.18 → valar-1.0.20}/src/valar/data/urls.py +3 -0
  13. {valar-1.0.18 → valar-1.0.20}/src/valar/data/views.py +56 -7
  14. {valar-1.0.18 → valar-1.0.20/src/valar.egg-info}/PKG-INFO +33 -11
  15. {valar-1.0.18 → valar-1.0.20}/src/valar.egg-info/SOURCES.txt +2 -1
  16. {valar-1.0.18 → valar-1.0.20}/src/valar.egg-info/requires.txt +4 -0
  17. valar-1.0.18/src/valar/data/migrations/0001_initial.py +0 -582
  18. valar-1.0.18/src/valar/data/migrations/0002_valatree_alter_metafield_allow_sort.py +0 -36
  19. valar-1.0.18/src/valar/data/orm/meta.py +0 -46
  20. {valar-1.0.18 → valar-1.0.20}/LICENSE +0 -0
  21. {valar-1.0.18 → valar-1.0.20}/setup.cfg +0 -0
  22. {valar-1.0.18 → valar-1.0.20}/src/valar/__init__.py +0 -0
  23. {valar-1.0.18 → valar-1.0.20}/src/valar/channels/__init__.py +0 -0
  24. {valar-1.0.18 → valar-1.0.20}/src/valar/channels/utils.py +0 -0
  25. {valar-1.0.18 → valar-1.0.20}/src/valar/channels/views.py +0 -0
  26. {valar-1.0.18 → valar-1.0.20}/src/valar/data/__init__.py +0 -0
  27. {valar-1.0.18 → valar-1.0.20}/src/valar/data/handlers.py +0 -0
  28. {valar-1.0.18 → valar-1.0.20}/src/valar/data/migrations/__init__.py +0 -0
  29. {valar-1.0.18 → valar-1.0.20}/src/valar/data/mon/__init__.py +0 -0
  30. {valar-1.0.18 → valar-1.0.20}/src/valar/data/mon/query_translator.py +0 -0
  31. {valar-1.0.18 → valar-1.0.20}/src/valar/data/orm/detacher.py +0 -0
  32. {valar-1.0.18 → valar-1.0.20}/src/valar/data/query.py +0 -0
  33. {valar-1.0.18 → valar-1.0.20}/src/valar/data/utils.py +0 -0
  34. {valar-1.0.18 → valar-1.0.20}/src/valar.egg-info/dependency_links.txt +0 -0
  35. {valar-1.0.18 → valar-1.0.20}/src/valar.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: valar
3
- Version: 1.0.18
3
+ Version: 1.0.20
4
4
  Summary: valar for morghulis
5
5
  Author: LYP
6
6
  Author-email: liuyinpeng@buaa.edu.cn
@@ -11,6 +11,10 @@ Requires-Dist: channels==3.0.3
11
11
  Requires-Dist: pymongo~=4.11.2
12
12
  Requires-Dist: asgiref~=3.8.1
13
13
  Requires-Dist: django-cors-headers==4.2.0
14
+ Requires-Dist: pandas==2.2.3
15
+ Requires-Dist: openpyxl==3.1.5
16
+ Requires-Dist: deepmerge~=2.0
17
+ Requires-Dist: minio==7.2.2
14
18
  Dynamic: author
15
19
  Dynamic: author-email
16
20
  Dynamic: description
@@ -32,7 +36,8 @@ BASE_DIR = Path(__file__).resolve().parent.parent
32
36
  BASE_APP = str(BASE_DIR.name)
33
37
  DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'
34
38
 
35
- """ Minimized compulsory settings """
39
+
40
+ """ DataSource """
36
41
 
37
42
  DATABASES = {
38
43
  'default': {
@@ -41,6 +46,22 @@ DATABASES = {
41
46
  }
42
47
  }
43
48
 
49
+ MONGO_SETTINGS = {
50
+ 'host': '47.98.192.120',
51
+ 'port': 27017,
52
+ "username": "admin",
53
+ "password": '19870120'
54
+ }
55
+
56
+ MINIO_SETTINGS = {
57
+ 'endpoint': '10.134.10.92:9000',
58
+ 'access_key': 'admin',
59
+ "secret_key": "19870120",
60
+ 'secure': False
61
+ }
62
+
63
+ """ Minimized compulsory settings """
64
+
44
65
  INSTALLED_APPS = [
45
66
  'django.contrib.sessions',
46
67
  "corsheaders",
@@ -67,6 +88,7 @@ ROOT_URLCONF = "%s.urls" % BASE_APP
67
88
  ASGI_APPLICATION = "%s.asgi.application" % BASE_APP
68
89
  VALAR_CHANNEL_HANDLER_MAPPING = "%s.urls.channel_handler_mapping" % BASE_APP
69
90
 
91
+
70
92
  """ Optional settings """
71
93
  # ALLOWED_HOSTS = ['*']
72
94
  # LANGUAGE_CODE = 'en-us'
@@ -81,27 +103,27 @@ VALAR_CHANNEL_HANDLER_MAPPING = "%s.urls.channel_handler_mapping" % BASE_APP
81
103
 
82
104
  # root urls
83
105
  ```python
84
- from django.urls import path
106
+ from django.urls import path, include
85
107
 
86
108
  from valar.channels import ValarSocketSender
87
109
  from valar.channels.views import handel_channel
88
110
 
89
111
  urlpatterns = [
90
112
  path('socket/<str:handler>', handel_channel),
113
+ path('data/', include('valar.data.urls')),
91
114
  ]
92
115
 
93
116
 
94
- async def test_handler(data, sender: ValarSocketSender):
95
- # print(data, sender.handler, sender.client, sender.uid)
96
- await sender.to_users({'user': 15}, 15)
97
- for i in range(3):
98
- await sender.to_clients({'h': i},sender.client)
99
-
100
-
101
117
  channel_handler_mapping = {
102
- 'test': test_handler
118
+ # 'test': test_handler
103
119
  }
104
120
 
121
+ # async def test_handler(data, sender: ValarSocketSender):
122
+ # # print(data, sender.handler, sender.client, sender.uid)
123
+ # await sender.to_users({'user': 15}, 15)
124
+ # for i in range(3):
125
+ # await sender.to_clients({'h': i},sender.client)
126
+
105
127
  ```
106
128
 
107
129
 
@@ -10,7 +10,8 @@ BASE_DIR = Path(__file__).resolve().parent.parent
10
10
  BASE_APP = str(BASE_DIR.name)
11
11
  DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'
12
12
 
13
- """ Minimized compulsory settings """
13
+
14
+ """ DataSource """
14
15
 
15
16
  DATABASES = {
16
17
  'default': {
@@ -19,6 +20,22 @@ DATABASES = {
19
20
  }
20
21
  }
21
22
 
23
+ MONGO_SETTINGS = {
24
+ 'host': '47.98.192.120',
25
+ 'port': 27017,
26
+ "username": "admin",
27
+ "password": '19870120'
28
+ }
29
+
30
+ MINIO_SETTINGS = {
31
+ 'endpoint': '10.134.10.92:9000',
32
+ 'access_key': 'admin',
33
+ "secret_key": "19870120",
34
+ 'secure': False
35
+ }
36
+
37
+ """ Minimized compulsory settings """
38
+
22
39
  INSTALLED_APPS = [
23
40
  'django.contrib.sessions',
24
41
  "corsheaders",
@@ -45,6 +62,7 @@ ROOT_URLCONF = "%s.urls" % BASE_APP
45
62
  ASGI_APPLICATION = "%s.asgi.application" % BASE_APP
46
63
  VALAR_CHANNEL_HANDLER_MAPPING = "%s.urls.channel_handler_mapping" % BASE_APP
47
64
 
65
+
48
66
  """ Optional settings """
49
67
  # ALLOWED_HOSTS = ['*']
50
68
  # LANGUAGE_CODE = 'en-us'
@@ -59,27 +77,27 @@ VALAR_CHANNEL_HANDLER_MAPPING = "%s.urls.channel_handler_mapping" % BASE_APP
59
77
 
60
78
  # root urls
61
79
  ```python
62
- from django.urls import path
80
+ from django.urls import path, include
63
81
 
64
82
  from valar.channels import ValarSocketSender
65
83
  from valar.channels.views import handel_channel
66
84
 
67
85
  urlpatterns = [
68
86
  path('socket/<str:handler>', handel_channel),
87
+ path('data/', include('valar.data.urls')),
69
88
  ]
70
89
 
71
90
 
72
- async def test_handler(data, sender: ValarSocketSender):
73
- # print(data, sender.handler, sender.client, sender.uid)
74
- await sender.to_users({'user': 15}, 15)
75
- for i in range(3):
76
- await sender.to_clients({'h': i},sender.client)
77
-
78
-
79
91
  channel_handler_mapping = {
80
- 'test': test_handler
92
+ # 'test': test_handler
81
93
  }
82
94
 
95
+ # async def test_handler(data, sender: ValarSocketSender):
96
+ # # print(data, sender.handler, sender.client, sender.uid)
97
+ # await sender.to_users({'user': 15}, 15)
98
+ # for i in range(3):
99
+ # await sender.to_clients({'h': i},sender.client)
100
+
83
101
  ```
84
102
 
85
103
 
@@ -6,11 +6,20 @@ with open("README.md", "r", encoding="utf-8") as f:
6
6
  # with open('requirements.txt', "r", encoding="utf-8") as f:
7
7
  # required = f.read().splitlines()
8
8
 
9
- requires = ['channels==3.0.3','pymongo~=4.11.2','asgiref~=3.8.1','django-cors-headers==4.2.0']
9
+ requires = [
10
+ 'channels==3.0.3',
11
+ 'pymongo~=4.11.2',
12
+ 'asgiref~=3.8.1',
13
+ 'django-cors-headers==4.2.0',
14
+ 'pandas==2.2.3',
15
+ 'openpyxl==3.1.5',
16
+ 'deepmerge~=2.0',
17
+ 'minio==7.2.2'
18
+ ]
10
19
 
11
20
  setup(
12
21
  name="valar", # 包名
13
- version="1.0.18", # 版本号
22
+ version="1.0.20", # 版本号
14
23
  author="LYP", # 作者
15
24
  author_email="liuyinpeng@buaa.edu.cn", # 邮箱
16
25
  description="valar for morghulis", # 简短描述
@@ -0,0 +1,91 @@
1
+ import json
2
+ from io import BytesIO
3
+
4
+ from django.conf import settings
5
+ from minio import Minio
6
+ from urllib3 import HTTPResponse
7
+
8
+ def minio_upload_object(bucket_name, object_name, _bytes):
9
+ client = __get_minio_client__()
10
+ __create_bucket__(bucket_name, client)
11
+ file_data = BytesIO(_bytes)
12
+ file_size = len(_bytes) # file.siz
13
+ client.put_object(bucket_name=bucket_name, object_name=object_name, data=file_data, length=file_size)
14
+ return f'{bucket_name}/{object_name}'
15
+
16
+ def minio_remove_object(bucket_name, object_name):
17
+ client = __get_minio_client__()
18
+ client.remove_object(bucket_name=bucket_name, object_name=object_name)
19
+
20
+ def minio_remove_path(path):
21
+ [bucket_name, object_name] = path.split('/')
22
+ client = __get_minio_client__()
23
+ client.remove_object(bucket_name=bucket_name, object_name=object_name)
24
+
25
+
26
+ def minio_read_object(bucket_name, object_name) -> HTTPResponse:
27
+ client = __get_minio_client__()
28
+ return client.get_object(bucket_name=bucket_name, object_name=object_name)
29
+
30
+
31
+
32
+
33
+
34
+ def __get_minio_client__(bucket_name=None):
35
+ options = settings.MINIO_SETTINGS
36
+ client = Minio(**options)
37
+ if bucket_name:
38
+ __create_bucket__(bucket_name, client)
39
+ return client
40
+
41
+ def __create_bucket__(bucket_name, client=None):
42
+ client = client or __get_minio_client__()
43
+ exists = client.bucket_exists(bucket_name)
44
+ if not exists:
45
+ client.make_bucket(bucket_name)
46
+ policy = generate_policy(bucket_name)
47
+ client.set_bucket_policy(bucket_name, policy)
48
+
49
+
50
+ def get_minio_bucket_name(entity):
51
+ value = f'{settings.BASE_DIR.name}.{entity}'
52
+ bucket_name = value.replace('_','-').lower()
53
+ __create_bucket__(bucket_name)
54
+ return bucket_name
55
+
56
+ def get_minio_object_name(_id, prop, file_name):
57
+ return f"{_id}-{prop}-{file_name}"
58
+
59
+ def generate_policy(bucket_name):
60
+ return json.dumps({
61
+ "Version": "2012-10-17",
62
+ "Statement": [
63
+ {
64
+ "Sid": "",
65
+ "Effect": "Allow",
66
+ "Principal": {"AWS": "*"},
67
+ "Action": "s3:GetBucketLocation",
68
+ "Resource": f"arn:aws:s3:::{bucket_name}"
69
+ },
70
+ {
71
+ "Sid": "",
72
+ "Effect": "Allow",
73
+ "Principal": {"AWS": "*"},
74
+ "Action": "s3:ListBucket",
75
+ "Resource": f"arn:aws:s3:::{bucket_name}"
76
+ },
77
+ {
78
+ "Sid": "",
79
+ "Effect": "Allow",
80
+ "Principal": {"AWS": "*"},
81
+ "Action": "s3:GetObject",
82
+ "Resource": f"arn:aws:s3:::{bucket_name}/*"
83
+ },
84
+ {
85
+ "Sid": "",
86
+ "Effect": "Allow",
87
+ "Principal": {"AWS": "*"},
88
+ "Action": "s3:PutObject",
89
+ "Resource": f"arn:aws:s3:::{bucket_name}/*"
90
+ }
91
+ ]})
@@ -0,0 +1,238 @@
1
+ # Generated by Django 4.2.21 on 2025-05-17 11:07
2
+
3
+ from django.db import migrations, models
4
+ import django.db.models.deletion
5
+
6
+
7
+ class Migration(migrations.Migration):
8
+
9
+ initial = True
10
+
11
+ dependencies = [
12
+ ]
13
+
14
+ operations = [
15
+ migrations.CreateModel(
16
+ name='Meta',
17
+ fields=[
18
+ ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
19
+ ('sort', models.BigIntegerField(null=True, verbose_name='序号')),
20
+ ('create_time', models.DateTimeField(auto_now_add=True, null=True, verbose_name='创建时间')),
21
+ ('modify_time', models.DateTimeField(auto_now=True, null=True, verbose_name='修改时间')),
22
+ ('saved', models.BooleanField(default=False)),
23
+ ('entity', models.CharField(max_length=100, null=True, unique=True, verbose_name='数据源')),
24
+ ('name', models.CharField(max_length=50, null=True, verbose_name='实体别名')),
25
+ ],
26
+ options={
27
+ 'verbose_name': '数据实体',
28
+ },
29
+ ),
30
+ migrations.CreateModel(
31
+ name='MetaFieldTool',
32
+ fields=[
33
+ ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
34
+ ('sort', models.BigIntegerField(null=True, verbose_name='序号')),
35
+ ('create_time', models.DateTimeField(auto_now_add=True, null=True, verbose_name='创建时间')),
36
+ ('modify_time', models.DateTimeField(auto_now=True, null=True, verbose_name='修改时间')),
37
+ ('saved', models.BooleanField(default=False)),
38
+ ('pid', models.IntegerField(default=0, verbose_name='父节点')),
39
+ ('isLeaf', models.BooleanField(default=False, verbose_name='叶子节点')),
40
+ ('icon', models.CharField(max_length=255, null=True, verbose_name='图标')),
41
+ ('name', models.CharField(max_length=255, null=True, verbose_name='名称')),
42
+ ('code', models.CharField(max_length=100, null=True, unique=True, verbose_name='代码')),
43
+ ('format', models.JSONField(default=dict, verbose_name='格式参数')),
44
+ ],
45
+ options={
46
+ 'verbose_name': '元数据字段工具',
47
+ },
48
+ ),
49
+ migrations.CreateModel(
50
+ name='TestM',
51
+ fields=[
52
+ ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
53
+ ('name', models.CharField(max_length=100, verbose_name='<UNK>')),
54
+ ],
55
+ ),
56
+ migrations.CreateModel(
57
+ name='Vala',
58
+ fields=[
59
+ ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
60
+ ('sort', models.BigIntegerField(null=True, verbose_name='序号')),
61
+ ('name', models.CharField(max_length=50, null=True)),
62
+ ('create_time', models.DateTimeField(auto_now_add=True, null=True, verbose_name='创建时间')),
63
+ ('modify_time', models.DateTimeField(auto_now=True, null=True, verbose_name='修改时间')),
64
+ ('saved', models.BooleanField(default=False)),
65
+ ('text_field', models.TextField(null=True, verbose_name='text')),
66
+ ('boolean_field', models.BooleanField(null=True, verbose_name='boolean')),
67
+ ('integer_field', models.IntegerField(null=True, verbose_name='integer')),
68
+ ('float_field', models.FloatField(null=True, verbose_name='float')),
69
+ ('date_field', models.DateField(null=True, verbose_name='date')),
70
+ ('datetime_field', models.DateTimeField(null=True, verbose_name='datetime')),
71
+ ('time_field', models.TimeField(null=True, verbose_name='time')),
72
+ ('json_field', models.JSONField(null=True, verbose_name='json')),
73
+ ('file', models.FileField(null=True, upload_to='', verbose_name='File')),
74
+ ],
75
+ options={
76
+ 'abstract': False,
77
+ },
78
+ ),
79
+ migrations.CreateModel(
80
+ name='ValaTree',
81
+ fields=[
82
+ ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
83
+ ('sort', models.BigIntegerField(null=True, verbose_name='序号')),
84
+ ('name', models.CharField(max_length=50, null=True)),
85
+ ('create_time', models.DateTimeField(auto_now_add=True, null=True, verbose_name='创建时间')),
86
+ ('modify_time', models.DateTimeField(auto_now=True, null=True, verbose_name='修改时间')),
87
+ ('saved', models.BooleanField(default=False)),
88
+ ('pid', models.IntegerField(default=0, verbose_name='父节点')),
89
+ ('isLeaf', models.BooleanField(default=False, verbose_name='叶子节点')),
90
+ ('icon', models.CharField(max_length=255, null=True, verbose_name='图标')),
91
+ ('text', models.TextField(null=True, verbose_name='text')),
92
+ ],
93
+ options={
94
+ 'verbose_name': '树形测试',
95
+ },
96
+ ),
97
+ migrations.CreateModel(
98
+ name='O2O',
99
+ fields=[
100
+ ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
101
+ ('sort', models.BigIntegerField(null=True, verbose_name='序号')),
102
+ ('create_time', models.DateTimeField(auto_now_add=True, null=True, verbose_name='创建时间')),
103
+ ('modify_time', models.DateTimeField(auto_now=True, null=True, verbose_name='修改时间')),
104
+ ('saved', models.BooleanField(default=False)),
105
+ ('name', models.CharField(max_length=100, null=True, verbose_name='name')),
106
+ ('vala', models.OneToOneField(null=True, on_delete=django.db.models.deletion.CASCADE, to='data.vala', verbose_name='vala')),
107
+ ],
108
+ options={
109
+ 'abstract': False,
110
+ },
111
+ ),
112
+ migrations.CreateModel(
113
+ name='MetaView',
114
+ fields=[
115
+ ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
116
+ ('sort', models.BigIntegerField(null=True, verbose_name='序号')),
117
+ ('name', models.CharField(max_length=50, null=True)),
118
+ ('create_time', models.DateTimeField(auto_now_add=True, null=True, verbose_name='创建时间')),
119
+ ('modify_time', models.DateTimeField(auto_now=True, null=True, verbose_name='修改时间')),
120
+ ('saved', models.BooleanField(default=False)),
121
+ ('code', models.CharField(default='default ', max_length=50, verbose_name='类视图')),
122
+ ('view_name', models.CharField(max_length=50, null=True, verbose_name='视图名称')),
123
+ ('form_width', models.IntegerField(default=0, verbose_name='表单宽度')),
124
+ ('form_height', models.IntegerField(default=0, verbose_name='表单高度')),
125
+ ('table_width', models.IntegerField(default=0, verbose_name='表格宽度')),
126
+ ('table_height', models.IntegerField(default=0, verbose_name='表格高度')),
127
+ ('enable', models.BooleanField(default=True, verbose_name='是否启用')),
128
+ ('show_header', models.BooleanField(default=True, verbose_name='展示头部')),
129
+ ('allow_batch', models.BooleanField(default=True, verbose_name='批处理')),
130
+ ('allow_search', models.BooleanField(default=True, verbose_name='检索功能')),
131
+ ('allow_sort', models.BooleanField(default=True, verbose_name='排序功能')),
132
+ ('allow_pop', models.BooleanField(default=True, verbose_name='移动功能')),
133
+ ('allow_insert', models.BooleanField(default=True, verbose_name='新增功能')),
134
+ ('allow_edit', models.BooleanField(default=True, verbose_name='编辑功能')),
135
+ ('allow_remove', models.BooleanField(default=True, verbose_name='删除功能')),
136
+ ('allow_download', models.BooleanField(default=True, verbose_name='下载功能')),
137
+ ('allow_upload', models.BooleanField(default=True, verbose_name='上传功能')),
138
+ ('meta', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='data.meta', verbose_name='元数据')),
139
+ ],
140
+ options={
141
+ 'verbose_name': '数据视图',
142
+ 'unique_together': {('meta', 'code')},
143
+ },
144
+ ),
145
+ migrations.CreateModel(
146
+ name='MetaFieldDomain',
147
+ fields=[
148
+ ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
149
+ ('sort', models.BigIntegerField(null=True, verbose_name='序号')),
150
+ ('create_time', models.DateTimeField(auto_now_add=True, null=True, verbose_name='创建时间')),
151
+ ('modify_time', models.DateTimeField(auto_now=True, null=True, verbose_name='修改时间')),
152
+ ('saved', models.BooleanField(default=False)),
153
+ ('name', models.CharField(max_length=255, null=True, unique=True, verbose_name='名称')),
154
+ ('align', models.CharField(max_length=10, null=True, verbose_name='对齐方式')),
155
+ ('default', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to='data.metafieldtool', verbose_name='默认工具')),
156
+ ('search', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to='data.metafieldtool', verbose_name='搜索工具')),
157
+ ('tools', models.ManyToManyField(to='data.metafieldtool', verbose_name='工具集')),
158
+ ],
159
+ options={
160
+ 'verbose_name': '元数据字段类型',
161
+ },
162
+ ),
163
+ migrations.CreateModel(
164
+ name='MetaField',
165
+ fields=[
166
+ ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
167
+ ('sort', models.BigIntegerField(null=True, verbose_name='序号')),
168
+ ('create_time', models.DateTimeField(auto_now_add=True, null=True, verbose_name='创建时间')),
169
+ ('modify_time', models.DateTimeField(auto_now=True, null=True, verbose_name='修改时间')),
170
+ ('saved', models.BooleanField(default=False)),
171
+ ('prop', models.CharField(max_length=100, verbose_name='字段名称')),
172
+ ('label', models.CharField(max_length=100, verbose_name='字段标签')),
173
+ ('name', models.CharField(max_length=100, verbose_name='字段别名')),
174
+ ('domain', models.CharField(max_length=100, verbose_name='字段类型')),
175
+ ('tool', models.CharField(default='default', max_length=100, verbose_name='工具组件')),
176
+ ('refer', models.JSONField(default=dict, verbose_name='索引')),
177
+ ('format', models.JSONField(default=dict, verbose_name='格式')),
178
+ ('not_null', models.BooleanField(default=False, verbose_name='不为空')),
179
+ ('allow_edit', models.BooleanField(default=True, verbose_name='可编辑')),
180
+ ('allow_sort', models.BooleanField(default=True, verbose_name='可排序')),
181
+ ('allow_search', models.BooleanField(default=True, verbose_name='可搜索')),
182
+ ('allow_download', models.BooleanField(default=True, verbose_name='可下载')),
183
+ ('allow_upload', models.BooleanField(default=False, verbose_name='可上传')),
184
+ ('allow_update', models.BooleanField(default=False, verbose_name='可更新')),
185
+ ('unit', models.CharField(max_length=55, null=True, verbose_name='单位符')),
186
+ ('column_width', models.FloatField(default=0, verbose_name='表头宽度')),
187
+ ('align', models.CharField(default='left', max_length=55, verbose_name='对齐方式')),
188
+ ('fixed', models.CharField(max_length=100, null=True, verbose_name='固定位置')),
189
+ ('header_color', models.CharField(max_length=55, null=True, verbose_name='表头颜色')),
190
+ ('cell_color', models.CharField(max_length=55, null=True, verbose_name='单元颜色')),
191
+ ('edit_on_table', models.BooleanField(default=True, verbose_name='表格编辑')),
192
+ ('hide_on_table', models.BooleanField(default=False, verbose_name='表内隐藏')),
193
+ ('span', models.IntegerField(default=0, verbose_name='表单占位')),
194
+ ('hide_on_form', models.BooleanField(default=False, verbose_name='表单隐藏')),
195
+ ('hide_on_form_edit', models.BooleanField(default=False, verbose_name='编辑隐藏')),
196
+ ('hide_on_form_insert', models.BooleanField(default=False, verbose_name='新增隐藏')),
197
+ ('hide_on_form_branch', models.BooleanField(default=False, verbose_name='分支隐藏')),
198
+ ('hide_on_form_leaf', models.BooleanField(default=False, verbose_name='叶子隐藏')),
199
+ ('view', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='data.metaview', verbose_name='数据视图')),
200
+ ],
201
+ options={
202
+ 'verbose_name': '视图字段',
203
+ },
204
+ ),
205
+ migrations.CreateModel(
206
+ name='M2O',
207
+ fields=[
208
+ ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
209
+ ('sort', models.BigIntegerField(null=True, verbose_name='序号')),
210
+ ('create_time', models.DateTimeField(auto_now_add=True, null=True, verbose_name='创建时间')),
211
+ ('modify_time', models.DateTimeField(auto_now=True, null=True, verbose_name='修改时间')),
212
+ ('saved', models.BooleanField(default=False)),
213
+ ('name', models.CharField(max_length=100, null=True, verbose_name='name')),
214
+ ('vala', models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, to='data.vala', verbose_name='vala')),
215
+ ],
216
+ options={
217
+ 'abstract': False,
218
+ },
219
+ ),
220
+ migrations.CreateModel(
221
+ name='M2M',
222
+ fields=[
223
+ ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
224
+ ('sort', models.BigIntegerField(null=True, verbose_name='序号')),
225
+ ('create_time', models.DateTimeField(auto_now_add=True, null=True, verbose_name='创建时间')),
226
+ ('modify_time', models.DateTimeField(auto_now=True, null=True, verbose_name='修改时间')),
227
+ ('saved', models.BooleanField(default=False)),
228
+ ('pid', models.IntegerField(default=0, verbose_name='父节点')),
229
+ ('isLeaf', models.BooleanField(default=False, verbose_name='叶子节点')),
230
+ ('icon', models.CharField(max_length=255, null=True, verbose_name='图标')),
231
+ ('name', models.CharField(max_length=100, null=True, verbose_name='name')),
232
+ ('valas', models.ManyToManyField(to='data.vala', verbose_name='valas')),
233
+ ],
234
+ options={
235
+ 'abstract': False,
236
+ },
237
+ ),
238
+ ]
@@ -4,6 +4,7 @@ from django.db.models.fields.files import FieldFile
4
4
 
5
5
 
6
6
  class VModel(models.Model):
7
+ objects = models.Manager()
7
8
  sort = models.BigIntegerField(null=True, verbose_name='序号')
8
9
  name = models.CharField(max_length=50, null=True)
9
10
  create_time = models.DateTimeField(auto_now_add=True, null=True, verbose_name='创建时间')
@@ -180,15 +181,23 @@ class MetaFieldTool(VTree):
180
181
  verbose_name = '元数据字段工具'
181
182
  #
182
183
  #
184
+ class TestM(models.Model):
185
+ name = models.CharField(max_length=100, verbose_name='<UNK>')
186
+
183
187
  class MetaFieldDomain(VModel):
184
188
  name = models.CharField(max_length=255, unique=True, null=True, verbose_name='名称')
185
189
  tools = models.ManyToManyField(to=MetaFieldTool, verbose_name='工具集')
186
- default = models.ForeignKey(to=MetaFieldTool, null=True, on_delete=models.SET_NULL, related_name='+',
187
- verbose_name='默认工具')
188
- search = models.ForeignKey(to=MetaFieldTool, null=True, on_delete=models.SET_NULL, related_name='+',
189
- verbose_name='搜索工具')
190
+ default = models.ForeignKey(
191
+ to=MetaFieldTool, null=True,
192
+ on_delete=models.SET_NULL,
193
+ related_name='+',
194
+ verbose_name='默认工具')
195
+ search = models.ForeignKey(
196
+ to=MetaFieldTool, null=True,
197
+ on_delete=models.SET_NULL,
198
+ related_name='+',
199
+ verbose_name='搜索工具')
190
200
  align = models.CharField(max_length=10, null=True, verbose_name='对齐方式')
191
-
192
201
  class Meta:
193
202
  verbose_name = '元数据字段类型'
194
203
 
@@ -222,6 +231,6 @@ class O2O(VModel):
222
231
  name = models.CharField(max_length=100, null=True, verbose_name='name')
223
232
 
224
233
 
225
- class M2M(VModel):
234
+ class M2M(VTree):
226
235
  valas = models.ManyToManyField(to=Vala, verbose_name='valas')
227
236
  name = models.CharField(max_length=100, null=True, verbose_name='name')
@@ -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():
@@ -31,12 +35,13 @@ class OrmDao:
31
35
  if param is None:
32
36
  raise Exception('no entity named %s' % entity)
33
37
  self.model = param[0]
38
+ self.isTree = issubclass(self.model, VTree)
34
39
  self.name: str = param[1]
35
40
  self.manager: Manager = self.model.objects
36
41
  self.meta_fields = {}
37
42
  self.model_fields = {}
38
43
  for field in self.model._meta.get_fields():
39
- _field = load_meta_field(field)
44
+ _field = load_meta_field(field, self.isTree)
40
45
  prop = _field['prop']
41
46
  self.model_fields[prop] = field
42
47
  self.meta_fields[prop] = _field
@@ -45,7 +50,6 @@ class OrmDao:
45
50
  def tree(self, query: Query, root_id = 0):
46
51
  all_set, _ = self.find_many(Query())
47
52
  includes, excludes = query.orm_conditions()
48
- print(root_id)
49
53
  if not len(includes) + len(excludes) + root_id:
50
54
  return all_set
51
55
  values = all_set.values('id','pid')
@@ -62,6 +66,19 @@ class OrmDao:
62
66
  id_set.update(route)
63
67
  return all_set.filter(id__in=id_set).order_by('-sort')
64
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
+
65
82
  def save_one(self, item):
66
83
  _item = detach_props(item, self.meta_fields.values())
67
84
  _id = item.get('id',0)
@@ -69,6 +86,7 @@ class OrmDao:
69
86
  if len(query_set):
70
87
  del item['id']
71
88
  item['modify_time'] = datetime.datetime.now()
89
+ self.__check_remove_file__(query_set,item)
72
90
  query_set.update(**item)
73
91
  bean = query_set.first()
74
92
  else:
@@ -79,13 +97,18 @@ class OrmDao:
79
97
  return bean
80
98
 
81
99
  def update_many(self, query: Query, template):
82
- self.find_many(query).update(**template)
100
+ query_set, total = self.find_many(query)
101
+ query_set.update(**template)
83
102
 
84
103
  def delete_one(self, _id):
85
- 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()
86
107
 
87
108
  def delete_many(self, query: Query):
88
- 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()
89
112
 
90
113
  def find_one(self, _id):
91
114
  return self.manager.filter(id=_id).first()
@@ -104,7 +127,9 @@ class OrmDao:
104
127
  omit = [ 'id', 'saved', 'sort', 'create_time', 'modify_time']
105
128
  fields = [ self.meta_fields[prop] for prop in self.meta_fields if prop not in omit]
106
129
  view = load_view(self.entity, code, self.name, fields)
107
- return load_meta(view)
130
+ _view = load_meta(view)
131
+ _view['isTree'] = self.isTree
132
+ return _view
108
133
 
109
134
 
110
135