valar 1.3.17__tar.gz → 1.3.24__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.
Files changed (65) hide show
  1. {valar-1.3.17/src/valar.egg-info → valar-1.3.24}/PKG-INFO +41 -18
  2. {valar-1.3.17 → valar-1.3.24}/README.md +39 -17
  3. {valar-1.3.17 → valar-1.3.24}/setup.py +19 -5
  4. {valar-1.3.17 → valar-1.3.24}/src/valar/auth/Authentication.py +2 -1
  5. {valar-1.3.17 → valar-1.3.24}/src/valar/channels/consumer.py +11 -0
  6. {valar-1.3.17 → valar-1.3.24}/src/valar/channels/executer.py +8 -2
  7. {valar-1.3.17 → valar-1.3.24}/src/valar/channels/sender.py +14 -8
  8. {valar-1.3.17 → valar-1.3.24}/src/valar/dao/defaults/field_keys_default.py +1 -1
  9. {valar-1.3.17 → valar-1.3.24}/src/valar/dao/defaults/field_values_default.py +5 -7
  10. {valar-1.3.17 → valar-1.3.24}/src/valar/dao/meta.py +1 -17
  11. {valar-1.3.17 → valar-1.3.24}/src/valar/dao/orm_dao.py +6 -4
  12. {valar-1.3.17 → valar-1.3.24}/src/valar/migrations/0001_initial.py +20 -2
  13. {valar-1.3.17 → valar-1.3.24}/src/valar/models/core.py +2 -3
  14. {valar-1.3.17 → valar-1.3.24}/src/valar/models/meta.py +0 -1
  15. {valar-1.3.17 → valar-1.3.24}/src/valar/urls.py +4 -1
  16. {valar-1.3.17 → valar-1.3.24}/src/valar/views/auth.py +7 -8
  17. valar-1.3.24/src/valar/views/handler.py +48 -0
  18. {valar-1.3.17 → valar-1.3.24}/src/valar/views/meta.py +24 -12
  19. {valar-1.3.17 → valar-1.3.24}/src/valar/views/password.py +1 -1
  20. {valar-1.3.17 → valar-1.3.24}/src/valar/views/rest.py +22 -2
  21. {valar-1.3.17 → valar-1.3.24/src/valar.egg-info}/PKG-INFO +41 -18
  22. {valar-1.3.17 → valar-1.3.24}/src/valar.egg-info/SOURCES.txt +0 -3
  23. {valar-1.3.17 → valar-1.3.24}/src/valar.egg-info/requires.txt +1 -0
  24. valar-1.3.17/src/valar/migrations/0002_location.py +0 -32
  25. valar-1.3.17/src/valar/migrations/0003_location_code_location_name_cn_location_name_en.py +0 -28
  26. valar-1.3.17/src/valar/migrations/0004_remove_location_icon_remove_location_isleaf_and_more.py +0 -25
  27. valar-1.3.17/src/valar/views/handler.py +0 -53
  28. {valar-1.3.17 → valar-1.3.24}/LICENSE +0 -0
  29. {valar-1.3.17 → valar-1.3.24}/MANIFEST.in +0 -0
  30. {valar-1.3.17 → valar-1.3.24}/setup.cfg +0 -0
  31. {valar-1.3.17 → valar-1.3.24}/src/valar/__init__.py +0 -0
  32. {valar-1.3.17 → valar-1.3.24}/src/valar/apps.py +0 -0
  33. {valar-1.3.17 → valar-1.3.24}/src/valar/auth/Middleware.py +0 -0
  34. {valar-1.3.17 → valar-1.3.24}/src/valar/auth/__init__.py +0 -0
  35. {valar-1.3.17 → valar-1.3.24}/src/valar/channels/__init__.py +0 -0
  36. {valar-1.3.17 → valar-1.3.24}/src/valar/channels/counter.py +0 -0
  37. {valar-1.3.17 → valar-1.3.24}/src/valar/channels/mapping.py +0 -0
  38. {valar-1.3.17 → valar-1.3.24}/src/valar/channels/views.py +0 -0
  39. {valar-1.3.17 → valar-1.3.24}/src/valar/classes/__init__.py +0 -0
  40. {valar-1.3.17 → valar-1.3.24}/src/valar/classes/app_mixins/__init__.py +0 -0
  41. {valar-1.3.17 → valar-1.3.24}/src/valar/classes/app_mixins/auto_migration_mixin.py +0 -0
  42. {valar-1.3.17 → valar-1.3.24}/src/valar/classes/app_mixins/auto_urlpatterns_mixin.py +0 -0
  43. {valar-1.3.17 → valar-1.3.24}/src/valar/classes/singleton_meta.py +0 -0
  44. {valar-1.3.17 → valar-1.3.24}/src/valar/classes/valar_minio.py +0 -0
  45. {valar-1.3.17 → valar-1.3.24}/src/valar/classes/valar_response.py +0 -0
  46. {valar-1.3.17 → valar-1.3.24}/src/valar/dao/__init__.py +0 -0
  47. {valar-1.3.17 → valar-1.3.24}/src/valar/dao/abstract.py +0 -0
  48. {valar-1.3.17 → valar-1.3.24}/src/valar/dao/defaults/__init__.py +0 -0
  49. {valar-1.3.17 → valar-1.3.24}/src/valar/dao/defaults/view_defaults.py +0 -0
  50. {valar-1.3.17 → valar-1.3.24}/src/valar/dao/engine.py +0 -0
  51. {valar-1.3.17 → valar-1.3.24}/src/valar/dao/frame.py +0 -0
  52. {valar-1.3.17 → valar-1.3.24}/src/valar/dao/mon_dao.py +0 -0
  53. {valar-1.3.17 → valar-1.3.24}/src/valar/dao/mon_field.py +0 -0
  54. {valar-1.3.17 → valar-1.3.24}/src/valar/dao/orm_field.py +0 -0
  55. {valar-1.3.17 → valar-1.3.24}/src/valar/dao/query.py +0 -0
  56. {valar-1.3.17 → valar-1.3.24}/src/valar/migrations/__init__.py +0 -0
  57. {valar-1.3.17 → valar-1.3.24}/src/valar/models/__init__.py +0 -0
  58. {valar-1.3.17 → valar-1.3.24}/src/valar/models/auth.py +0 -0
  59. {valar-1.3.17 → valar-1.3.24}/src/valar/models/frame.py +0 -0
  60. {valar-1.3.17 → valar-1.3.24}/src/valar/models/indicator.py +0 -0
  61. {valar-1.3.17 → valar-1.3.24}/src/valar/models/test.py +0 -0
  62. {valar-1.3.17 → valar-1.3.24}/src/valar/views/__init__.py +0 -0
  63. {valar-1.3.17 → valar-1.3.24}/src/valar/views/file.py +0 -0
  64. {valar-1.3.17 → valar-1.3.24}/src/valar.egg-info/dependency_links.txt +0 -0
  65. {valar-1.3.17 → valar-1.3.24}/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.3.17
3
+ Version: 1.3.24
4
4
  Summary: valar for morghulis
5
5
  Home-page: https://gitee.com/GRIFFIN120/valar_dev
6
6
  Author: LYP
@@ -8,6 +8,7 @@ Author-email: liuyinpeng@buaa.edu.cn
8
8
  Requires-Python: >=3.9
9
9
  Description-Content-Type: text/markdown
10
10
  License-File: LICENSE
11
+ Requires-Dist: autobahn==24.4.2
11
12
  Requires-Dist: channels==3.0.3
12
13
  Requires-Dist: pymongo~=4.11.2
13
14
  Requires-Dist: asgiref~=3.8.1
@@ -45,7 +46,7 @@ pip install valar
45
46
  - asgi.py
46
47
  - urls.py
47
48
 
48
- ## 2.1 settings.py
49
+ ## 2.1 settings.py and ___init__.py
49
50
 
50
51
  ```python
51
52
  from pathlib import Path
@@ -61,8 +62,16 @@ SECRET_KEY = 'django-insecure-of@tfouoq^_f$l!yki#m=6j7)@&kjri$1_$!mca-=%7=+@f@5^
61
62
 
62
63
  DATABASES = {
63
64
  'default': {
64
- 'ENGINE': 'django.db.backends.sqlite3',
65
- 'NAME': BASE_DIR / 'db.sqlite3',
65
+ 'ENGINE': 'django.db.backends.mysql', # 使用 MySQL
66
+ 'NAME': 'vm_ets', # 数据库名
67
+ 'USER': 'root', # 用户名
68
+ 'PASSWORD': password, # 密码
69
+ 'HOST': 'localhost', # 数据库地址,本机用127.0.0.1
70
+ 'PORT': '3306', # MySQL端口,默认3306
71
+ 'OPTIONS': {
72
+ 'connect_timeout': 5, # 默认10秒,可以缩短
73
+ 'charset': 'utf8mb4',
74
+ }
66
75
  }
67
76
  }
68
77
 
@@ -105,44 +114,58 @@ DATA_UPLOAD_MAX_MEMORY_SIZE = 1024 * 1024 * 100
105
114
  """ Valar Options """
106
115
 
107
116
  HANDLER_MAPPING = "%s.urls.channel_mapping" % BASE_APP
108
- MONGO_URI = 'mongodb://username:password@host:27017'
109
- MINIO_URL = "s3://username:password@host:9000"
110
- MINIO_ROOT = "https://host:9001"
117
+ MONGO_URI = f'mongodb://root:{password}@{host}:27017/'
118
+ MINIO_URL = f"s3://admin:{password}@{host}:9001"
119
+ MINIO_ROOT = f"http://{host}:9001"
111
120
 
112
121
  """ Email Options """
122
+
113
123
  EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'
114
- EMAIL_HOST = 'xxx.xx.xx.xx'
115
- EMAIL_PORT = 465
116
- EMAIL_DOMAIN = 'http://xx.xx.xx'
117
- EMAIL_HOST_USER = "xxx@xx.xx.xx"
118
- EMAIL_HOST_PASSWORD = '*******'
119
- EMAIL_USE_TLS = False
120
- EMAIL_USE_SSL = True
124
+ EMAIL_HOST = 'smtp.126.com'
125
+ EMAIL_PORT = 25
126
+ EMAIL_HOST_USER = "xxxx@126.com"
127
+ EMAIL_HOST_PASSWORD = 'CGiKQh5FyQyupQYA'
128
+ ```
129
+
130
+ ```python
131
+ import pymysql
132
+
133
+ pymysql.install_as_MySQLdb()
134
+
121
135
  ```
122
136
 
123
137
  ## 2.2 asgi.py
124
138
 
125
139
  ```python
140
+ import os
141
+ from pathlib import Path
142
+
126
143
  from django.core.asgi import get_asgi_application
127
144
  from channels.routing import ProtocolTypeRouter, URLRouter
128
145
  from django.urls import re_path
129
146
 
130
147
  from valar.channels.consumer import ValarConsumer
131
148
 
149
+ os.environ.setdefault('DJANGO_SETTINGS_MODULE', '%s.settings' % Path(__file__).resolve().parent.parent.name)
132
150
  application = ProtocolTypeRouter({
133
151
  'http': get_asgi_application(),
134
152
  'websocket': URLRouter([
135
153
  re_path(r'(?P<client>\w+)/$', ValarConsumer.as_asgi()),
136
154
  ])
137
155
  })
138
-
139
-
140
156
  ```
141
157
 
142
158
  ## 2.3 urls.py
143
159
 
144
- - no need to provide urls for Valar, Valar will auto set urlpatterns for Morghulis (
145
- see https://www.npmjs.com/package/morghulis)
160
+ ```python
161
+ from django.urls import path, include
162
+
163
+ urlpatterns = [
164
+ path('valar/', include('valar.urls')),
165
+ ]
166
+
167
+ ```
168
+
146
169
  - go to section 4 to see how to register channel handlers (a Vue - Django async communication tool) in urls.
147
170
 
148
171
  # 3. migrate
@@ -15,7 +15,7 @@ pip install valar
15
15
  - asgi.py
16
16
  - urls.py
17
17
 
18
- ## 2.1 settings.py
18
+ ## 2.1 settings.py and ___init__.py
19
19
 
20
20
  ```python
21
21
  from pathlib import Path
@@ -31,8 +31,16 @@ SECRET_KEY = 'django-insecure-of@tfouoq^_f$l!yki#m=6j7)@&kjri$1_$!mca-=%7=+@f@5^
31
31
 
32
32
  DATABASES = {
33
33
  'default': {
34
- 'ENGINE': 'django.db.backends.sqlite3',
35
- 'NAME': BASE_DIR / 'db.sqlite3',
34
+ 'ENGINE': 'django.db.backends.mysql', # 使用 MySQL
35
+ 'NAME': 'vm_ets', # 数据库名
36
+ 'USER': 'root', # 用户名
37
+ 'PASSWORD': password, # 密码
38
+ 'HOST': 'localhost', # 数据库地址,本机用127.0.0.1
39
+ 'PORT': '3306', # MySQL端口,默认3306
40
+ 'OPTIONS': {
41
+ 'connect_timeout': 5, # 默认10秒,可以缩短
42
+ 'charset': 'utf8mb4',
43
+ }
36
44
  }
37
45
  }
38
46
 
@@ -75,44 +83,58 @@ DATA_UPLOAD_MAX_MEMORY_SIZE = 1024 * 1024 * 100
75
83
  """ Valar Options """
76
84
 
77
85
  HANDLER_MAPPING = "%s.urls.channel_mapping" % BASE_APP
78
- MONGO_URI = 'mongodb://username:password@host:27017'
79
- MINIO_URL = "s3://username:password@host:9000"
80
- MINIO_ROOT = "https://host:9001"
86
+ MONGO_URI = f'mongodb://root:{password}@{host}:27017/'
87
+ MINIO_URL = f"s3://admin:{password}@{host}:9001"
88
+ MINIO_ROOT = f"http://{host}:9001"
81
89
 
82
90
  """ Email Options """
91
+
83
92
  EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'
84
- EMAIL_HOST = 'xxx.xx.xx.xx'
85
- EMAIL_PORT = 465
86
- EMAIL_DOMAIN = 'http://xx.xx.xx'
87
- EMAIL_HOST_USER = "xxx@xx.xx.xx"
88
- EMAIL_HOST_PASSWORD = '*******'
89
- EMAIL_USE_TLS = False
90
- EMAIL_USE_SSL = True
93
+ EMAIL_HOST = 'smtp.126.com'
94
+ EMAIL_PORT = 25
95
+ EMAIL_HOST_USER = "xxxx@126.com"
96
+ EMAIL_HOST_PASSWORD = 'CGiKQh5FyQyupQYA'
97
+ ```
98
+
99
+ ```python
100
+ import pymysql
101
+
102
+ pymysql.install_as_MySQLdb()
103
+
91
104
  ```
92
105
 
93
106
  ## 2.2 asgi.py
94
107
 
95
108
  ```python
109
+ import os
110
+ from pathlib import Path
111
+
96
112
  from django.core.asgi import get_asgi_application
97
113
  from channels.routing import ProtocolTypeRouter, URLRouter
98
114
  from django.urls import re_path
99
115
 
100
116
  from valar.channels.consumer import ValarConsumer
101
117
 
118
+ os.environ.setdefault('DJANGO_SETTINGS_MODULE', '%s.settings' % Path(__file__).resolve().parent.parent.name)
102
119
  application = ProtocolTypeRouter({
103
120
  'http': get_asgi_application(),
104
121
  'websocket': URLRouter([
105
122
  re_path(r'(?P<client>\w+)/$', ValarConsumer.as_asgi()),
106
123
  ])
107
124
  })
108
-
109
-
110
125
  ```
111
126
 
112
127
  ## 2.3 urls.py
113
128
 
114
- - no need to provide urls for Valar, Valar will auto set urlpatterns for Morghulis (
115
- see https://www.npmjs.com/package/morghulis)
129
+ ```python
130
+ from django.urls import path, include
131
+
132
+ urlpatterns = [
133
+ path('valar/', include('valar.urls')),
134
+ ]
135
+
136
+ ```
137
+
116
138
  - go to section 4 to see how to register channel handlers (a Vue - Django async communication tool) in urls.
117
139
 
118
140
  # 3. migrate
@@ -1,11 +1,16 @@
1
1
  from setuptools import setup, find_packages
2
+ from setuptools.command.build_py import build_py as _build_py
3
+ import pathlib, os
4
+ from setuptools import Command
5
+ from typing import Dict, Type
2
6
 
3
7
  with open("README.md", "r", encoding="utf-8") as f:
4
8
  long_description = f.read()
5
9
 
6
- version = "1.3.17"
10
+ version = "1.3.24"
7
11
 
8
12
  requires = [
13
+ 'autobahn==24.4.2',
9
14
  'channels==3.0.3',
10
15
  'pymongo~=4.11.2',
11
16
  'asgiref~=3.8.1',
@@ -18,6 +23,17 @@ requires = [
18
23
  'PyMySQL~=1.1.2'
19
24
  ]
20
25
 
26
+
27
+ class BuildBy(_build_py, Command):
28
+ def run(self):
29
+ base = pathlib.Path("src")
30
+ for path in base.rglob("migrations/*.py"):
31
+ if path.name != "__init__.py":
32
+ print(f"🧹 Removing migration file: {path}")
33
+ os.remove(path)
34
+ super().run()
35
+
36
+
21
37
  setup(
22
38
  name="valar", # 包名
23
39
  version=version, # 版本号
@@ -31,9 +47,7 @@ setup(
31
47
  package_dir={"": "src"}, # 设置src目录为根目录
32
48
  python_requires=">=3.9", # 项目支持的Python版本
33
49
  install_requires=requires, # 项目必须的依赖
34
- include_package_data=True,
35
- exclude_package_data={
36
- "": ["migrations/*.py", "*/migrations/*.py"], # 排除所有迁移脚本
37
- },
50
+ include_package_data=False,
51
+ cmdclass={"build_py": BuildBy},
38
52
 
39
53
  )
@@ -1,5 +1,6 @@
1
1
  import jwt
2
2
  from django.conf import settings
3
+ from django.http import HttpRequest
3
4
 
4
5
  from ..classes.valar_response import ValarResponse
5
6
 
@@ -11,7 +12,7 @@ class ValaAuthError(Exception):
11
12
 
12
13
 
13
14
  def auth_required(view_func):
14
- def wrapper(request, *args, **kwargs):
15
+ def wrapper(request: HttpRequest, *args, **kwargs):
15
16
  try:
16
17
  payload = valid_request_token(request)
17
18
  request.user_id = payload["user_id"]
@@ -1,4 +1,5 @@
1
1
  from channels.generic.websocket import AsyncJsonWebsocketConsumer
2
+ from django.conf import settings
2
3
 
3
4
  VALAR_CHANNEL_GROUP = 'VALAR'
4
5
 
@@ -15,6 +16,10 @@ class ValarConsumer(AsyncJsonWebsocketConsumer):
15
16
  self.client = params.get('client')
16
17
  await self.channel_layer.group_add(VALAR_CHANNEL_GROUP, self.channel_name)
17
18
  await self.accept()
19
+ await self.send_json({
20
+ "tag": 'system',
21
+ "minio": getattr(settings, 'MINIO_ROOT') if hasattr(settings, 'MINIO_ROOT') else '/minio'
22
+ })
18
23
 
19
24
  async def disconnect(self, code):
20
25
  await self.channel_layer.group_discard(VALAR_CHANNEL_GROUP, self.channel_name)
@@ -30,17 +35,23 @@ class ValarConsumer(AsyncJsonWebsocketConsumer):
30
35
  async def user_emit(self, event):
31
36
  users: list = event.get('users', [])
32
37
  data = event.get('data', {})
38
+ tag = event.get('tag')
39
+ data.update({'tag': tag})
33
40
  if self.uid in users:
34
41
  await self.send_json(data)
35
42
 
36
43
  async def client_emit(self, event):
37
44
  clients: list = event.get('clients', [])
38
45
  data = event.get('data', {})
46
+ tag = event.get('tag')
47
+ data.update({'tag': tag})
39
48
  if self.client in clients:
40
49
  await self.send_json(data)
41
50
 
42
51
  async def broadcast_emit(self, event):
43
52
  data = event.get('data', {})
53
+ tag = event.get('tag')
54
+ data.update({'tag': tag})
44
55
  await self.send_json(data)
45
56
 
46
57
  async def register_emit(self, event):
@@ -1,6 +1,7 @@
1
1
  import asyncio
2
2
 
3
3
  from ..channels.sender import ValarChannelSender
4
+ import traceback
4
5
 
5
6
 
6
7
  async def execute_channel(method, sender: ValarChannelSender):
@@ -10,5 +11,10 @@ async def execute_channel(method, sender: ValarChannelSender):
10
11
 
11
12
  def __execute__(method, sender: ValarChannelSender):
12
13
  sender.start()
13
- method(sender)
14
- sender.stop()
14
+ try:
15
+ response = method(sender)
16
+ sender.done(response)
17
+ sender.stop()
18
+ except Exception as e:
19
+ traceback.print_exc()
20
+ sender.error(str(e))
@@ -18,20 +18,21 @@ class Channel:
18
18
  self.url = body.get('url')
19
19
  self.auth = body.get('auth')
20
20
  self.broadcast = body.get('broadcast')
21
+
21
22
  self.data = body.get('data')
22
- self.resolve = body.get('resolve')
23
+ self.token = body.get('token')
23
24
 
24
- def to_dict(self, status, payload):
25
+ def to_dict(self, resolver, payload):
25
26
  data = {
26
27
  'handler': self.handler,
27
28
  'url': self.url,
28
29
  'auth': self.auth,
29
30
  'broadcast': self.broadcast,
30
- 'resolve': self.resolve,
31
+ 'token': self.token,
31
32
  'timestamp': datetime.now().timestamp()
32
33
  }
33
- if status:
34
- data.update({'status': status})
34
+ if resolver:
35
+ data.update({'resolver': resolver})
35
36
  if payload:
36
37
  data.update({'payload': payload})
37
38
  return data
@@ -86,17 +87,22 @@ class ValarChannelSender(Sender):
86
87
  with self.__lock__:
87
88
  self.__payload__ = payload
88
89
 
89
- def done(self, payload):
90
- self.__emit__('done', payload)
90
+ def done(self, response):
91
+ self.__emit__('done', response)
91
92
 
92
93
  def error(self, payload):
93
94
  self.__emit__('error', payload)
95
+ if self.__thread__:
96
+ self.__thread__.join()
97
+ self.__thread__ = None
94
98
 
95
99
  def __emit__(self, status='proceed', data=None):
96
100
  scope = 'broadcast' if self.__channel__.broadcast else 'client'
101
+ pay = self.__payload__ if status == 'proceed' else data
97
102
  body = {
98
103
  'type': f'{scope}.emit',
99
- 'data': self.__channel__.to_dict(status, data or self.__payload__),
104
+ 'tag': 'batch',
105
+ 'data': self.__channel__.to_dict(status, pay),
100
106
  'clients': [self.client],
101
107
  'users': []
102
108
  }
@@ -4,7 +4,7 @@ meta_field_key_defaults = {
4
4
  },
5
5
  'valar.MetaView': {
6
6
  'list': ('pick', ['code', 'name']),
7
- 'core': ('pick', ['name', 'enable', 'lock', 'property']),
7
+ 'core': ('pick', ['name', 'enable', 'lock']),
8
8
  'style': ('pick', ['form_width', 'form_height', 'table_width', 'table_height']),
9
9
  'rest': ('pick',
10
10
  ['allow_search', 'allow_order', 'allow_insert', 'allow_remove', 'allow_download', 'allow_upload']),
@@ -27,11 +27,8 @@ meta_field_value_defaults = {
27
27
  },
28
28
  "core": {
29
29
  "name": {
30
- 'span': 16
30
+ 'span': 24
31
31
  },
32
- "enable": {
33
- "span": 8
34
- }
35
32
  }
36
33
  },
37
34
  'valar.MetaFieldDomain': {
@@ -104,7 +101,6 @@ meta_field_value_defaults = {
104
101
  },
105
102
  "tool": {
106
103
  'column_width': 100,
107
- 'span': 24,
108
104
  'tool': 'tree',
109
105
  'refer': {
110
106
  'entity': 'valar.MetaFieldTool',
@@ -119,11 +115,13 @@ meta_field_value_defaults = {
119
115
  },
120
116
  "refer": {
121
117
  'allow_edit': False,
122
- 'column_width': 80
118
+ 'column_width': 80,
119
+ "hide_on_form": True
123
120
  },
124
121
  "format": {
125
122
  'allow_edit': False,
126
- 'column_width': 80
123
+ 'column_width': 80,
124
+ "hide_on_form": True
127
125
  },
128
126
  'header_color': {
129
127
  'tool': 'color',
@@ -1,7 +1,6 @@
1
1
  import copy
2
2
 
3
3
  from deepmerge import always_merger
4
- from django.conf import settings
5
4
 
6
5
  from ..dao.defaults.field_keys_default import meta_field_key_defaults
7
6
  from ..dao.defaults.field_values_default import meta_field_value_defaults
@@ -11,7 +10,6 @@ from ..dao.frame import meta_field_tool_mapping
11
10
  from ..dao.mon_dao import MonDao
12
11
  from ..dao.orm_dao import OrmDao
13
12
  from ..dao.orm_field import column_width
14
- from ..models.frame import MetaFieldDomain
15
13
  from ..models.meta import Meta, MetaView
16
14
 
17
15
 
@@ -56,18 +54,15 @@ class ValarMeta:
56
54
  name, entity = meta['name'], meta['entity']
57
55
  fields = self.view.metafield_set.all().order_by('-sort')
58
56
  _fields = {}
59
- _minio = settings.MINIO_ROOT if hasattr(settings, 'MINIO_ROOT') else '/minio'
60
57
  for field in fields:
61
- _field = field.json(entity=entity, code=self.code, db='orm', minio=_minio)
58
+ _field = field.json(entity=entity, code=self.code, db='orm')
62
59
  align, tool, width, domain = _field['align'], _field['tool'], _field['column_width'], _field['domain']
63
60
  _field['align'] = align if align else meta_field_tool_mapping.get(tool, 'left')
64
61
  _field['column_width'] = width if width else column_width(domain, tool)
65
62
 
66
63
  _fields[field.prop] = _field
67
64
 
68
- _minio = settings.MINIO_ROOT if hasattr(settings, 'MINIO_ROOT') else '/minio'
69
65
  _view.update({
70
- '$minio': _minio,
71
66
  '$db': 'orm',
72
67
  '$entity': entity,
73
68
  '$code': self.code,
@@ -87,17 +82,6 @@ class ValarMeta:
87
82
  view_item.update({
88
83
  "name": self.code.upper(),
89
84
  "saved": True,
90
- "property": {
91
- "value": "id",
92
- "label": "name",
93
- "display": "id",
94
- "sort": "sort",
95
- "disabled": "disabled",
96
- "isLeaf": "isLeaf",
97
- "icon": "icon",
98
- "children": "children",
99
- "pid": "pid",
100
- }
101
85
  })
102
86
  values = always_merger.merge(default_values, code_values)
103
87
  view_item.update(values)
@@ -1,7 +1,7 @@
1
1
  import datetime
2
2
  import json
3
+ from urllib.parse import quote
3
4
 
4
- from django.conf import settings
5
5
  from django.core.paginator import Paginator
6
6
  from django.db.models.options import Options
7
7
 
@@ -15,7 +15,6 @@ from django.db.models.fields.files import FieldFile
15
15
  from django.forms import FileField
16
16
 
17
17
  from ..dao.orm_field import OrmField
18
- from ..models.auth import Account
19
18
  from ..models.core import VTree, VModel
20
19
  from ..models.meta import MetaField
21
20
 
@@ -52,7 +51,6 @@ class OrmDao(AbstractDao):
52
51
  return list(query_set.values(*props))
53
52
 
54
53
  def insert_one(self, item):
55
- print(item)
56
54
  return self.__save__(item)
57
55
 
58
56
  def update_one(self, item):
@@ -320,6 +318,7 @@ def __get_custom_props__(entity, code='default'):
320
318
  def __set_simple_values__(fields, values):
321
319
  date_props_mapping = {}
322
320
  json_props = []
321
+ file_props = []
323
322
  for field in fields:
324
323
  if isinstance(field, OrmField):
325
324
  prop = field.prop
@@ -331,13 +330,16 @@ def __set_simple_values__(fields, values):
331
330
  date_props_mapping[prop] = __data_props_formatting__[domain]
332
331
  elif domain == 'JSONField':
333
332
  json_props.append(prop)
333
+ elif domain == 'FileField':
334
+ file_props.append(prop)
334
335
  for row in values:
335
- row['$minio'] = settings.MINIO_ROOT
336
336
  for prop, formating in date_props_mapping.items():
337
337
  if row.get(prop):
338
338
  row[prop] = row[prop].strftime(formating)
339
339
  for prop in json_props:
340
340
  row[prop] = json.loads(row[prop]) if type(row[prop]) is str else row[prop]
341
+ for prop in file_props:
342
+ row[prop] = quote(row[prop], safe=":/")
341
343
 
342
344
  # def fun(field): return type(field).__name__ not in __referred_domains__ and field.name not in __omit_field_props__
343
345
  #
@@ -1,4 +1,4 @@
1
- # Generated by Django 4.2.24 on 2025-09-21 19:05
1
+ # Generated by Django 4.2.24 on 2025-10-19 15:26
2
2
 
3
3
  from django.db import migrations, models
4
4
  import django.db.models.deletion
@@ -30,6 +30,25 @@ class Migration(migrations.Migration):
30
30
  'verbose_name': '指标集',
31
31
  },
32
32
  ),
33
+ migrations.CreateModel(
34
+ name='Location',
35
+ fields=[
36
+ ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
37
+ ('sort', models.BigIntegerField(null=True, verbose_name='序号')),
38
+ ('create_time', models.DateTimeField(auto_now_add=True, null=True, verbose_name='创建时间')),
39
+ ('modify_time', models.DateTimeField(auto_now=True, null=True, verbose_name='修改时间')),
40
+ ('disabled', models.BooleanField(default=False, verbose_name='禁用')),
41
+ ('saved', models.BooleanField(default=False, verbose_name='已保存')),
42
+ ('scope', models.CharField(max_length=100, null=True)),
43
+ ('code', models.CharField(max_length=100, null=True)),
44
+ ('name', models.CharField(max_length=100, null=True)),
45
+ ('name_cn', models.CharField(max_length=100, null=True)),
46
+ ('name_en', models.CharField(max_length=100, null=True)),
47
+ ],
48
+ options={
49
+ 'verbose_name': '指标集',
50
+ },
51
+ ),
33
52
  migrations.CreateModel(
34
53
  name='Meta',
35
54
  fields=[
@@ -184,7 +203,6 @@ class Migration(migrations.Migration):
184
203
  ('modify_time', models.DateTimeField(auto_now=True, null=True, verbose_name='修改时间')),
185
204
  ('disabled', models.BooleanField(default=False, verbose_name='禁用')),
186
205
  ('saved', models.BooleanField(default=False, verbose_name='已保存')),
187
- ('property', models.JSONField(default=dict, verbose_name='属性')),
188
206
  ('code', models.CharField(default='default ', max_length=50, verbose_name='类视图')),
189
207
  ('name', models.CharField(max_length=50, null=True, verbose_name='视图名称')),
190
208
  ('lock', models.BooleanField(default=False, verbose_name='锁定元数据')),
@@ -1,7 +1,7 @@
1
1
  import json
2
+ from urllib.parse import quote
2
3
 
3
4
  from django.apps import AppConfig
4
- from django.conf import settings
5
5
  from django.db import models
6
6
  from django.db.models import ManyToOneRel, OneToOneRel, ManyToManyRel, ManyToManyField, UUIDField, FileField, \
7
7
  ForeignKey, OneToOneField, DateField, TimeField, DateTimeField, BigAutoField, JSONField
@@ -49,7 +49,7 @@ class VModel(models.Model):
49
49
  elif domain in [TimeField]:
50
50
  value = value.strftime('%H:%M:%S')
51
51
  elif domain in [FileField]:
52
- value = value.name
52
+ value = quote(value.name, safe=":/")
53
53
  elif domain in [BigAutoField]:
54
54
  value = value
55
55
  data[prop] = value
@@ -76,7 +76,6 @@ class VModel(models.Model):
76
76
  _set = getattr(self, accessor).all().order_by('-sort')
77
77
  data[prop] = [item.id for item in _set]
78
78
  data[f'{prop}_set'] = [item.json() for item in _set]
79
- data['$minio'] = settings.MINIO_ROOT
80
79
  return data
81
80
 
82
81
 
@@ -15,7 +15,6 @@ class Meta(VModel):
15
15
 
16
16
  class MetaView(VModel):
17
17
  meta = models.ForeignKey('Meta', on_delete=models.CASCADE, verbose_name='元数据')
18
- property = models.JSONField(default=dict, verbose_name='属性')
19
18
 
20
19
  code = models.CharField(max_length=50, verbose_name='类视图', default='default ')
21
20
  name = models.CharField(max_length=50, verbose_name='视图名称', null=True)
@@ -5,6 +5,9 @@ from django.urls import path, re_path
5
5
  urlpatterns = [
6
6
  path('socket/<str:handler>', handel_channel),
7
7
  path('batch', rest.batch),
8
+
9
+ path('<str:db>/<str:entity>/save_many', rest.save_many),
10
+ path('<str:db>/<str:entity>/delete_many', rest.delete_many),
8
11
  path('<str:db>/<str:entity>/save_one', rest.save_one),
9
12
  path('<str:db>/<str:entity>/insert_one', rest.insert_one),
10
13
  path('<str:db>/<str:entity>/delete_one', rest.delete_one),
@@ -20,7 +23,7 @@ urlpatterns = [
20
23
  path('load_customs', meta.load_customs),
21
24
  path('get_fields', meta.get_fields),
22
25
  path('save_custom', meta.save_custom),
23
- path('upload_mapping', meta.upload_mapping),
26
+ path('upload_frame', meta.upload_frame),
24
27
 
25
28
  path('<str:db>/<str:entity>/save_file', file.save_file),
26
29
  path('<str:db>/<str:entity>/remove_file', file.remove_file),
@@ -14,24 +14,23 @@ from ..models.auth import Account, AbstractUser, Menu
14
14
 
15
15
  def sign_in(request):
16
16
  body = json.loads(request.body)
17
- username = body.get("username")
18
- email = body.get("email")
19
- password = body.get("password")
20
- signin = body.get("signin")
17
+ keys = ['username', 'email', 'password', 'signin']
18
+ username, email, password, signin = [body.get(k) for k in keys]
21
19
  dao = Dao('valar.Account')
22
20
  account = dao.search({"username": username}).first()
21
+
23
22
  if account is not None:
24
23
  if signin:
25
24
  if not account.is_auth(password):
26
- return ValarResponse(False, '密码错误', 'warning', status=400)
25
+ return ValarResponse(False, '密码错误', 'warning')
27
26
  else:
28
- return ValarResponse(False, f"{username}已被占用", 'warning', status=400)
27
+ return ValarResponse(False, f"{username}已被占用", 'warning')
29
28
  else:
30
29
  if signin:
31
- return ValarResponse(False, f"{username}不存在", 'warning', status=400)
30
+ return ValarResponse(False, f"{username}不存在", 'warning')
32
31
  else:
33
32
  if username == 'admin' and password != settings.SECRET_KEY:
34
- return ValarResponse(False, "请输入正确的admin密码", 'warning', status=400)
33
+ return ValarResponse(False, "请输入正确的admin密码", 'warning')
35
34
  else:
36
35
  account = dao.save_one({
37
36
  "username": username,
@@ -0,0 +1,48 @@
1
+ import traceback
2
+
3
+ from ..channels.counter import Counter
4
+ from ..channels.sender import ValarChannelSender
5
+ from ..dao import Dao
6
+ from ..dao.engine import ValarEngine
7
+
8
+ import time
9
+
10
+
11
+ def valar_test_handler(sender: ValarChannelSender):
12
+ data = sender.data
13
+ length = data.get('length', 100)
14
+ counter = Counter(length)
15
+ for i in range(length):
16
+ time.sleep(0.1)
17
+ tick = counter.tick()
18
+ tick.update({'name': 'test1'})
19
+ sender.load(tick)
20
+ return "aba"
21
+
22
+
23
+ def batch_handler(sender: ValarChannelSender):
24
+ data = sender.data
25
+ entity, db, method = data.get("entity"), data.get("db"), data.get("method")
26
+ print(entity, db, method)
27
+ dao = Dao(entity, db)
28
+ if method == 'save_many':
29
+ array = data.get("data", [])
30
+ counter = Counter(array)
31
+ keys = []
32
+ for item in array:
33
+ item.update({'saved': True})
34
+ bean = dao.save_one(item)
35
+ keys.append(bean.id)
36
+ payload = counter.tick()
37
+ sender.load(payload)
38
+ return keys
39
+ elif method == 'delete_many':
40
+ conditions = data.get("data", [])
41
+ paths = dao.delete(conditions)
42
+ counter = Counter(len(paths))
43
+ minio = ValarEngine().get_minio_bucket(entity)
44
+ for path in paths:
45
+ minio.remove(path)
46
+ # payload = counter.tick()
47
+ # sender.load(payload)
48
+ return []
@@ -10,7 +10,7 @@ from ..dao.meta import ValarMeta
10
10
  from ..models.meta import MetaView, Meta, MetaField
11
11
 
12
12
 
13
- def upload_mapping(request):
13
+ def upload_frame(request):
14
14
  body = json.loads(request.body)
15
15
  db = body.get('db')
16
16
  entity = body.get('entity')
@@ -19,9 +19,17 @@ def upload_mapping(request):
19
19
  view__meta__db=db,
20
20
  view__meta__entity=entity,
21
21
  view__code=code,
22
- domain__in=['ManyToManyField', 'ManyToManyRel', 'ManyToOneRel', 'OneToOneField', 'OneToOneRel', 'ForeignKey']
22
+ domain__in=[
23
+ 'ManyToManyField',
24
+ 'ManyToManyRel',
25
+ 'ManyToOneRel',
26
+ 'OneToOneField',
27
+ 'OneToOneRel',
28
+ 'ForeignKey',
29
+ 'CharField'
30
+ ]
23
31
  ).filter(Q(allow_upload=True) | Q(allow_update=True))
24
- mapping = {}
32
+ frame = {}
25
33
  for field in fields:
26
34
  prop = field.prop
27
35
  refer = field.refer
@@ -29,14 +37,18 @@ def upload_mapping(request):
29
37
  entity = refer['entity']
30
38
  value = refer['value']
31
39
  label = refer['label']
32
- includes = {prop: refer['includes'][prop] for prop in refer['includes'] if not prop.startswith('$')}
33
- excludes = {prop: refer['excludes'][prop] for prop in refer['excludes'] if not prop.startswith('$')}
34
- values = Dao(entity, db).manager.filter(**includes).exclude(**excludes).values(*[value, label])
35
- mapping[prop] = {
36
- row[value]: row[label]
37
- for row in values if row[value]
38
- }
39
- return ValarResponse(mapping)
40
+ try:
41
+ includes = {prop: refer['includes'][prop] for prop in refer['includes'] if not prop.startswith('$')}
42
+ excludes = {prop: refer['excludes'][prop] for prop in refer['excludes'] if not prop.startswith('$')}
43
+ values = Dao(entity, db).manager.filter(**includes).exclude(**excludes).values(*[value, label])
44
+ frame[prop] = [
45
+ {"value": row[value], "label": row[label]}
46
+ for row in values if row[value]
47
+ ]
48
+ except Exception:
49
+ pass
50
+
51
+ return ValarResponse(frame)
40
52
 
41
53
 
42
54
  def meta_view(request, db, entity):
@@ -121,7 +133,7 @@ def add_fields(request):
121
133
 
122
134
 
123
135
  def metas(request):
124
- values = Meta.objects.all().values('db', 'entity', 'name', 'tree', 'metaview__name')
136
+ values = Meta.objects.all().values('db', 'entity', 'name', 'tree')
125
137
  mapping = {'orm': {'valar': []}, 'mon': []}
126
138
  for row in values:
127
139
  db = row['db']
@@ -57,4 +57,4 @@ def __send__(account):
57
57
  return ValarResponse(False, '该账户未登记邮箱信息', code='error')
58
58
  content = f'Your temporary password is {token}, please change it as soon as possible.'
59
59
  ValarEngine().send_email('Retrieve Password', content, email)
60
- return ValarResponse(True, '临时密码发送成功', 'success')
60
+ return ValarResponse(f'临时密码已发送至{email}')
@@ -8,6 +8,7 @@ from ..channels.executer import execute_channel
8
8
  from ..channels.sender import ValarChannelSender
9
9
  from ..classes.valar_response import ValarResponse
10
10
  from ..dao import Dao
11
+ from ..dao.engine import ValarEngine
11
12
 
12
13
 
13
14
  async def batch(request):
@@ -16,10 +17,30 @@ async def batch(request):
16
17
  return ValarResponse(True)
17
18
 
18
19
 
20
+ def save_many(request, db, entity):
21
+ array = json.loads(request.body)
22
+ dao = Dao(entity, db)
23
+ keys = []
24
+ for item in array:
25
+ item.update({'saved': True})
26
+ bean = dao.save_one(item)
27
+ keys.append(bean.id)
28
+ return ValarResponse(keys)
29
+
30
+
31
+ def delete_many(request, db, entity):
32
+ conditions = json.loads(request.body)
33
+ dao = Dao(entity, db)
34
+ paths = dao.delete(conditions)
35
+ minio = ValarEngine().get_minio_bucket(entity)
36
+ for path in paths:
37
+ minio.remove(path)
38
+ return ValarResponse(True)
39
+
40
+
19
41
  def insert_one(request, db, entity):
20
42
  item = json.loads(request.body)
21
43
  dao = Dao(entity, db)
22
- print(item)
23
44
  bean = dao.insert_one(item)
24
45
  item = dao.serialize(bean)
25
46
  return ValarResponse(item)
@@ -56,7 +77,6 @@ def find_one(request, db, entity):
56
77
  dao = Dao(entity, db)
57
78
  bean = dao.find_one(_id)
58
79
  item = dao.serialize(bean)
59
- item['$minio'] = settings.MINIO_ROOT
60
80
  return ValarResponse(item)
61
81
 
62
82
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: valar
3
- Version: 1.3.17
3
+ Version: 1.3.24
4
4
  Summary: valar for morghulis
5
5
  Home-page: https://gitee.com/GRIFFIN120/valar_dev
6
6
  Author: LYP
@@ -8,6 +8,7 @@ Author-email: liuyinpeng@buaa.edu.cn
8
8
  Requires-Python: >=3.9
9
9
  Description-Content-Type: text/markdown
10
10
  License-File: LICENSE
11
+ Requires-Dist: autobahn==24.4.2
11
12
  Requires-Dist: channels==3.0.3
12
13
  Requires-Dist: pymongo~=4.11.2
13
14
  Requires-Dist: asgiref~=3.8.1
@@ -45,7 +46,7 @@ pip install valar
45
46
  - asgi.py
46
47
  - urls.py
47
48
 
48
- ## 2.1 settings.py
49
+ ## 2.1 settings.py and ___init__.py
49
50
 
50
51
  ```python
51
52
  from pathlib import Path
@@ -61,8 +62,16 @@ SECRET_KEY = 'django-insecure-of@tfouoq^_f$l!yki#m=6j7)@&kjri$1_$!mca-=%7=+@f@5^
61
62
 
62
63
  DATABASES = {
63
64
  'default': {
64
- 'ENGINE': 'django.db.backends.sqlite3',
65
- 'NAME': BASE_DIR / 'db.sqlite3',
65
+ 'ENGINE': 'django.db.backends.mysql', # 使用 MySQL
66
+ 'NAME': 'vm_ets', # 数据库名
67
+ 'USER': 'root', # 用户名
68
+ 'PASSWORD': password, # 密码
69
+ 'HOST': 'localhost', # 数据库地址,本机用127.0.0.1
70
+ 'PORT': '3306', # MySQL端口,默认3306
71
+ 'OPTIONS': {
72
+ 'connect_timeout': 5, # 默认10秒,可以缩短
73
+ 'charset': 'utf8mb4',
74
+ }
66
75
  }
67
76
  }
68
77
 
@@ -105,44 +114,58 @@ DATA_UPLOAD_MAX_MEMORY_SIZE = 1024 * 1024 * 100
105
114
  """ Valar Options """
106
115
 
107
116
  HANDLER_MAPPING = "%s.urls.channel_mapping" % BASE_APP
108
- MONGO_URI = 'mongodb://username:password@host:27017'
109
- MINIO_URL = "s3://username:password@host:9000"
110
- MINIO_ROOT = "https://host:9001"
117
+ MONGO_URI = f'mongodb://root:{password}@{host}:27017/'
118
+ MINIO_URL = f"s3://admin:{password}@{host}:9001"
119
+ MINIO_ROOT = f"http://{host}:9001"
111
120
 
112
121
  """ Email Options """
122
+
113
123
  EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'
114
- EMAIL_HOST = 'xxx.xx.xx.xx'
115
- EMAIL_PORT = 465
116
- EMAIL_DOMAIN = 'http://xx.xx.xx'
117
- EMAIL_HOST_USER = "xxx@xx.xx.xx"
118
- EMAIL_HOST_PASSWORD = '*******'
119
- EMAIL_USE_TLS = False
120
- EMAIL_USE_SSL = True
124
+ EMAIL_HOST = 'smtp.126.com'
125
+ EMAIL_PORT = 25
126
+ EMAIL_HOST_USER = "xxxx@126.com"
127
+ EMAIL_HOST_PASSWORD = 'CGiKQh5FyQyupQYA'
128
+ ```
129
+
130
+ ```python
131
+ import pymysql
132
+
133
+ pymysql.install_as_MySQLdb()
134
+
121
135
  ```
122
136
 
123
137
  ## 2.2 asgi.py
124
138
 
125
139
  ```python
140
+ import os
141
+ from pathlib import Path
142
+
126
143
  from django.core.asgi import get_asgi_application
127
144
  from channels.routing import ProtocolTypeRouter, URLRouter
128
145
  from django.urls import re_path
129
146
 
130
147
  from valar.channels.consumer import ValarConsumer
131
148
 
149
+ os.environ.setdefault('DJANGO_SETTINGS_MODULE', '%s.settings' % Path(__file__).resolve().parent.parent.name)
132
150
  application = ProtocolTypeRouter({
133
151
  'http': get_asgi_application(),
134
152
  'websocket': URLRouter([
135
153
  re_path(r'(?P<client>\w+)/$', ValarConsumer.as_asgi()),
136
154
  ])
137
155
  })
138
-
139
-
140
156
  ```
141
157
 
142
158
  ## 2.3 urls.py
143
159
 
144
- - no need to provide urls for Valar, Valar will auto set urlpatterns for Morghulis (
145
- see https://www.npmjs.com/package/morghulis)
160
+ ```python
161
+ from django.urls import path, include
162
+
163
+ urlpatterns = [
164
+ path('valar/', include('valar.urls')),
165
+ ]
166
+
167
+ ```
168
+
146
169
  - go to section 4 to see how to register channel handlers (a Vue - Django async communication tool) in urls.
147
170
 
148
171
  # 3. migrate
@@ -42,9 +42,6 @@ src/valar/dao/defaults/field_keys_default.py
42
42
  src/valar/dao/defaults/field_values_default.py
43
43
  src/valar/dao/defaults/view_defaults.py
44
44
  src/valar/migrations/0001_initial.py
45
- src/valar/migrations/0002_location.py
46
- src/valar/migrations/0003_location_code_location_name_cn_location_name_en.py
47
- src/valar/migrations/0004_remove_location_icon_remove_location_isleaf_and_more.py
48
45
  src/valar/migrations/__init__.py
49
46
  src/valar/models/__init__.py
50
47
  src/valar/models/auth.py
@@ -1,3 +1,4 @@
1
+ autobahn==24.4.2
1
2
  channels==3.0.3
2
3
  pymongo~=4.11.2
3
4
  asgiref~=3.8.1
@@ -1,32 +0,0 @@
1
- # Generated by Django 4.2.24 on 2025-09-22 11:51
2
-
3
- from django.db import migrations, models
4
-
5
-
6
- class Migration(migrations.Migration):
7
-
8
- dependencies = [
9
- ('valar', '0001_initial'),
10
- ]
11
-
12
- operations = [
13
- migrations.CreateModel(
14
- name='Location',
15
- fields=[
16
- ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
17
- ('sort', models.BigIntegerField(null=True, verbose_name='序号')),
18
- ('create_time', models.DateTimeField(auto_now_add=True, null=True, verbose_name='创建时间')),
19
- ('modify_time', models.DateTimeField(auto_now=True, null=True, verbose_name='修改时间')),
20
- ('disabled', models.BooleanField(default=False, verbose_name='禁用')),
21
- ('saved', models.BooleanField(default=False, verbose_name='已保存')),
22
- ('pid', models.IntegerField(default=0, verbose_name='父节点')),
23
- ('isLeaf', models.BooleanField(default=False, verbose_name='叶子节点')),
24
- ('icon', models.CharField(max_length=255, null=True, verbose_name='图标')),
25
- ('scope', models.CharField(max_length=100, null=True)),
26
- ('name', models.CharField(max_length=100, null=True)),
27
- ],
28
- options={
29
- 'verbose_name': '指标集',
30
- },
31
- ),
32
- ]
@@ -1,28 +0,0 @@
1
- # Generated by Django 4.2.24 on 2025-09-22 11:51
2
-
3
- from django.db import migrations, models
4
-
5
-
6
- class Migration(migrations.Migration):
7
-
8
- dependencies = [
9
- ('valar', '0002_location'),
10
- ]
11
-
12
- operations = [
13
- migrations.AddField(
14
- model_name='location',
15
- name='code',
16
- field=models.CharField(max_length=100, null=True),
17
- ),
18
- migrations.AddField(
19
- model_name='location',
20
- name='name_cn',
21
- field=models.CharField(max_length=100, null=True),
22
- ),
23
- migrations.AddField(
24
- model_name='location',
25
- name='name_en',
26
- field=models.CharField(max_length=100, null=True),
27
- ),
28
- ]
@@ -1,25 +0,0 @@
1
- # Generated by Django 4.2.24 on 2025-09-22 11:52
2
-
3
- from django.db import migrations
4
-
5
-
6
- class Migration(migrations.Migration):
7
-
8
- dependencies = [
9
- ('valar', '0003_location_code_location_name_cn_location_name_en'),
10
- ]
11
-
12
- operations = [
13
- migrations.RemoveField(
14
- model_name='location',
15
- name='icon',
16
- ),
17
- migrations.RemoveField(
18
- model_name='location',
19
- name='isLeaf',
20
- ),
21
- migrations.RemoveField(
22
- model_name='location',
23
- name='pid',
24
- ),
25
- ]
@@ -1,53 +0,0 @@
1
- import traceback
2
-
3
- from ..channels.counter import Counter
4
- from ..channels.sender import ValarChannelSender
5
- from ..dao import Dao
6
- from ..dao.engine import ValarEngine
7
-
8
- import time
9
-
10
-
11
- def valar_test_handler(sender: ValarChannelSender):
12
- data = sender.data
13
- length = data.get('length', 100)
14
- counter = Counter(length)
15
- for i in range(length):
16
- time.sleep(0.1)
17
- tick = counter.tick()
18
- tick.update({'name': 'test1'})
19
- sender.load(tick)
20
-
21
-
22
- def batch_handler(sender: ValarChannelSender):
23
- data = sender.data
24
- entity, db, method = data.get("entity"), data.get("db"), data.get("method")
25
- dao = Dao(entity, db)
26
- body = {"method": method}
27
-
28
- try:
29
- if method == 'save_many':
30
- array = data.get("array", [])
31
- counter = Counter(array)
32
- keys = []
33
- for item in array:
34
- item.update({'saved': True})
35
- bean = dao.save_one(item)
36
- keys.append(bean.id)
37
- payload = counter.tick()
38
- sender.load(payload)
39
- body.update({'keys': keys})
40
- sender.done(body)
41
- elif method == 'delete_many':
42
- conditions = data.get("conditions", [])
43
- paths = dao.delete(conditions)
44
- counter = Counter(len(paths))
45
- minio = ValarEngine().get_minio_bucket(entity)
46
- for path in paths:
47
- minio.remove(path)
48
- payload = counter.tick()
49
- sender.load(payload)
50
- sender.done(body)
51
- except Exception as e:
52
- traceback.print_exc()
53
- sender.error(str(e))
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes