fastgenerateapi 1.2.13__tar.gz → 1.2.15__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 (122) hide show
  1. {fastgenerateapi-1.2.13 → fastgenerateapi-1.2.15}/PKG-INFO +1 -1
  2. {fastgenerateapi-1.2.13 → fastgenerateapi-1.2.15}/fastgenerateapi/__init__.py +7 -0
  3. {fastgenerateapi-1.2.13 → fastgenerateapi-1.2.15}/fastgenerateapi/__version__.py +1 -1
  4. {fastgenerateapi-1.2.13 → fastgenerateapi-1.2.15}/fastgenerateapi/api_view/base_view.py +37 -9
  5. {fastgenerateapi-1.2.13 → fastgenerateapi-1.2.15}/fastgenerateapi/api_view/delete_filter_view.py +14 -7
  6. {fastgenerateapi-1.2.13 → fastgenerateapi-1.2.15}/fastgenerateapi/api_view/get_all_view.py +85 -60
  7. {fastgenerateapi-1.2.13 → fastgenerateapi-1.2.15}/fastgenerateapi/api_view/get_relation_view.py +22 -29
  8. {fastgenerateapi-1.2.13 → fastgenerateapi-1.2.15}/fastgenerateapi/api_view/get_tree_view.py +1 -1
  9. {fastgenerateapi-1.2.13 → fastgenerateapi-1.2.15}/fastgenerateapi/api_view/mixin/dbmodel_mixin.py +27 -0
  10. {fastgenerateapi-1.2.13 → fastgenerateapi-1.2.15}/fastgenerateapi/api_view/mixin/response_mixin.py +4 -5
  11. fastgenerateapi-1.2.15/fastgenerateapi/api_view/mixin/tool_mixin.py +49 -0
  12. {fastgenerateapi-1.2.13 → fastgenerateapi-1.2.15}/fastgenerateapi/api_view/mixin/utils/pdf_util.py +4 -6
  13. fastgenerateapi-1.2.15/fastgenerateapi/api_view/mixin/utils/xlsx_util.py +319 -0
  14. {fastgenerateapi-1.2.13 → fastgenerateapi-1.2.15}/fastgenerateapi/api_view/switch_view.py +4 -6
  15. {fastgenerateapi-1.2.13 → fastgenerateapi-1.2.15}/fastgenerateapi/controller/filter_controller.py +2 -3
  16. fastgenerateapi-1.2.15/fastgenerateapi/deps/__init__.py +13 -0
  17. {fastgenerateapi-1.2.13 → fastgenerateapi-1.2.15}/fastgenerateapi/deps/filter_params_deps.py +28 -0
  18. {fastgenerateapi-1.2.13 → fastgenerateapi-1.2.15}/fastgenerateapi/deps/tree_params_deps.py +0 -1
  19. {fastgenerateapi-1.2.13 → fastgenerateapi-1.2.15}/fastgenerateapi/example/models.py +2 -2
  20. {fastgenerateapi-1.2.13 → fastgenerateapi-1.2.15}/fastgenerateapi/example/schemas.py +14 -18
  21. {fastgenerateapi-1.2.13 → fastgenerateapi-1.2.15}/fastgenerateapi/example/views.py +14 -24
  22. {fastgenerateapi-1.2.13 → fastgenerateapi-1.2.15}/fastgenerateapi/fastapi_utils/param_utils.py +5 -10
  23. {fastgenerateapi-1.2.13 → fastgenerateapi-1.2.15}/fastgenerateapi/my_fields/validator.py +6 -6
  24. {fastgenerateapi-1.2.13 → fastgenerateapi-1.2.15}/fastgenerateapi/pydantic_utils/base_model.py +45 -5
  25. {fastgenerateapi-1.2.13 → fastgenerateapi-1.2.15}/fastgenerateapi/schemas_factory/common_function.py +2 -2
  26. {fastgenerateapi-1.2.13 → fastgenerateapi-1.2.15}/fastgenerateapi/schemas_factory/response_factory.py +14 -1
  27. {fastgenerateapi-1.2.13 → fastgenerateapi-1.2.15}/fastgenerateapi/settings/app_settings.py +7 -8
  28. fastgenerateapi-1.2.15/fastgenerateapi/utils/__init__.py +1 -0
  29. {fastgenerateapi-1.2.13 → fastgenerateapi-1.2.15}/fastgenerateapi/utils/str_util.py +10 -2
  30. {fastgenerateapi-1.2.13 → fastgenerateapi-1.2.15}/fastgenerateapi.egg-info/PKG-INFO +1 -1
  31. {fastgenerateapi-1.2.13 → fastgenerateapi-1.2.15}/fastgenerateapi.egg-info/SOURCES.txt +0 -2
  32. fastgenerateapi-1.2.13/fastgenerateapi/api_view/mixin/tool_mixin.py +0 -17
  33. fastgenerateapi-1.2.13/fastgenerateapi/api_view/mixin/utils/xlsx_util.py +0 -336
  34. fastgenerateapi-1.2.13/fastgenerateapi/api_view/sql_get_view.py +0 -142
  35. fastgenerateapi-1.2.13/fastgenerateapi/deps/__init__.py +0 -14
  36. fastgenerateapi-1.2.13/fastgenerateapi/deps/paginator_deps.py +0 -73
  37. fastgenerateapi-1.2.13/fastgenerateapi/validator/__init__.py +0 -0
  38. {fastgenerateapi-1.2.13 → fastgenerateapi-1.2.15}/LICENSE +0 -0
  39. {fastgenerateapi-1.2.13 → fastgenerateapi-1.2.15}/README.md +0 -0
  40. {fastgenerateapi-1.2.13 → fastgenerateapi-1.2.15}/fastgenerateapi/api_view/__init__.py +0 -0
  41. {fastgenerateapi-1.2.13 → fastgenerateapi-1.2.15}/fastgenerateapi/api_view/api_view.py +0 -0
  42. {fastgenerateapi-1.2.13 → fastgenerateapi-1.2.15}/fastgenerateapi/api_view/create_view.py +0 -0
  43. {fastgenerateapi-1.2.13 → fastgenerateapi-1.2.15}/fastgenerateapi/api_view/delete_tree_view.py +0 -0
  44. {fastgenerateapi-1.2.13 → fastgenerateapi-1.2.15}/fastgenerateapi/api_view/delete_view.py +0 -0
  45. {fastgenerateapi-1.2.13 → fastgenerateapi-1.2.15}/fastgenerateapi/api_view/get_one_view.py +0 -0
  46. {fastgenerateapi-1.2.13 → fastgenerateapi-1.2.15}/fastgenerateapi/api_view/mixin/__init__.py +0 -0
  47. {fastgenerateapi-1.2.13 → fastgenerateapi-1.2.15}/fastgenerateapi/api_view/mixin/base_mixin.py +0 -0
  48. {fastgenerateapi-1.2.13 → fastgenerateapi-1.2.15}/fastgenerateapi/api_view/mixin/get_mixin.py +0 -0
  49. {fastgenerateapi-1.2.13 → fastgenerateapi-1.2.15}/fastgenerateapi/api_view/mixin/save_mixin.py +0 -0
  50. {fastgenerateapi-1.2.13 → fastgenerateapi-1.2.15}/fastgenerateapi/api_view/mixin/utils/__init__.py +0 -0
  51. {fastgenerateapi-1.2.13 → fastgenerateapi-1.2.15}/fastgenerateapi/api_view/mixin/utils/docx_util.py +0 -0
  52. {fastgenerateapi-1.2.13 → fastgenerateapi-1.2.15}/fastgenerateapi/api_view/mixin/utils/file_util.py +0 -0
  53. {fastgenerateapi-1.2.13 → fastgenerateapi-1.2.15}/fastgenerateapi/api_view/mixin/utils/zip_util.py +0 -0
  54. {fastgenerateapi-1.2.13 → fastgenerateapi-1.2.15}/fastgenerateapi/api_view/update_relation_view.py +0 -0
  55. {fastgenerateapi-1.2.13 → fastgenerateapi-1.2.15}/fastgenerateapi/api_view/update_view.py +0 -0
  56. {fastgenerateapi-1.2.13 → fastgenerateapi-1.2.15}/fastgenerateapi/cache/__init__.py +0 -0
  57. {fastgenerateapi-1.2.13 → fastgenerateapi-1.2.15}/fastgenerateapi/cache/cache_decorator.py +0 -0
  58. {fastgenerateapi-1.2.13 → fastgenerateapi-1.2.15}/fastgenerateapi/cache/key_builder.py +0 -0
  59. {fastgenerateapi-1.2.13 → fastgenerateapi-1.2.15}/fastgenerateapi/channel/__init__.py +0 -0
  60. {fastgenerateapi-1.2.13 → fastgenerateapi-1.2.15}/fastgenerateapi/channel/connection_manager.py +0 -0
  61. {fastgenerateapi-1.2.13 → fastgenerateapi-1.2.15}/fastgenerateapi/channel/consumer.py +0 -0
  62. {fastgenerateapi-1.2.13 → fastgenerateapi-1.2.15}/fastgenerateapi/channel/websocket_view.py +0 -0
  63. {fastgenerateapi-1.2.13 → fastgenerateapi-1.2.15}/fastgenerateapi/controller/__init__.py +0 -0
  64. {fastgenerateapi-1.2.13 → fastgenerateapi-1.2.15}/fastgenerateapi/controller/router_controller.py +0 -0
  65. {fastgenerateapi-1.2.13 → fastgenerateapi-1.2.15}/fastgenerateapi/controller/rpc_controller.py +0 -0
  66. {fastgenerateapi-1.2.13 → fastgenerateapi-1.2.15}/fastgenerateapi/controller/search_controller.py +0 -0
  67. {fastgenerateapi-1.2.13 → fastgenerateapi-1.2.15}/fastgenerateapi/controller/ws_controller.py +0 -0
  68. {fastgenerateapi-1.2.13 → fastgenerateapi-1.2.15}/fastgenerateapi/data_type/__init__.py +0 -0
  69. {fastgenerateapi-1.2.13 → fastgenerateapi-1.2.15}/fastgenerateapi/data_type/data_type.py +0 -0
  70. {fastgenerateapi-1.2.13 → fastgenerateapi-1.2.15}/fastgenerateapi/data_type/mysql_data_type.py +0 -0
  71. {fastgenerateapi-1.2.13 → fastgenerateapi-1.2.15}/fastgenerateapi/example/__init__.py +0 -0
  72. {fastgenerateapi-1.2.13 → fastgenerateapi-1.2.15}/fastgenerateapi/example/routers.py +0 -0
  73. {fastgenerateapi-1.2.13 → fastgenerateapi-1.2.15}/fastgenerateapi/fastapi_utils/__init__.py +0 -0
  74. {fastgenerateapi-1.2.13 → fastgenerateapi-1.2.15}/fastgenerateapi/fastapi_utils/all.py +0 -0
  75. {fastgenerateapi-1.2.13 → fastgenerateapi-1.2.15}/fastgenerateapi/fastapi_utils/response_utils.py +0 -0
  76. {fastgenerateapi-1.2.13 → fastgenerateapi-1.2.15}/fastgenerateapi/fastapi_utils/tortoise_utils.py +0 -0
  77. {fastgenerateapi-1.2.13 → fastgenerateapi-1.2.15}/fastgenerateapi/model/__init__.py +0 -0
  78. {fastgenerateapi-1.2.13 → fastgenerateapi-1.2.15}/fastgenerateapi/model/base_model.py +0 -0
  79. {fastgenerateapi-1.2.13 → fastgenerateapi-1.2.15}/fastgenerateapi/my_fields/__init__.py +0 -0
  80. {fastgenerateapi-1.2.13 → fastgenerateapi-1.2.15}/fastgenerateapi/my_fields/aes_field.py +0 -0
  81. {fastgenerateapi-1.2.13 → fastgenerateapi-1.2.15}/fastgenerateapi/my_fields/enum_field.py +0 -0
  82. {fastgenerateapi-1.2.13 → fastgenerateapi-1.2.15}/fastgenerateapi/my_fields/pk_field.py +0 -0
  83. {fastgenerateapi-1.2.13 → fastgenerateapi-1.2.15}/fastgenerateapi/my_fields/pwd_field.py +0 -0
  84. {fastgenerateapi-1.2.13 → fastgenerateapi-1.2.15}/fastgenerateapi/my_fields/soft_delete_field.py +0 -0
  85. {fastgenerateapi-1.2.13 → fastgenerateapi-1.2.15}/fastgenerateapi/pydantic_utils/__init__.py +0 -0
  86. {fastgenerateapi-1.2.13 → fastgenerateapi-1.2.15}/fastgenerateapi/pydantic_utils/base_settings.py +0 -0
  87. {fastgenerateapi-1.2.13 → fastgenerateapi-1.2.15}/fastgenerateapi/pydantic_utils/json_encoders.py +0 -0
  88. {fastgenerateapi-1.2.13 → fastgenerateapi-1.2.15}/fastgenerateapi/schemas_factory/__init__.py +0 -0
  89. {fastgenerateapi-1.2.13 → fastgenerateapi-1.2.15}/fastgenerateapi/schemas_factory/common_schema_factory.py +0 -0
  90. {fastgenerateapi-1.2.13 → fastgenerateapi-1.2.15}/fastgenerateapi/schemas_factory/create_schema_factory.py +0 -0
  91. {fastgenerateapi-1.2.13 → fastgenerateapi-1.2.15}/fastgenerateapi/schemas_factory/filter_schema_factory.py +0 -0
  92. {fastgenerateapi-1.2.13 → fastgenerateapi-1.2.15}/fastgenerateapi/schemas_factory/get_all_schema_factory.py +0 -0
  93. {fastgenerateapi-1.2.13 → fastgenerateapi-1.2.15}/fastgenerateapi/schemas_factory/get_one_schema_factory.py +0 -0
  94. {fastgenerateapi-1.2.13 → fastgenerateapi-1.2.15}/fastgenerateapi/schemas_factory/get_relation_schema_factory.py +0 -0
  95. {fastgenerateapi-1.2.13 → fastgenerateapi-1.2.15}/fastgenerateapi/schemas_factory/get_tree_schema_factory.py +0 -0
  96. {fastgenerateapi-1.2.13 → fastgenerateapi-1.2.15}/fastgenerateapi/schemas_factory/sql_get_all_schema_factory.py +0 -0
  97. {fastgenerateapi-1.2.13 → fastgenerateapi-1.2.15}/fastgenerateapi/schemas_factory/update_schema_factory.py +0 -0
  98. {fastgenerateapi-1.2.13 → fastgenerateapi-1.2.15}/fastgenerateapi/settings/__init__.py +0 -0
  99. {fastgenerateapi-1.2.13 → fastgenerateapi-1.2.15}/fastgenerateapi/settings/all_settings.py +0 -0
  100. {fastgenerateapi-1.2.13 → fastgenerateapi-1.2.15}/fastgenerateapi/settings/db_settings.py +0 -0
  101. {fastgenerateapi-1.2.13 → fastgenerateapi-1.2.15}/fastgenerateapi/settings/etcd_settings.py +0 -0
  102. {fastgenerateapi-1.2.13 → fastgenerateapi-1.2.15}/fastgenerateapi/settings/file_settings.py +0 -0
  103. {fastgenerateapi-1.2.13 → fastgenerateapi-1.2.15}/fastgenerateapi/settings/jwt_settings.py +0 -0
  104. {fastgenerateapi-1.2.13 → fastgenerateapi-1.2.15}/fastgenerateapi/settings/otlp_settings.py +0 -0
  105. {fastgenerateapi-1.2.13 → fastgenerateapi-1.2.15}/fastgenerateapi/settings/redis_settings.py +0 -0
  106. {fastgenerateapi-1.2.13 → fastgenerateapi-1.2.15}/fastgenerateapi/settings/sms_settings.py +0 -0
  107. {fastgenerateapi-1.2.13 → fastgenerateapi-1.2.15}/fastgenerateapi/settings/system_settings.py +0 -0
  108. {fastgenerateapi-1.2.13 → fastgenerateapi-1.2.15}/fastgenerateapi/utils/aes.py +0 -0
  109. {fastgenerateapi-1.2.13 → fastgenerateapi-1.2.15}/fastgenerateapi/utils/auto_discover.py +0 -0
  110. {fastgenerateapi-1.2.13 → fastgenerateapi-1.2.15}/fastgenerateapi/utils/exception.py +0 -0
  111. {fastgenerateapi-1.2.13 → fastgenerateapi-1.2.15}/fastgenerateapi/utils/file_utils.py +0 -0
  112. {fastgenerateapi-1.2.13 → fastgenerateapi-1.2.15}/fastgenerateapi/utils/pwd_utils.py +0 -0
  113. {fastgenerateapi-1.2.13 → fastgenerateapi-1.2.15}/fastgenerateapi/utils/ramdom_utils.py +0 -0
  114. {fastgenerateapi-1.2.13 → fastgenerateapi-1.2.15}/fastgenerateapi/utils/snowflake.py +0 -0
  115. {fastgenerateapi-1.2.13 → fastgenerateapi-1.2.15}/fastgenerateapi/utils/swagger_to_js.py +0 -0
  116. {fastgenerateapi-1.2.13/fastgenerateapi/utils → fastgenerateapi-1.2.15/fastgenerateapi/validator}/__init__.py +0 -0
  117. {fastgenerateapi-1.2.13 → fastgenerateapi-1.2.15}/fastgenerateapi/validator/validator.py +0 -0
  118. {fastgenerateapi-1.2.13 → fastgenerateapi-1.2.15}/fastgenerateapi.egg-info/dependency_links.txt +0 -0
  119. {fastgenerateapi-1.2.13 → fastgenerateapi-1.2.15}/fastgenerateapi.egg-info/top_level.txt +0 -0
  120. {fastgenerateapi-1.2.13 → fastgenerateapi-1.2.15}/script/__init__.py +0 -0
  121. {fastgenerateapi-1.2.13 → fastgenerateapi-1.2.15}/setup.cfg +0 -0
  122. {fastgenerateapi-1.2.13 → fastgenerateapi-1.2.15}/setup.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: fastgenerateapi
3
- Version: 1.2.13
3
+ Version: 1.2.15
4
4
  Summary: FastAPIView Class View
5
5
  Author: ShiLiang
6
6
  Author-email: 2509144896@qq.com
@@ -27,3 +27,10 @@ from fastgenerateapi.channel.consumer import Consumer
27
27
  # 模型相关类
28
28
  from fastgenerateapi.pydantic_utils.base_model import model_config, BaseModel, IdList
29
29
 
30
+ # 工具相关
31
+ from fastgenerateapi.api_view.mixin.utils.docx_util import DocxUtil
32
+ from fastgenerateapi.api_view.mixin.utils.file_util import FileUtil
33
+ from fastgenerateapi.api_view.mixin.utils.pdf_util import PdfUtil
34
+ from fastgenerateapi.api_view.mixin.utils.xlsx_util import XlsxUtil
35
+ from fastgenerateapi.api_view.mixin.utils.zip_util import ZipUtil
36
+
@@ -8,7 +8,7 @@
8
8
  # d8888P
9
9
 
10
10
 
11
- VERSION = (1, 2, 13)
11
+ VERSION = (1, 2, 15)
12
12
 
13
13
  __version__ = '.'.join(map(str, VERSION))
14
14
 
@@ -1,7 +1,7 @@
1
1
  import time
2
2
  import uuid
3
3
  from copy import copy
4
- from typing import Optional, Type, List, Union, Sequence, Dict
4
+ from typing import Optional, Type, List, Union, Sequence, Dict, Any
5
5
  from urllib.parse import parse_qs
6
6
 
7
7
  from fastapi import params
@@ -24,7 +24,7 @@ class BaseView(BaseMixin, ResponseMixin, ToolMixin, DBModelMixin):
24
24
 
25
25
  prefix: Optional[str] = None # 路由追加后缀
26
26
  model_class: Optional[Type[Model]] = None # 数据库模型
27
- prefetch_related_fields: Union[None, dict] = None
27
+ prefetch_related_fields: Optional[dict] = None
28
28
  is_with_prefetch: Optional[bool] = False
29
29
  response_schema: Optional[Type[BaseModel]] = None # 通用返回序列化
30
30
  dependencies: Optional[Sequence[params.Depends]] = None
@@ -98,6 +98,8 @@ class BaseView(BaseMixin, ResponseMixin, ToolMixin, DBModelMixin):
98
98
 
99
99
  @staticmethod
100
100
  async def setattr_model(model: Model, prefetch_related_fields, *args, **kwargs) -> Model:
101
+ if not prefetch_related_fields:
102
+ return model
101
103
  for key, value_list in prefetch_related_fields.items():
102
104
  if value_list is None:
103
105
  continue
@@ -149,6 +151,8 @@ class BaseView(BaseMixin, ResponseMixin, ToolMixin, DBModelMixin):
149
151
  model_class: Type[Model],
150
152
  model: Union[Model, None] = None,
151
153
  check_ignore_error_fields: List[str] = None,
154
+ error_format: Optional[str] = None,
155
+ error_value_list: Optional[List[str]] = None,
152
156
  ):
153
157
  """
154
158
  校验模型中设置了 唯一索引和联合唯一索引 的字段
@@ -156,6 +160,8 @@ class BaseView(BaseMixin, ResponseMixin, ToolMixin, DBModelMixin):
156
160
  :param model_class: 数据库模型
157
161
  :param model: 修改前的数据,用于判断是否修改了字段,当唯一字段与数据data_dict一致时,不会做校验
158
162
  :param check_ignore_error_fields: 错误提示忽略字段,会合并类上的字段
163
+ :param error_format: 错误格式,例如: "错误:输入年龄 '{}' 无效!合法范围是 {}-{} 岁"
164
+ :param error_value_list: 错误字段列表 ,例如:[input_age, min_age, max_age]
159
165
  :return:
160
166
  """
161
167
  check_unique_fields = self._get_unique_fields(model_class)
@@ -193,16 +199,27 @@ class BaseView(BaseMixin, ResponseMixin, ToolMixin, DBModelMixin):
193
199
  is_equal = False
194
200
  description_fields.append(unique_together_field)
195
201
  filter_fields[unique_together_field] = unique_together_field_value
202
+ elif unique_together_field == settings.app_settings.WHETHER_DELETE_FIELD:
203
+ if settings.app_settings.DELETE_FIELD_TYPE == "time":
204
+ filter_fields[unique_together_field] = 0
205
+ else:
206
+ filter_fields[unique_together_field] = True
196
207
  if is_equal:
197
208
  continue
198
209
 
199
210
  if await model_class.filter(**filter_fields).first():
211
+ if error_format and error_value_list:
212
+ return self.error(
213
+ status_code=422,
214
+ msg=error_format.format(*[data_dict[k] for k in error_value_list])
215
+ )
200
216
  if settings.app_settings.WHETHER_DELETE_FIELD in description_fields:
201
217
  description_fields.remove(settings.app_settings.WHETHER_DELETE_FIELD)
202
218
  for ignore_error_field in ignore_error_field_list:
203
219
  if ignore_error_field in description_fields:
204
220
  description_fields.remove(ignore_error_field)
205
221
  return self.error(
222
+ status_code=422,
206
223
  msg=f"{self.get_field_description(model_class, description_fields)}已存在相同值:{[filter_fields.get(field) for field in description_fields]}"
207
224
  )
208
225
 
@@ -214,6 +231,23 @@ class BaseView(BaseMixin, ResponseMixin, ToolMixin, DBModelMixin):
214
231
  result[key] = val[0]
215
232
  return result
216
233
 
234
+ def _get_extra_related_schema(self):
235
+ """
236
+ prefetch_related_fields 转换为 extra_include 的参数
237
+ :return:
238
+ """
239
+ schema_include = []
240
+ for key, value in self.prefetch_related_fields.items():
241
+ if not value:
242
+ schema_include.append([key, Optional[Any]])
243
+ elif type(value) in [list, tuple, set]:
244
+ for val in value:
245
+ val_str = val
246
+ if type(val) in [list, tuple, set]:
247
+ val_str = val[0]
248
+ schema_include.append(key + "__" + val_str)
249
+ return schema_include
250
+
217
251
  def get_response_schema(self):
218
252
  """
219
253
  如果response_schema不存在,则生成
@@ -222,13 +256,7 @@ class BaseView(BaseMixin, ResponseMixin, ToolMixin, DBModelMixin):
222
256
  if not self.response_schema:
223
257
  get_one_schema_include = []
224
258
  if self.is_with_prefetch and self.prefetch_related_fields:
225
- for key, value in self.prefetch_related_fields.items():
226
- if value and type(value) in [list, tuple, set]:
227
- for val in value:
228
- val_str = val
229
- if type(val) in [list, tuple, set]:
230
- val_str = val[0]
231
- get_one_schema_include.append(key + "__" + val_str)
259
+ get_one_schema_include = self._get_extra_related_schema()
232
260
  self.response_schema = get_one_schema_factory(self.model_class, extra_include=get_one_schema_include)
233
261
 
234
262
  return self.response_schema
@@ -11,8 +11,9 @@ from tortoise.transactions import atomic
11
11
 
12
12
  from fastgenerateapi.api_view.base_view import BaseView
13
13
  from fastgenerateapi.data_type.data_type import CALLABLE, DEPENDENCIES
14
- from fastgenerateapi.deps import filter_params_deps
15
- from fastgenerateapi.schemas_factory import response_factory, get_one_schema_factory
14
+ from fastgenerateapi.deps.filter_params_deps import filter_json_deps
15
+ from fastgenerateapi.pydantic_utils.base_model import IdList, SearchPydantic
16
+ from fastgenerateapi.schemas_factory import response_factory
16
17
  from fastgenerateapi.settings.all_settings import settings
17
18
 
18
19
 
@@ -28,22 +29,28 @@ class DeleteFilterView(BaseView):
28
29
  """
29
30
 
30
31
  @atomic()
31
- async def destroy_filter(self, search: str, filters: dict, *args, **kwargs):
32
+ async def destroy_filter(self, search: str, request_data, filters: dict, *args, **kwargs):
32
33
  queryset = await self.get_queryset(search=search, filters=filters, *args, **kwargs)
33
-
34
+ queryset = await self.get_del_filter_queryset(queryset, request_data=request_data, *args, **kwargs)
34
35
  await self.delete_queryset(queryset)
35
36
 
36
37
  return
37
38
 
39
+ async def get_del_filter_queryset(self, queryset, request_data, *args, **kwargs):
40
+ queryset = queryset.filter(id__in=request_data.id_list)
41
+ return queryset
42
+
38
43
  def _delete_filter_decorator(self, *args: Any, **kwargs: Any) -> DecoratedCallable:
39
44
  async def route(
40
45
  request: Request,
41
- search: str = Query(default="", description="搜索"),
42
- filters: dict = Depends(filter_params_deps(model_class=self.model_class, fields=self.filter_fields)),
46
+ search: SearchPydantic,
47
+ request_data: IdList,
48
+ filters: dict = Depends(filter_json_deps(model_class=self.model_class, fields=self.filter_fields)),
43
49
  token: Optional[str] = Depends(OAuth2PasswordBearer(tokenUrl="token", auto_error=False)),
44
50
  ) -> JSONResponse:
45
51
  data = await self.destroy_filter(
46
- search=search,
52
+ search=search.search,
53
+ request_data=request_data,
47
54
  filters=filters,
48
55
  request=request,
49
56
  token=token,
@@ -7,6 +7,7 @@ from fastapi.types import DecoratedCallable
7
7
  from fastapi_cache import JsonCoder
8
8
  from fastapi_cache.decorator import cache
9
9
  from pydantic import BaseModel
10
+ from starlette._utils import is_async_callable
10
11
  from starlette.requests import Request
11
12
  from starlette.responses import JSONResponse
12
13
  from tortoise import Model
@@ -19,10 +20,10 @@ from fastgenerateapi.cache.cache_decorator import get_all_cache_decorator
19
20
  from fastgenerateapi.cache.key_builder import generate_key_builder
20
21
  from fastgenerateapi.controller import SearchController, BaseFilter, FilterController
21
22
  from fastgenerateapi.data_type.data_type import DEPENDENCIES, PYDANTIC_SCHEMA
22
- from fastgenerateapi.deps import paginator_deps, filter_params_deps
23
+ from fastgenerateapi.deps import filter_params_deps
23
24
  from fastgenerateapi.deps.filter_params_deps import search_params_deps, extra_filter_params_deps
24
- from fastgenerateapi.schemas_factory import get_all_schema_factory, get_page_schema_factory, get_one_schema_factory, \
25
- response_factory
25
+ from fastgenerateapi.pydantic_utils.base_model import PagePydantic
26
+ from fastgenerateapi.schemas_factory import get_all_schema_factory, get_page_schema_factory, response_factory
26
27
  from fastgenerateapi.schemas_factory.get_all_schema_factory import get_list_schema_factory, hasattr_get_all_schema
27
28
  from fastgenerateapi.settings.all_settings import settings
28
29
 
@@ -58,7 +59,11 @@ class GetAllView(BaseView, GetMixin):
58
59
  async def get_all(self, search: Optional[str], filters: dict, *args, **kwargs):
59
60
  queryset = await self.get_queryset(search=search, filters=filters, *args, **kwargs)
60
61
 
61
- return await self.pagination_data(queryset=queryset, *args, **kwargs)
62
+ return await self.get_page_data(
63
+ queryset=queryset,
64
+ prefetch_related_fields=self.prefetch_related_fields,
65
+ *args, **kwargs
66
+ )
62
67
 
63
68
  async def get_queryset(self, search: Optional[str], filters: dict, *args, **kwargs) -> QuerySet:
64
69
  """
@@ -89,73 +94,99 @@ class GetAllView(BaseView, GetMixin):
89
94
  """
90
95
  return model
91
96
 
92
- async def pagination_data(
97
+ async def get_queryset_data(
93
98
  self,
94
99
  queryset: QuerySet,
95
- paginator=None,
96
100
  schema: Type[BaseModel] = None,
97
- name: str = "", # 当使用fields时,需要输入名称用于自动生成schema
98
- fields: List[Union[str, tuple]] = None,
99
- *args, **kwargs
101
+ paginator: Optional[PagePydantic] = PagePydantic(),
102
+ model_handler_list: Optional[List[Callable]] = None,
103
+ *args, **kwargs,
100
104
  ):
101
-
102
- data_list = []
103
- if paginator is None or getattr(paginator, settings.app_settings.DETERMINE_WHETHER_PAGE_FIELD) == \
104
- settings.app_settings.DETERMINE_PAGE_BOOL_VALUE:
105
+ """
106
+ 通用分页函数,获取对应的数据,和分页统计
107
+ :param queryset:
108
+ :param schema:
109
+ :param paginator:
110
+ :param model_handler_list:
111
+ :param args:
112
+ :param kwargs:
113
+ :return:
114
+ """
115
+ count = None
116
+ if paginator.no_page:
105
117
  model_list = await queryset.all()
106
118
  else:
107
119
  count = await queryset.count()
108
- current_num = getattr(paginator, settings.app_settings.CURRENT_PAGE_FIELD)
109
- page_size = getattr(paginator, settings.app_settings.PAGE_SIZE_FIELD)
110
- queryset = queryset.offset(cast(int, (current_num - 1) * page_size))
111
- model_list = await queryset.limit(page_size)
120
+ queryset = queryset.offset(cast(int, (paginator.page - 1) * paginator.page_size))
121
+ model_list = await queryset.limit(paginator.page_size)
112
122
 
123
+ data_list = []
113
124
  for model in model_list:
125
+ await self.setattr_model(model,*args, **kwargs)
126
+ if model_handler_list:
127
+ for model_handler in model_handler_list:
128
+ if is_async_callable(model_handler):
129
+ model = await model_handler(model, paginator=paginator,*args, **kwargs)
130
+ else:
131
+ model = model_handler(model, paginator=paginator,*args, **kwargs)
132
+ if schema:
133
+ data_list.append(schema.model_validate(model))
134
+ else:
135
+ model = await self.set_get_model(model, paginator=paginator,*args, **kwargs)
136
+ model = await self.set_get_all_model(model, paginator=paginator, *args, **kwargs)
137
+ data_list.append(self.get_all_schema.model_validate(model))
114
138
 
115
- await self.setattr_model(model, prefetch_related_fields=self.prefetch_related_fields, *args, **kwargs)
139
+ return data_list, count
116
140
 
117
- # await self.setattr_model_rpc(self.rpc_class, model, self.rpc_param)
118
- model = await self.set_get_model(model, *args, **kwargs)
119
- model = await self.set_get_all_model(model, *args, **kwargs)
141
+ def get_page_schema_func(self, data_list, count = None, schema: Type[BaseModel] = None, paginator: Optional[PagePydantic] = None, *args, **kwargs):
142
+ """
143
+ 返回列表结果
144
+ :param data_list:
145
+ :param count:
146
+ :param schema: 当使用自定义列表时使用,默认列表的get_all_schema
147
+ :param paginator:
148
+ :param args:
149
+ :param kwargs: 自定义列表时,传schema或fields
150
+ :return:
151
+ """
152
+ if paginator.no_page:
153
+ page_schema = get_list_schema_factory(schema) if schema else self.get_all_list_schema
154
+ else:
155
+ page_schema = get_page_schema_factory(schema) if schema else self.get_all_page_schema
120
156
 
121
- if schema:
122
- data_list.append(schema.from_orm(model))
123
- elif fields:
124
- data_list.append(await self.getattr_model(model=model, fields=fields))
125
- else:
126
- data_list.append(self.get_all_schema.from_orm(model))
127
-
128
- if paginator is None or getattr(paginator, settings.app_settings.DETERMINE_WHETHER_PAGE_FIELD) == \
129
- settings.app_settings.DETERMINE_PAGE_BOOL_VALUE:
130
- if schema or fields:
131
- return get_list_schema_factory(schema, name)(**{settings.app_settings.LIST_RESPONSE_FIELD: data_list})
132
- return self.get_list_schema(**{settings.app_settings.LIST_RESPONSE_FIELD: data_list})
133
- if schema or fields:
134
- return get_page_schema_factory(schema, name)(**{
135
- settings.app_settings.CURRENT_PAGE_FIELD: current_num,
136
- settings.app_settings.PAGE_SIZE_FIELD: page_size,
137
- settings.app_settings.TOTAL_SIZE_FIELD: count,
157
+ return page_schema(
158
+ **paginator.model_dump(by_alias=True),
159
+ **{
138
160
  settings.app_settings.LIST_RESPONSE_FIELD: data_list,
139
- })
140
- return self.get_page_schema(**{
141
- settings.app_settings.CURRENT_PAGE_FIELD: current_num,
142
- settings.app_settings.PAGE_SIZE_FIELD: page_size,
143
- settings.app_settings.TOTAL_SIZE_FIELD: count,
144
- settings.app_settings.LIST_RESPONSE_FIELD: data_list,
145
- })
161
+ settings.app_settings.TOTAL_SIZE_FIELD: count,
162
+ }
163
+ )
146
164
 
147
- def get_page_list(self, page_result: BaseModel):
148
- return getattr(page_result, settings.app_settings.LIST_RESPONSE_FIELD, [])
165
+ async def get_page_data(
166
+ self,
167
+ queryset: QuerySet,
168
+ *args, **kwargs,
169
+ ):
170
+ """
171
+ 通用分页,获取序列化后的值
172
+ :param queryset:
173
+ :param args:
174
+ :param kwargs: 其他参数 schema, paginator, prefetch_related_fields
175
+ :return:
176
+ """
177
+ data_list, count = await self.get_queryset_data(queryset=queryset,*args, **kwargs)
178
+ res = self.get_page_schema_func(data_list, count, *args, **kwargs)
179
+ return res
149
180
 
150
181
  def _get_all_decorator(self, *args: Any, **kwargs: Any) -> DecoratedCallable:
151
182
  @get_all_cache_decorator(cache(expire=settings.app_settings.CACHE_GET_ALL_SECONDS, coder=JsonCoder,
152
183
  key_builder=generate_key_builder))
153
184
  async def route(
154
185
  request: Request,
155
- paginator=Depends(paginator_deps()),
186
+ paginator: PagePydantic = Depends(),
156
187
  search: Optional[str] = Depends(search_params_deps(self.search_fields)),
157
- filters: dict = Depends(filter_params_deps(model_class=self.model_class, fields=self.filter_fields,
158
- schema=self.filter_schema)),
188
+ filters: dict = Depends(filter_params_deps(
189
+ model_class=self.model_class, fields=self.filter_fields, schema=self.filter_schema)),
159
190
  extra_filters: dict = Depends(extra_filter_params_deps(schema=self.extra_filter_schema)),
160
191
  token: Optional[str] = Depends(OAuth2PasswordBearer(tokenUrl="token", auto_error=False)),
161
192
  ) -> JSONResponse:
@@ -187,20 +218,14 @@ class GetAllView(BaseView, GetMixin):
187
218
  if not self.get_all_schema:
188
219
  get_all_schema_include = []
189
220
  if self.prefetch_related_fields:
190
- for key, value in self.prefetch_related_fields.items():
191
- if value and type(value) in [list, tuple, set]:
192
- for val in value:
193
- val_str = val
194
- if type(val) in [list, tuple, set]:
195
- val_str = val[0]
196
- get_all_schema_include.append(key + "__" + val_str)
221
+ get_all_schema_include = self._get_extra_related_schema()
197
222
  if hasattr_get_all_schema(self.model_class) or get_all_schema_include:
198
223
  self.get_all_schema = get_all_schema_factory(self.model_class, extra_include=get_all_schema_include)
199
224
  else:
200
225
  self.get_all_schema = self.get_response_schema()
201
- self.get_page_schema = get_page_schema_factory(self.get_all_schema)
202
- self.get_list_schema = get_list_schema_factory(self.get_all_schema)
203
- self.get_all_response_schema_factory = response_factory(self.get_page_schema, name="GetPage")
226
+ self.get_all_page_schema = get_page_schema_factory(self.get_all_schema)
227
+ self.get_all_list_schema = get_list_schema_factory(self.get_all_schema)
228
+ self.get_all_response_schema_factory = response_factory(self.get_all_page_schema, name="GetPage")
204
229
  if not self.get_all_summary:
205
230
  doc = self.get_all.__doc__
206
231
  self.get_all_summary = doc.strip().split("\n")[0] if doc else "Get All"
@@ -14,7 +14,9 @@ from tortoise.queryset import QuerySet
14
14
  from fastgenerateapi.api_view.base_view import BaseView
15
15
  from fastgenerateapi.controller import SearchController, BaseFilter, FilterController
16
16
  from fastgenerateapi.data_type.data_type import DEPENDENCIES
17
- from fastgenerateapi.deps import paginator_deps, filter_params_deps
17
+ from fastgenerateapi.deps import filter_params_deps
18
+ from fastgenerateapi.deps.filter_params_deps import search_params_deps
19
+ from fastgenerateapi.pydantic_utils.base_model import PagePydantic
18
20
  from fastgenerateapi.schemas_factory import get_page_schema_factory, response_factory
19
21
  from fastgenerateapi.schemas_factory.get_all_schema_factory import get_list_schema_factory
20
22
  from fastgenerateapi.schemas_factory.get_relation_schema_factory import get_relation_schema_factory
@@ -54,13 +56,13 @@ class GetRelationView(BaseView):
54
56
  relation_order_by_fields: 多对多关联表排序对应字段
55
57
  """
56
58
 
57
- async def get_relation(self, pk: str, search: str, filters: dict, relation_filters: dict, *args, **kwargs):
59
+ async def get_relation(self, pk: str, search: Optional[str], filters: dict, relation_filters: dict, *args, **kwargs):
58
60
  relation_queryset = await self.get_relation_queryset(filters=relation_filters, *args, **kwargs)
59
61
  id_list = relation_queryset.filter(Q(**{self.path_id_name: pk})).values_list(self.relation_id_name, flat=True)
60
62
 
61
63
  queryset = await self.get_queryset(search=search, filters=filters, *args, **kwargs)
62
64
 
63
- return await self.pagination_data(queryset=queryset, id_list=id_list, *args, **kwargs)
65
+ return await self.get_tree_data(queryset=queryset, id_list=id_list, *args, **kwargs)
64
66
 
65
67
  async def get_relation_queryset(self, filters: dict, *args, **kwargs) -> QuerySet:
66
68
  """
@@ -104,61 +106,52 @@ class GetRelationView(BaseView):
104
106
  """
105
107
  return model
106
108
 
107
- async def pagination_data(
109
+ async def get_tree_data(
108
110
  self,
109
111
  queryset: QuerySet,
110
112
  id_list,
111
- paginator,
113
+ paginator: Optional[PagePydantic] = PagePydantic(),
112
114
  fields: List[Union[str, tuple]] = None,
113
115
  *args, **kwargs
114
116
  ) -> Union[dict, str, None, BaseModel]:
115
117
 
116
118
  data_list = []
117
- if getattr(paginator, settings.app_settings.DETERMINE_WHETHER_PAGE_FIELD) == settings.app_settings.DETERMINE_PAGE_BOOL_VALUE:
119
+ if paginator.no_page:
118
120
  model_list = await queryset.filter(id__in=id_list).all()
119
121
  else:
120
- current_num = getattr(paginator, settings.app_settings.CURRENT_PAGE_FIELD)
121
- page_size = getattr(paginator, settings.app_settings.PAGE_SIZE_FIELD)
122
122
  if self.relation_order_by_fields:
123
- id_list = id_list[cast(int, (current_num - 1) * page_size): page_size]
123
+ id_list = id_list[cast(int, (paginator.page - 1) * paginator.page_size): paginator.page_size]
124
124
  queryset = queryset.filter(id__in=id_list)
125
125
  count = await queryset.count()
126
126
  if self.relation_order_by_fields:
127
127
  model_list = await queryset
128
128
  else:
129
- queryset = queryset.offset(cast(int, (current_num - 1) * page_size))
130
- model_list = await queryset.limit(page_size)
129
+ queryset = queryset.offset(cast(int, (paginator.page - 1) * paginator.page_size))
130
+ model_list = await queryset.limit(paginator.page_size)
131
131
 
132
132
  for model in model_list:
133
-
134
133
  await self.setattr_model(model, prefetch_related_fields=self.prefetch_related_fields, *args, **kwargs)
135
-
136
- # await self.setattr_model_rpc(self.rpc_class, model, self.rpc_param)
137
134
  await self.set_get_relation_model(model)
135
+ data_list.append(self.get_relation_schema.model_validate(model))
138
136
 
139
- if fields:
140
- data_list.append(await self.getattr_model(model=model, fields=fields))
141
- else:
142
- data_list.append(self.get_relation_schema.from_orm(model))
143
-
144
- if getattr(paginator, settings.app_settings.DETERMINE_WHETHER_PAGE_FIELD) == settings.app_settings.DETERMINE_PAGE_BOOL_VALUE:
137
+ if paginator.no_page:
145
138
  return self.get_relation_list_schema(**{
146
139
  settings.app_settings.LIST_RESPONSE_FIELD: data_list,
147
140
  })
148
-
149
- return self.get_relation_page_schema(**{
150
- settings.app_settings.CURRENT_PAGE_FIELD: current_num,
151
- settings.app_settings.PAGE_SIZE_FIELD: page_size,
152
- settings.app_settings.TOTAL_SIZE_FIELD: count,
153
- settings.app_settings.LIST_RESPONSE_FIELD: data_list,
154
- })
141
+ return self.get_relation_page_schema(
142
+ **paginator.model_dump(by_alias=True),
143
+ **{
144
+ settings.app_settings.TOTAL_SIZE_FIELD: count,
145
+ settings.app_settings.LIST_RESPONSE_FIELD: data_list,
146
+ }
147
+ )
155
148
 
156
149
  def _get_relation_decorator(self, *args: Any, **kwargs: Any) -> DecoratedCallable:
157
150
  async def route(
158
151
  pk: str,
159
152
  request: Request,
160
- paginator=Depends(paginator_deps()),
161
- search: str = Query(default="", description="搜索"),
153
+ paginator: PagePydantic = Depends(),
154
+ search: Optional[str] = Depends(search_params_deps(self.search_fields)),
162
155
  filters: dict = Depends(filter_params_deps(model_class=self.model_class, fields=self.filter_fields)),
163
156
  relation_filters: dict = Depends(
164
157
  filter_params_deps(model_class=self.relation_model_class, fields=self.relation_filter_fields)),
@@ -23,7 +23,7 @@ from fastgenerateapi.api_view.base_view import BaseView
23
23
  from fastgenerateapi.api_view.mixin.get_mixin import GetMixin
24
24
  from fastgenerateapi.controller import SearchController, BaseFilter, FilterController
25
25
  from fastgenerateapi.data_type.data_type import DEPENDENCIES
26
- from fastgenerateapi.deps import paginator_deps, filter_params_deps
26
+ from fastgenerateapi.deps import filter_params_deps
27
27
  from fastgenerateapi.deps.tree_params_deps import tree_params_deps
28
28
  from fastgenerateapi.schemas_factory import get_one_schema_factory, response_factory
29
29
  from fastgenerateapi.schemas_factory.get_tree_schema_factory import get_tree_schema_factory
@@ -116,3 +116,30 @@ class DBModelMixin:
116
116
  except:
117
117
  return model_class
118
118
 
119
+ # ############################### 枚举相关方法 ###############################
120
+ @classmethod
121
+ def get_enum_index_by_model(cls, value, model_class, filed):
122
+ """
123
+ 查找枚举的返回值
124
+ :param value:
125
+ :param model_class:
126
+ :param filed:
127
+ :return: 找不到返回-1
128
+ """
129
+ model_field_info = model_class._meta.fields_map[filed]
130
+
131
+ return cls.get_enum_index(value, model_field_info.enum_list, model_field_info.start_num)
132
+
133
+ @classmethod
134
+ def get_enum_index(cls, value, enum_list: List[any], start_num=0) -> int:
135
+ """
136
+ 查找枚举的返回值
137
+ :param value: 枚举值
138
+ :param enum_list: 枚举列表
139
+ :param start_num:
140
+ :return: 找不到返回-1
141
+ """
142
+ try:
143
+ return start_num + enum_list.index(value)
144
+ except Exception as e:
145
+ return -1
@@ -5,7 +5,6 @@ from urllib.parse import quote
5
5
 
6
6
  from fastapi import HTTPException
7
7
  from fastapi.encoders import jsonable_encoder
8
- from pydantic import BaseModel
9
8
 
10
9
  from fastgenerateapi.settings.all_settings import settings
11
10
  from starlette.background import BackgroundTask
@@ -93,7 +92,7 @@ class ResponseMixin:
93
92
  @staticmethod
94
93
  def stream(
95
94
  bytes_io: BytesIO,
96
- file_name: Optional[str] = None,
95
+ filename: Optional[str] = None,
97
96
  media_type: Optional[str] = None,
98
97
  is_xlsx: Optional[bool] = None,
99
98
  is_docx: Optional[bool] = None,
@@ -102,7 +101,7 @@ class ResponseMixin:
102
101
  """
103
102
 
104
103
  :param bytes_io: io.BytesIO()
105
- :param file_name: 文件名称
104
+ :param filename: 文件名称
106
105
  :param media_type: 优先度大于其他参数
107
106
  :param is_xlsx: 自动设置media_type
108
107
  :param is_docx: 自动设置media_type
@@ -118,8 +117,8 @@ class ResponseMixin:
118
117
  elif is_pdf:
119
118
  media_type = "application/pdf"
120
119
  headers = {}
121
- if file_name:
122
- headers["Content-Disposition"] = f"attachment; filename={quote(file_name, safe='/:?=&')}"
120
+ if filename:
121
+ headers["Content-Disposition"] = f"attachment; filename={quote(filename, safe='/:?=&')}"
123
122
  return StreamingResponse(
124
123
  bytes_io,
125
124
  media_type= media_type,
@@ -0,0 +1,49 @@
1
+ from typing import Type, Optional, Dict, List
2
+
3
+ from pydantic.fields import FieldInfo
4
+
5
+ from fastgenerateapi.data_type.data_type import T
6
+
7
+ class ToolMixin:
8
+
9
+ @staticmethod
10
+ def reserve_dict(data: dict) -> dict:
11
+ """
12
+ 字典key,value互转
13
+ """
14
+ result = {}
15
+ for key, val in data.items():
16
+ result[val] = key
17
+ return result
18
+
19
+ @staticmethod
20
+ def get_schema_alise_to_name(schema: Optional[Type[T]]) -> Dict[str, str]:
21
+ """
22
+ 返回 alias 对 name 的字典
23
+ :param schema:
24
+ :return:
25
+ """
26
+ alias_dict = {}
27
+ if schema and hasattr(schema, "model_fields"):
28
+ for field, info in schema.model_fields.items():
29
+ alias_dict[info.alias or field] = field
30
+
31
+ return alias_dict
32
+
33
+ @staticmethod
34
+ def get_schema_alise_to_field_info(schema: Optional[Type[T]]) -> Dict[str, FieldInfo]:
35
+ """
36
+ 返回 alias 对 FieldInfo 的字典
37
+ :param schema:
38
+ :return:
39
+ """
40
+ alias_dict = {}
41
+ if schema and hasattr(schema, "model_fields"):
42
+ for field, info in schema.model_fields.items():
43
+ if info.alias:
44
+ alias_dict[info.alias] = info
45
+ alias_dict[field] = info
46
+
47
+ return alias_dict
48
+
49
+