fastgenerateapi 0.0.23__py2.py3-none-any.whl → 0.0.26__py2.py3-none-any.whl

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

Potentially problematic release.


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

Files changed (38) hide show
  1. fastgenerateapi/__init__.py +1 -0
  2. fastgenerateapi/__version__.py +1 -1
  3. fastgenerateapi/api_view/base_view.py +29 -14
  4. fastgenerateapi/api_view/delete_filter_view.py +67 -0
  5. fastgenerateapi/api_view/delete_tree_view.py +13 -11
  6. fastgenerateapi/api_view/delete_view.py +12 -11
  7. fastgenerateapi/api_view/get_tree_view.py +2 -1
  8. fastgenerateapi/api_view/mixin/base_mixin.py +1 -1
  9. fastgenerateapi/api_view/mixin/dbmodel_mixin.py +5 -3
  10. fastgenerateapi/channel/consumer.py +5 -0
  11. fastgenerateapi/channel/websocket_view.py +3 -0
  12. fastgenerateapi/controller/ws_controller.py +8 -6
  13. fastgenerateapi/example/models.py +19 -11
  14. fastgenerateapi/example/routers.py +3 -3
  15. fastgenerateapi/example/schemas.py +1 -1
  16. fastgenerateapi/example/views.py +46 -10
  17. fastgenerateapi/my_fields/__init__.py +4 -0
  18. fastgenerateapi/my_fields/aes_field.py +166 -0
  19. fastgenerateapi/my_fields/enum_field.py +215 -0
  20. fastgenerateapi/my_fields/pk_field.py +68 -0
  21. fastgenerateapi/my_fields/pwd_field.py +81 -0
  22. fastgenerateapi/my_fields/soft_delete_field.py +54 -0
  23. fastgenerateapi/pydantic_utils/base_model.py +3 -1
  24. fastgenerateapi/schemas_factory/common_function.py +2 -1
  25. fastgenerateapi/schemas_factory/common_schema_factory.py +1 -1
  26. fastgenerateapi/schemas_factory/create_schema_factory.py +9 -3
  27. fastgenerateapi/schemas_factory/get_all_schema_factory.py +7 -0
  28. fastgenerateapi/schemas_factory/get_one_schema_factory.py +8 -0
  29. fastgenerateapi/schemas_factory/get_tree_schema_factory.py +8 -0
  30. fastgenerateapi/schemas_factory/update_schema_factory.py +9 -3
  31. fastgenerateapi/settings/settings.py +13 -7
  32. fastgenerateapi/utils/aes.py +93 -0
  33. fastgenerateapi/utils/snowflake.py +148 -0
  34. {fastgenerateapi-0.0.23.dist-info → fastgenerateapi-0.0.26.dist-info}/METADATA +1 -1
  35. {fastgenerateapi-0.0.23.dist-info → fastgenerateapi-0.0.26.dist-info}/RECORD +38 -29
  36. {fastgenerateapi-0.0.23.dist-info → fastgenerateapi-0.0.26.dist-info}/WHEEL +1 -1
  37. {fastgenerateapi-0.0.23.dist-info → fastgenerateapi-0.0.26.dist-info}/LICENSE +0 -0
  38. {fastgenerateapi-0.0.23.dist-info → fastgenerateapi-0.0.26.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,215 @@
1
+ from enum import IntEnum
2
+ from typing import (
3
+ TYPE_CHECKING,
4
+ Any,
5
+ Callable,
6
+ Dict,
7
+ Generic,
8
+ List,
9
+ Optional,
10
+ Tuple,
11
+ Type,
12
+ TypeVar,
13
+ Union,
14
+ overload,
15
+ )
16
+
17
+ from fastapi import HTTPException
18
+ from tortoise.fields.data import IntEnumFieldInstance
19
+
20
+ if TYPE_CHECKING: # pragma: nocoverage
21
+ from tortoise.models import Model
22
+
23
+
24
+ class IntEnumField(IntEnumFieldInstance):
25
+ """
26
+ 传入参数数组,默认生成枚举类,数字从 1 开始
27
+ 例如:
28
+ enum_list = ["A", "B"]
29
+ 相当于枚举
30
+ class CategoryEnum(IntEnum):
31
+ one = 1
32
+ two = 2
33
+ 通过方法 get_name 获取对应的值, "A"
34
+ """
35
+
36
+ def __init__(self, enum_list: List[any], **kwargs: Any) -> None:
37
+ kwargs.setdefault("description", self.get_description(enum_list))
38
+ self.enum_list = enum_list
39
+ self.description = kwargs.get("description")
40
+ super().__init__(enum_type=self.create_enum(enum_list), **kwargs)
41
+
42
+ @property
43
+ def constraints(self) -> dict:
44
+ return {
45
+ "ge": 0,
46
+ "le": len(self.enum_list),
47
+ }
48
+
49
+ def to_db_value(self, value: Any, instance: "Union[Type[Model], Model]") -> Any:
50
+ """
51
+ Converts from the Python type to the DB type.
52
+ """
53
+ if value is not None:
54
+ value = int(value) # pylint: disable=E1102
55
+ if value > len(self.enum_list) or 0 > value:
56
+ raise HTTPException(detail=f"枚举值:{value} 校验失败。【{self.description}】", status_code=422)
57
+ self.validate(value)
58
+ return value
59
+
60
+ def to_python_value(self, value: Any) -> Any:
61
+ """
62
+ Converts from the DB type to the Python type.
63
+ """
64
+ if value is not None:
65
+ value = int(value) # pylint: disable=E1102
66
+ self.validate(value)
67
+ return IntEnumClass(value, self.enum_list)
68
+
69
+ def get_description(self, enum_list):
70
+ description = ""
71
+ for index, val in enumerate(enum_list, 1):
72
+ description += f"{index}:{val};"
73
+ return description
74
+
75
+ def create_enum(self, enum_list):
76
+ # 创建枚举类的成员字典,确保值是唯一的
77
+
78
+ members = {self.number_to_words(name): name for name, _ in enumerate(enum_list, 1)}
79
+
80
+ # 使用Enum的元类EnumMeta来动态创建枚举类
81
+ enum_class = IntEnum("CategoryEnum", members)
82
+
83
+ # 返回创建的枚举类
84
+ return enum_class
85
+
86
+ def number_to_words(self, num):
87
+ # 定义数字到单词的映射
88
+ ones = ['', 'one', 'two', 'three', 'four', 'five', 'six', 'seven', 'eight', 'nine', 'ten',
89
+ 'eleven', 'twelve', 'thirteen', 'fourteen', 'fifteen', 'sixteen', 'seventeen', 'eighteen', 'nineteen']
90
+ tens = ['', '', 'twenty', 'thirty', 'forty', 'fifty', 'sixty', 'seventy', 'eighty', 'ninety']
91
+
92
+ if num == 0:
93
+ return 'zero'
94
+
95
+ if num < 20:
96
+ return ones[num]
97
+
98
+ if num < 100:
99
+ ten_digit = num // 10
100
+ one_digit = num % 10
101
+ if one_digit == 0:
102
+ return tens[ten_digit]
103
+ else:
104
+ return tens[ten_digit] + '_' + ones[one_digit]
105
+
106
+ if num < 1000:
107
+ hundred_digit = num // 100
108
+ remaining = num % 100
109
+ return ones[hundred_digit] + '_hundred_' + self.number_to_words(remaining)
110
+
111
+ # 对于大于1000的数字,可以进一步扩展这个函数来处理
112
+ # 但请注意,标准的英文数字读法会变得复杂,涉及"thousand", "million", "billion"等词
113
+
114
+ # 这里仅处理到9999,如果需要处理更大的数字,请继续扩展这个函数
115
+ thousand_digit = num // 1000
116
+ remaining = num % 1000
117
+ return self.number_to_words(thousand_digit) + '_thousand_' + self.number_to_words(remaining)
118
+
119
+
120
+ class IntEnumClass:
121
+ def __init__(self, value: int, name_list: list):
122
+ self.value = value
123
+ self.name_list = name_list
124
+
125
+ def __str__(self):
126
+ return f"{self.value}"
127
+
128
+ @property
129
+ def name(self):
130
+ try:
131
+ return self.name_list[self.value-1]
132
+ except:
133
+ return self.value
134
+
135
+ def __add__(self, other: Union["IntEnumClass", int]):
136
+ if isinstance(other, IntEnumClass):
137
+ return IntEnumClass(self.value + other.value, self.name_list)
138
+ elif isinstance(other, int):
139
+ return IntEnumClass(self.value + other, self.name_list)
140
+ else:
141
+ raise TypeError(f"unsupported operand type(s) for +: 'NamedInt' and '{type(other).__name__}'")
142
+
143
+ def __sub__(self, other: Union["IntEnumClass", int]):
144
+ if isinstance(other, IntEnumClass):
145
+ return IntEnumClass(self.value - other.value, self.name_list)
146
+ elif isinstance(other, int):
147
+ return IntEnumClass(self.value - other, self.name_list)
148
+ else:
149
+ raise TypeError(f"unsupported operand type(s) for -: 'IntEnumClass' and '{type(other).__name__}'")
150
+
151
+ def __mul__(self, other: Union["IntEnumClass", int]):
152
+ if isinstance(other, IntEnumClass):
153
+ return IntEnumClass(self.value * other.value, self.name_list)
154
+ elif isinstance(other, int):
155
+ return IntEnumClass(self.value * other, self.name_list)
156
+ else:
157
+ raise TypeError(f"unsupported operand type(s) for *: 'IntEnumClass' and '{type(other).__name__}'")
158
+
159
+ def __truediv__(self, other: Union["IntEnumClass", int]):
160
+ if isinstance(other, IntEnumClass):
161
+ if other.value == 0:
162
+ raise ZeroDivisionError("division by zero")
163
+ return IntEnumClass(self.value // other.value, self.name_list)
164
+ elif isinstance(other, int):
165
+ if other == 0:
166
+ raise ZeroDivisionError("division by zero")
167
+ return IntEnumClass(self.value // other, self.name_list)
168
+ else:
169
+ raise TypeError(f"unsupported operand type(s) for /: 'IntEnumClass' and '{type(other).__name__}'")
170
+
171
+ def __eq__(self, other: Union["IntEnumClass", int]):
172
+ if isinstance(other, IntEnumClass):
173
+ return self.value == other.value
174
+ elif isinstance(other, int):
175
+ return self.value == other
176
+ return NotImplemented
177
+
178
+ def __ne__(self, other: Union["IntEnumClass", int]):
179
+ result = self.__eq__(other)
180
+ if result is NotImplemented:
181
+ return result
182
+ return not result
183
+
184
+ def __lt__(self, other: Union["IntEnumClass", int]):
185
+ if isinstance(other, IntEnumClass):
186
+ return self.value < other.value
187
+ elif isinstance(other, int):
188
+ return self.value < other
189
+ return NotImplemented
190
+
191
+ def __le__(self, other: Union["IntEnumClass", int]):
192
+ if isinstance(other, IntEnumClass):
193
+ return self.value <= other.value
194
+ elif isinstance(other, int):
195
+ return self.value <= other
196
+ return NotImplemented
197
+
198
+ def __gt__(self, other: Union["IntEnumClass", int]):
199
+ if isinstance(other, IntEnumClass):
200
+ return self.value > other.value
201
+ elif isinstance(other, int):
202
+ return self.value > other
203
+ return NotImplemented
204
+
205
+ def __ge__(self, other: Union["IntEnumClass", int]):
206
+ if isinstance(other, IntEnumClass):
207
+ return self.value >= other.value
208
+ elif isinstance(other, int):
209
+ return self.value >= other
210
+ return NotImplemented
211
+
212
+
213
+
214
+
215
+
@@ -0,0 +1,68 @@
1
+ from typing import (
2
+ TYPE_CHECKING,
3
+ Any,
4
+ Callable,
5
+ Dict,
6
+ Generic,
7
+ List,
8
+ Optional,
9
+ Tuple,
10
+ Type,
11
+ TypeVar,
12
+ Union,
13
+ overload,
14
+ )
15
+ from tortoise.fields import Field
16
+
17
+ if TYPE_CHECKING: # pragma: nocoverage
18
+ from tortoise.models import Model
19
+
20
+ from fastgenerateapi.utils.snowflake import worker
21
+
22
+
23
+ class PrimaryKeyField(Field[str], str):
24
+ """
25
+ Big integer field. (64-bit signed)
26
+ """
27
+
28
+ SQL_TYPE = "BIGINT"
29
+ allows_generated = True
30
+
31
+ def __init__(self, **kwargs: Any) -> None:
32
+ kwargs["generated"] = False
33
+ kwargs["unique"] = True
34
+ kwargs["description"] = "主键"
35
+ kwargs["default"] = worker.get_id
36
+ super().__init__(pk=True, **kwargs)
37
+
38
+ def to_db_value(self, value: Any, instance: "Union[Type[Model], Model]") -> Any:
39
+ """
40
+ Converts from the Python type to the DB type.
41
+ """
42
+ if value is not None:
43
+ value = int(value) # pylint: disable=E1102
44
+ self.validate(value)
45
+ return value
46
+
47
+ def to_python_value(self, value: Any) -> Any:
48
+ """
49
+ Converts from the DB type to the Python type.
50
+ """
51
+ if value is not None:
52
+ value = str(value) # pylint: disable=E1102
53
+ self.validate(value)
54
+ return value
55
+
56
+
57
+
58
+
59
+
60
+
61
+
62
+
63
+
64
+
65
+
66
+
67
+
68
+
@@ -0,0 +1,81 @@
1
+ from typing import (
2
+ TYPE_CHECKING,
3
+ Any,
4
+ Callable,
5
+ Dict,
6
+ Generic,
7
+ List,
8
+ Optional,
9
+ Tuple,
10
+ Type,
11
+ TypeVar,
12
+ Union,
13
+ overload,
14
+ )
15
+
16
+ from passlib.handlers.pbkdf2 import pbkdf2_sha256
17
+ from tortoise.fields import CharField
18
+ if TYPE_CHECKING: # pragma: nocoverage
19
+ from tortoise.models import Model
20
+
21
+
22
+ class PasswordField(CharField):
23
+ """
24
+ Character field.
25
+
26
+ You must provide the following:
27
+
28
+ ``salt`` (str):
29
+ """
30
+
31
+ def __init__(self, salt: str, rounds=1000, **kwargs: Any) -> None:
32
+ kwargs.setdefault("max_length", 255)
33
+ kwargs.setdefault("description", "密码")
34
+ self.salt = salt
35
+ self.rounds = rounds
36
+ super().__init__(**kwargs)
37
+
38
+ def to_db_value(self, value: Any, instance: "Union[Type[Model], Model]") -> Any:
39
+ """
40
+ Converts from the Python type to the DB type.
41
+ """
42
+ if value is not None:
43
+ if not isinstance(value, self.field_type):
44
+ value = self.field_type(value) # pylint: disable=E1102
45
+ custom_pbkdf2 = pbkdf2_sha256.using(salt=self.salt.encode('utf-8'), rounds=self.rounds)
46
+ value = custom_pbkdf2.hash(value)
47
+
48
+ self.validate(value)
49
+ return value
50
+
51
+ def to_python_value(self, value: Any) -> Any:
52
+ """
53
+ Converts from the DB type to the Python type.
54
+ """
55
+ if value is not None and not isinstance(value, self.field_type):
56
+ value = PasswordString(self.field_type(value), self.salt, self.rounds) # pylint: disable=E1102
57
+ self.validate(value)
58
+ return value
59
+
60
+
61
+ class PasswordString(str):
62
+ def __init__(self, password, salt, rounds):
63
+ self.value = password
64
+ self.salt = salt
65
+ self.rounds = rounds
66
+ super().__init__()
67
+
68
+ def __str__(self):
69
+ return self.value
70
+
71
+ def check_valid(self, password: str) -> bool:
72
+ """
73
+ 检查密码是否正确
74
+ """
75
+ custom_pbkdf2 = pbkdf2_sha256.using(salt=self.salt.encode('utf-8'), rounds=self.rounds)
76
+ return self.password == custom_pbkdf2.hash(password)
77
+
78
+
79
+
80
+
81
+
@@ -0,0 +1,54 @@
1
+ from typing import (
2
+ TYPE_CHECKING,
3
+ Any,
4
+ Callable,
5
+ Dict,
6
+ Generic,
7
+ List,
8
+ Optional,
9
+ Tuple,
10
+ Type,
11
+ TypeVar,
12
+ Union,
13
+ overload,
14
+ )
15
+ from tortoise.fields import IntField
16
+ if TYPE_CHECKING: # pragma: nocoverage
17
+ from tortoise.models import Model
18
+
19
+
20
+ class SoftDeleteField(IntField):
21
+ """
22
+ Integer field. (64-bit signed)
23
+ """
24
+
25
+ allows_generated = False
26
+
27
+ def __init__(self, **kwargs: Any) -> None:
28
+ kwargs.setdefault("index", True)
29
+ kwargs.setdefault("null", True)
30
+ kwargs.setdefault("default", None)
31
+ kwargs.setdefault("description", "软删除")
32
+ super().__init__(**kwargs)
33
+
34
+ def to_db_value(self, value: Any, instance: "Union[Type[Model], Model]") -> Any:
35
+ """
36
+ Converts from the Python type to the DB type.
37
+ """
38
+ if value is not None and not isinstance(value, self.field_type):
39
+ value = self.field_type(value) # pylint: disable=E1102
40
+ if value == 0:
41
+ value = None
42
+ self.validate(value)
43
+ return value
44
+
45
+ def to_python_value(self, value: Any) -> Any:
46
+ """
47
+ Converts from the DB type to the Python type.
48
+ """
49
+ if value is not None and not isinstance(value, self.field_type):
50
+ value = self.field_type(value) # pylint: disable=E1102
51
+ self.validate(value)
52
+ return value
53
+
54
+
@@ -10,12 +10,14 @@ class BaseModel(PydanticBaseModel):
10
10
  json_encoders = JSON_ENCODERS
11
11
  extra = Extra.ignore
12
12
  orm_mode = True
13
+ from_attributes = True
13
14
 
14
15
 
15
16
  class Config(BaseConfig):
16
17
  json_encoders = JSON_ENCODERS
17
18
  extra = Extra.ignore
18
- orm_mode = True
19
+ orm_mode = True # v1 版本
20
+ from_attributes = True # v2 版本
19
21
 
20
22
 
21
23
  class QueryConfig(BaseConfig):
@@ -63,7 +63,8 @@ def get_field_info_from_model_class(model_class: Type[Model], field: str, descri
63
63
  return Optional[str], FieldInfo(default=None, description=f"{field}")
64
64
  return get_field_info(value, description=description)
65
65
 
66
- if field_info := model_class._meta.fields_map.get(field.split("__", maxsplit=1)[0]):
66
+ field_info = model_class._meta.fields_map.get(field.split("__", maxsplit=1)[0])
67
+ if field_info:
67
68
  description += field_info.description or ""
68
69
 
69
70
  model_class = DBModelMixin._get_foreign_key_relation_class(model_class, field.split("__", maxsplit=1)[0])
@@ -26,7 +26,7 @@ def common_schema_factory(
26
26
  include_fields = set()
27
27
  exclude_fields = set()
28
28
  if exclude_readonly:
29
- exclude_fields.update(["id", "is_active", "created_at", "modified_at", "updated_at"])
29
+ exclude_fields.update(["id", "is_active", "deleted_at", "created_at", "modified_at", "updated_at"])
30
30
  if hasattr(model_class, "PydanticMeta"):
31
31
  if hasattr(model_class.PydanticMeta, "include"):
32
32
  include_fields_dict = get_dict_from_pydanticmeta(model_class, model_class.PydanticMeta.include)
@@ -34,10 +34,16 @@ def create_schema_factory(
34
34
  include_fields.update(all_fields_info.keys())
35
35
  if hasattr(model_class.PydanticMeta, "exclude"):
36
36
  exclude_fields.update(model_class.PydanticMeta.exclude)
37
+ if hasattr(model_class.PydanticMeta, "save_include"):
38
+ save_include_fields_dict = get_dict_from_pydanticmeta(model_class, model_class.PydanticMeta.save_include)
39
+ all_fields_info.update(save_include_fields_dict)
40
+ include_fields.update(save_include_fields_dict.keys())
37
41
  if hasattr(model_class.PydanticMeta, "create_include"):
38
- get_one_include_fields_dict = get_dict_from_pydanticmeta(model_class, model_class.PydanticMeta.create_include)
39
- all_fields_info.update(get_one_include_fields_dict)
40
- include_fields.update(get_one_include_fields_dict.keys())
42
+ create_include_fields_dict = get_dict_from_pydanticmeta(model_class, model_class.PydanticMeta.create_include)
43
+ all_fields_info.update(create_include_fields_dict)
44
+ include_fields.update(create_include_fields_dict.keys())
45
+ if hasattr(model_class.PydanticMeta, "save_exclude"):
46
+ exclude_fields.update(model_class.PydanticMeta.save_exclude)
41
47
  if hasattr(model_class.PydanticMeta, "create_exclude"):
42
48
  exclude_fields.update(model_class.PydanticMeta.create_exclude)
43
49
  else:
@@ -40,6 +40,13 @@ def get_all_schema_factory(
40
40
  if hasattr(model_class.PydanticMeta, "exclude"):
41
41
  exclude_fields.update(model_class.PydanticMeta.exclude)
42
42
 
43
+ if hasattr(model_class.PydanticMeta, "get_include"):
44
+ get_include_fields_dict = get_dict_from_pydanticmeta(model_class, model_class.PydanticMeta.get_include)
45
+ all_fields_info.update(get_include_fields_dict)
46
+ include_fields.update(get_include_fields_dict.keys())
47
+ if hasattr(model_class.PydanticMeta, "get_exclude"):
48
+ exclude_fields.update(model_class.PydanticMeta.get_exclude)
49
+
43
50
  # get_all_include
44
51
  if hasattr(model_class.PydanticMeta, "get_all_include"):
45
52
  get_all_include_fields_dict = get_dict_from_pydanticmeta(model_class, model_class.PydanticMeta.get_all_include)
@@ -33,6 +33,14 @@ def get_one_schema_factory(
33
33
  include_fields.update(all_fields_info.keys())
34
34
  if hasattr(model_class.PydanticMeta, "exclude"):
35
35
  exclude_fields.update(model_class.PydanticMeta.exclude)
36
+
37
+ if hasattr(model_class.PydanticMeta, "get_include"):
38
+ get_include_fields_dict = get_dict_from_pydanticmeta(model_class, model_class.PydanticMeta.get_include)
39
+ all_fields_info.update(get_include_fields_dict)
40
+ include_fields.update(get_include_fields_dict.keys())
41
+ if hasattr(model_class.PydanticMeta, "get_exclude"):
42
+ exclude_fields.update(model_class.PydanticMeta.get_exclude)
43
+
36
44
  if hasattr(model_class.PydanticMeta, "get_one_include"):
37
45
  get_one_include_fields_dict = get_dict_from_pydanticmeta(model_class, model_class.PydanticMeta.get_one_include)
38
46
  all_fields_info.update(get_one_include_fields_dict)
@@ -38,6 +38,14 @@ def get_tree_schema_factory(
38
38
  include_fields.update(include_fields_dict.keys())
39
39
  else:
40
40
  include_fields.update(all_fields_info.keys())
41
+
42
+ if hasattr(model_class.PydanticMeta, "get_include"):
43
+ get_include_fields_dict = get_dict_from_pydanticmeta(model_class, model_class.PydanticMeta.get_include)
44
+ all_fields_info.update(get_include_fields_dict)
45
+ include_fields.update(get_include_fields_dict.keys())
46
+ if hasattr(model_class.PydanticMeta, "get_exclude"):
47
+ exclude_fields.update(model_class.PydanticMeta.get_exclude)
48
+
41
49
  if hasattr(model_class.PydanticMeta, "get_tree_exclude"):
42
50
  exclude_fields.update(model_class.PydanticMeta.get_tree_exclude)
43
51
  if hasattr(model_class.PydanticMeta, "exclude"):
@@ -34,10 +34,16 @@ def update_schema_factory(
34
34
  include_fields.update(all_fields_info.keys())
35
35
  if hasattr(model_class.PydanticMeta, "exclude"):
36
36
  exclude_fields.update(model_class.PydanticMeta.exclude)
37
+ if hasattr(model_class.PydanticMeta, "save_include"):
38
+ save_include_fields_dict = get_dict_from_pydanticmeta(model_class, model_class.PydanticMeta.save_include)
39
+ all_fields_info.update(save_include_fields_dict)
40
+ include_fields.update(save_include_fields_dict.keys())
37
41
  if hasattr(model_class.PydanticMeta, "update_include"):
38
- get_one_include_fields_dict = get_dict_from_pydanticmeta(model_class, model_class.PydanticMeta.update_include)
39
- all_fields_info.update(get_one_include_fields_dict)
40
- include_fields.update(get_one_include_fields_dict.keys())
42
+ update_include_fields_dict = get_dict_from_pydanticmeta(model_class, model_class.PydanticMeta.update_include)
43
+ all_fields_info.update(update_include_fields_dict)
44
+ include_fields.update(update_include_fields_dict.keys())
45
+ if hasattr(model_class.PydanticMeta, "save_exclude"):
46
+ exclude_fields.update(model_class.PydanticMeta.update_exclude)
41
47
  if hasattr(model_class.PydanticMeta, "update_exclude"):
42
48
  exclude_fields.update(model_class.PydanticMeta.update_exclude)
43
49
  else:
@@ -29,12 +29,13 @@ class AppSettings(BaseSettings):
29
29
  ROUTER_WHETHER_UNDERLINE_TO_STRIKE: Optional[bool] = Field(default=False, description="路由是否下划线转中划线")
30
30
  ROUTER_WHETHER_ADD_SUFFIX: Optional[bool] = Field(default=True, description="增删改查路由是否添加后缀")
31
31
  ROUTER_CREATE_SUFFIX_FIELD: Optional[str] = Field(default='create', description="创建路由后缀字段")
32
- ROUTER_GET_ONE_SUFFIX_FIELD: Optional[str] = Field(default='get-one', description="获取一个路由后缀字段")
33
- ROUTER_GET_ALL_SUFFIX_FIELD: Optional[str] = Field(default='get-all', description="获取列表路由后缀字段")
34
- ROUTER_GET_TREE_SUFFIX_FIELD: Optional[str] = Field(default='get-tree', description="获取树状数据路由后缀字段")
32
+ ROUTER_GET_ONE_SUFFIX_FIELD: Optional[str] = Field(default='get_one', description="获取一个路由后缀字段")
33
+ ROUTER_GET_ALL_SUFFIX_FIELD: Optional[str] = Field(default='get_all', description="获取列表路由后缀字段")
34
+ ROUTER_GET_TREE_SUFFIX_FIELD: Optional[str] = Field(default='get_tree', description="获取树状数据路由后缀字段")
35
35
  ROUTER_UPDATE_SUFFIX_FIELD: Optional[str] = Field(default='update', description="修改路由后缀字段")
36
36
  ROUTER_DELETE_SUFFIX_FIELD: Optional[str] = Field(default='delete', description="删除路由后缀字段")
37
- ROUTER_RECURSION_DELETE_SUFFIX_FIELD: Optional[str] = Field(default='delete-tree', description="递归删除路由后缀字段")
37
+ ROUTER_RECURSION_DELETE_SUFFIX_FIELD: Optional[str] = Field(default='delete_tree', description="递归删除路由后缀字段")
38
+ ROUTER_FILTER_DELETE_SUFFIX_FIELD: Optional[str] = Field(default='delete_filter', description="递归删除路由后缀字段")
38
39
 
39
40
  # 函数转换路由时,默认添加字段,(遵循restful规范时,get路由处理方案)
40
41
  RESTFUL_GET_ROUTER_ADD_PREFIX: Optional[str] = Field(default='', description="函数转换路由时:前缀添加字段")
@@ -46,9 +47,14 @@ class AppSettings(BaseSettings):
46
47
  RESTFUL_DELETE_ROUTER_ADD_PREFIX: Optional[str] = Field(default='', description="函数转换路由时:前缀添加字段")
47
48
  RESTFUL_DELETE_ROUTER_ADD_SUFFIX: Optional[str] = Field(default='', description="函数转换路由时:后缀pk前添加字段")
48
49
 
50
+ # 分布式id
51
+ WORKER_ID: Optional[int] = Field(default=1, description="数据中心(机器区域)ID")
52
+ DATACENTER_ID: Optional[int] = Field(default=1, description="机器ID")
53
+
49
54
  # 数据库字段默认值
50
- WHETHER_DELETE_FIELD: Optional[str] = Field(default="is_active", description="是否删除字段")
51
- ACTIVE_DEFAULT_VALUE: Optional[bool] = Field(default=True, description="有效的默认值")
55
+ WHETHER_DELETE_FIELD: Optional[str] = Field(default="deleted_at", description="是否删除字段;推荐命名 >> deleted_at;is_active")
56
+ DELETE_FIELD_TYPE: Optional[str] = Field(default="time", description="删除字段类型;推荐命名 >> time;bool")
57
+ # ACTIVE_DEFAULT_VALUE: Optional[bool] = Field(default=True, description="有效的默认值")
52
58
  GET_EXCLUDE_ACTIVE_VALUE: Optional[bool] = Field(default=True, description="查询结果是否排除有效字段")
53
59
  CREATE_EXCLUDE_ACTIVE_VALUE: Optional[bool] = Field(default=True, description="创建是否排除有效字段")
54
60
  UPDATE_EXCLUDE_ACTIVE_VALUE: Optional[bool] = Field(default=True, description="修改是否排除有效字段")
@@ -70,7 +76,7 @@ class AppSettings(BaseSettings):
70
76
  SCHEMAS_UNDERLINE_WHETHER_DOUBLE_TO_SINGLE: Optional[bool] = Field(default=True, description="序列化字段是否双下划线转单下划线")
71
77
 
72
78
  class Config:
73
- # env_prefix = 'APP_'
79
+ env_prefix = 'APP_'
74
80
  env_file = "./.env"
75
81
  case_sensitive = True
76
82