fastapi-sqlalchemy-toolkit 0.7.14__tar.gz → 0.7.16__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.
- {fastapi_sqlalchemy_toolkit-0.7.14 → fastapi_sqlalchemy_toolkit-0.7.16}/PKG-INFO +1 -1
- {fastapi_sqlalchemy_toolkit-0.7.14 → fastapi_sqlalchemy_toolkit-0.7.16}/fastapi_sqlalchemy_toolkit/model_manager.py +17 -58
- {fastapi_sqlalchemy_toolkit-0.7.14 → fastapi_sqlalchemy_toolkit-0.7.16}/pyproject.toml +1 -1
- {fastapi_sqlalchemy_toolkit-0.7.14 → fastapi_sqlalchemy_toolkit-0.7.16}/.flake8 +0 -0
- {fastapi_sqlalchemy_toolkit-0.7.14 → fastapi_sqlalchemy_toolkit-0.7.16}/.github/workflows/docker-test.yml +0 -0
- {fastapi_sqlalchemy_toolkit-0.7.14 → fastapi_sqlalchemy_toolkit-0.7.16}/.github/workflows/python-publish.yml +0 -0
- {fastapi_sqlalchemy_toolkit-0.7.14 → fastapi_sqlalchemy_toolkit-0.7.16}/.gitignore +0 -0
- {fastapi_sqlalchemy_toolkit-0.7.14 → fastapi_sqlalchemy_toolkit-0.7.16}/.pylintrc +0 -0
- {fastapi_sqlalchemy_toolkit-0.7.14 → fastapi_sqlalchemy_toolkit-0.7.16}/AUTHORS +0 -0
- {fastapi_sqlalchemy_toolkit-0.7.14 → fastapi_sqlalchemy_toolkit-0.7.16}/LICENSE +0 -0
- {fastapi_sqlalchemy_toolkit-0.7.14 → fastapi_sqlalchemy_toolkit-0.7.16}/Makefile +0 -0
- {fastapi_sqlalchemy_toolkit-0.7.14 → fastapi_sqlalchemy_toolkit-0.7.16}/README.md +0 -0
- {fastapi_sqlalchemy_toolkit-0.7.14 → fastapi_sqlalchemy_toolkit-0.7.16}/docs/benefits.md +0 -0
- {fastapi_sqlalchemy_toolkit-0.7.14 → fastapi_sqlalchemy_toolkit-0.7.16}/docs/db_validation.md +0 -0
- {fastapi_sqlalchemy_toolkit-0.7.14 → fastapi_sqlalchemy_toolkit-0.7.16}/docs/extension.md +0 -0
- {fastapi_sqlalchemy_toolkit-0.7.14 → fastapi_sqlalchemy_toolkit-0.7.16}/docs/filtering.md +0 -0
- {fastapi_sqlalchemy_toolkit-0.7.14 → fastapi_sqlalchemy_toolkit-0.7.16}/docs/index.md +0 -0
- {fastapi_sqlalchemy_toolkit-0.7.14 → fastapi_sqlalchemy_toolkit-0.7.16}/docs/ru/benefits.md +0 -0
- {fastapi_sqlalchemy_toolkit-0.7.14 → fastapi_sqlalchemy_toolkit-0.7.16}/docs/ru/db_validation.md +0 -0
- {fastapi_sqlalchemy_toolkit-0.7.14 → fastapi_sqlalchemy_toolkit-0.7.16}/docs/ru/extension.md +0 -0
- {fastapi_sqlalchemy_toolkit-0.7.14 → fastapi_sqlalchemy_toolkit-0.7.16}/docs/ru/filtering.md +0 -0
- {fastapi_sqlalchemy_toolkit-0.7.14 → fastapi_sqlalchemy_toolkit-0.7.16}/docs/ru/index.md +0 -0
- {fastapi_sqlalchemy_toolkit-0.7.14 → fastapi_sqlalchemy_toolkit-0.7.16}/docs/ru/sorting.md +0 -0
- {fastapi_sqlalchemy_toolkit-0.7.14 → fastapi_sqlalchemy_toolkit-0.7.16}/docs/ru/transactions.md +0 -0
- {fastapi_sqlalchemy_toolkit-0.7.14 → fastapi_sqlalchemy_toolkit-0.7.16}/docs/ru/usage.md +0 -0
- {fastapi_sqlalchemy_toolkit-0.7.14 → fastapi_sqlalchemy_toolkit-0.7.16}/docs/ru/utils.md +0 -0
- {fastapi_sqlalchemy_toolkit-0.7.14 → fastapi_sqlalchemy_toolkit-0.7.16}/docs/sorting.md +0 -0
- {fastapi_sqlalchemy_toolkit-0.7.14 → fastapi_sqlalchemy_toolkit-0.7.16}/docs/transactions.md +0 -0
- {fastapi_sqlalchemy_toolkit-0.7.14 → fastapi_sqlalchemy_toolkit-0.7.16}/docs/usage.md +0 -0
- {fastapi_sqlalchemy_toolkit-0.7.14 → fastapi_sqlalchemy_toolkit-0.7.16}/docs/utils.md +0 -0
- {fastapi_sqlalchemy_toolkit-0.7.14 → fastapi_sqlalchemy_toolkit-0.7.16}/examples/app/.env +0 -0
- {fastapi_sqlalchemy_toolkit-0.7.14 → fastapi_sqlalchemy_toolkit-0.7.16}/examples/app/__init__.py +0 -0
- {fastapi_sqlalchemy_toolkit-0.7.14 → fastapi_sqlalchemy_toolkit-0.7.16}/examples/app/api/__init__.py +0 -0
- {fastapi_sqlalchemy_toolkit-0.7.14 → fastapi_sqlalchemy_toolkit-0.7.16}/examples/app/api/api.py +0 -0
- {fastapi_sqlalchemy_toolkit-0.7.14 → fastapi_sqlalchemy_toolkit-0.7.16}/examples/app/api/deps.py +0 -0
- {fastapi_sqlalchemy_toolkit-0.7.14 → fastapi_sqlalchemy_toolkit-0.7.16}/examples/app/api/endpoints/__init__.py +0 -0
- {fastapi_sqlalchemy_toolkit-0.7.14 → fastapi_sqlalchemy_toolkit-0.7.16}/examples/app/api/endpoints/child.py +0 -0
- {fastapi_sqlalchemy_toolkit-0.7.14 → fastapi_sqlalchemy_toolkit-0.7.16}/examples/app/config.py +0 -0
- {fastapi_sqlalchemy_toolkit-0.7.14 → fastapi_sqlalchemy_toolkit-0.7.16}/examples/app/db.py +0 -0
- {fastapi_sqlalchemy_toolkit-0.7.14 → fastapi_sqlalchemy_toolkit-0.7.16}/examples/app/main.py +0 -0
- {fastapi_sqlalchemy_toolkit-0.7.14 → fastapi_sqlalchemy_toolkit-0.7.16}/examples/app/managers.py +0 -0
- {fastapi_sqlalchemy_toolkit-0.7.14 → fastapi_sqlalchemy_toolkit-0.7.16}/examples/app/models.py +0 -0
- {fastapi_sqlalchemy_toolkit-0.7.14 → fastapi_sqlalchemy_toolkit-0.7.16}/examples/app/schemas.py +0 -0
- {fastapi_sqlalchemy_toolkit-0.7.14 → fastapi_sqlalchemy_toolkit-0.7.16}/fastapi_sqlalchemy_toolkit/__init__.py +0 -0
- {fastapi_sqlalchemy_toolkit-0.7.14 → fastapi_sqlalchemy_toolkit-0.7.16}/fastapi_sqlalchemy_toolkit/filters.py +0 -0
- {fastapi_sqlalchemy_toolkit-0.7.14 → fastapi_sqlalchemy_toolkit-0.7.16}/fastapi_sqlalchemy_toolkit/ordering.py +0 -0
- {fastapi_sqlalchemy_toolkit-0.7.14 → fastapi_sqlalchemy_toolkit-0.7.16}/fastapi_sqlalchemy_toolkit/utils.py +0 -0
- {fastapi_sqlalchemy_toolkit-0.7.14 → fastapi_sqlalchemy_toolkit-0.7.16}/mkdocs.yml +0 -0
- {fastapi_sqlalchemy_toolkit-0.7.14 → fastapi_sqlalchemy_toolkit-0.7.16}/requirements/base.txt +0 -0
- {fastapi_sqlalchemy_toolkit-0.7.14 → fastapi_sqlalchemy_toolkit-0.7.16}/requirements/docs.txt +0 -0
- {fastapi_sqlalchemy_toolkit-0.7.14 → fastapi_sqlalchemy_toolkit-0.7.16}/requirements/lint.txt +0 -0
- {fastapi_sqlalchemy_toolkit-0.7.14 → fastapi_sqlalchemy_toolkit-0.7.16}/requirements/test.txt +0 -0
- {fastapi_sqlalchemy_toolkit-0.7.14 → fastapi_sqlalchemy_toolkit-0.7.16}/tests/Dockerfile +0 -0
- {fastapi_sqlalchemy_toolkit-0.7.14 → fastapi_sqlalchemy_toolkit-0.7.16}/tests/__init__.py +0 -0
- {fastapi_sqlalchemy_toolkit-0.7.14 → fastapi_sqlalchemy_toolkit-0.7.16}/tests/conftest.py +0 -0
- {fastapi_sqlalchemy_toolkit-0.7.14 → fastapi_sqlalchemy_toolkit-0.7.16}/tests/db.py +0 -0
- {fastapi_sqlalchemy_toolkit-0.7.14 → fastapi_sqlalchemy_toolkit-0.7.16}/tests/docker-compose.yml +0 -0
- {fastapi_sqlalchemy_toolkit-0.7.14 → fastapi_sqlalchemy_toolkit-0.7.16}/tests/models.py +0 -0
- {fastapi_sqlalchemy_toolkit-0.7.14 → fastapi_sqlalchemy_toolkit-0.7.16}/tests/test_public_methods.py +0 -0
|
@@ -38,7 +38,7 @@ ModelDict = dict[str, Any]
|
|
|
38
38
|
|
|
39
39
|
def sqlalchemy_model_to_dict(model: DeclarativeBase) -> dict:
|
|
40
40
|
db_obj_dict = model.__dict__.copy()
|
|
41
|
-
|
|
41
|
+
db_obj_dict.pop("_sa_instance_state", None)
|
|
42
42
|
return db_obj_dict
|
|
43
43
|
|
|
44
44
|
|
|
@@ -65,27 +65,14 @@ class ModelManager(Generic[ModelT, CreateSchemaT, UpdateSchemaT]):
|
|
|
65
65
|
self.fk_name_to_model: dict[str, type[ModelT]] = {}
|
|
66
66
|
|
|
67
67
|
self.unique_constraints: List[List[str]] = []
|
|
68
|
-
self.nullable_unique_constraints: List[List[str]] = []
|
|
69
68
|
|
|
70
69
|
if hasattr(self.model, "__table_args__"):
|
|
71
70
|
for table_arg in self.model.__table_args__:
|
|
72
71
|
if isinstance(table_arg, UniqueConstraint):
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
if table_arg.dialect_kwargs.get("postgresql_nulls_not_distinct"):
|
|
76
|
-
if table_arg.columns.keys():
|
|
77
|
-
self.nullable_unique_constraints.append(
|
|
78
|
-
table_arg.columns.keys()
|
|
79
|
-
)
|
|
80
|
-
else:
|
|
81
|
-
self.nullable_unique_constraints.append(
|
|
82
|
-
table_arg._pending_colargs
|
|
83
|
-
)
|
|
72
|
+
if table_arg.columns.keys():
|
|
73
|
+
self.unique_constraints.append(table_arg.columns.keys())
|
|
84
74
|
else:
|
|
85
|
-
|
|
86
|
-
self.unique_constraints.append(table_arg.columns.keys())
|
|
87
|
-
else:
|
|
88
|
-
self.unique_constraints.append(table_arg._pending_colargs)
|
|
75
|
+
self.unique_constraints.append(table_arg._pending_colargs)
|
|
89
76
|
|
|
90
77
|
self.reverse_relationships: dict[str, type[ModelT]] = {}
|
|
91
78
|
self.m2m_relationships: dict[str, type[ModelT]] = {}
|
|
@@ -878,7 +865,6 @@ class ModelManager(Generic[ModelT, CreateSchemaT, UpdateSchemaT]):
|
|
|
878
865
|
await self.handle_m2m_fields(session, in_obj)
|
|
879
866
|
await self.validate_unique_fields(session, in_obj, db_obj=db_obj)
|
|
880
867
|
await self.validate_unique_constraints(session, in_obj)
|
|
881
|
-
await self.validate_nullable_unique_constraints(session, in_obj)
|
|
882
868
|
return in_obj
|
|
883
869
|
|
|
884
870
|
def get_select(self, base_stmt: Select | None = None, **_kwargs: Any) -> Select:
|
|
@@ -1093,47 +1079,20 @@ class ModelManager(Generic[ModelT, CreateSchemaT, UpdateSchemaT]):
|
|
|
1093
1079
|
for field in unique_constraint:
|
|
1094
1080
|
if in_obj[field] is not None:
|
|
1095
1081
|
query[field] = in_obj[field]
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
if object_exists:
|
|
1100
|
-
conflicting_fields = ", ".join(unique_constraint)
|
|
1101
|
-
raise HTTPException(
|
|
1102
|
-
status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
|
|
1103
|
-
detail=(
|
|
1104
|
-
f"{self.model.__tablename__} с такими "
|
|
1105
|
-
+ conflicting_fields
|
|
1106
|
-
+ " уже существует."
|
|
1107
|
-
),
|
|
1108
|
-
)
|
|
1109
|
-
|
|
1110
|
-
async def validate_nullable_unique_constraints(
|
|
1111
|
-
self, session: AsyncSession, in_obj: ModelDict
|
|
1112
|
-
) -> None:
|
|
1113
|
-
"""
|
|
1114
|
-
Проверяет, не нарушаются ли nullable UniqueConstraint модели.
|
|
1115
|
-
Поля со значением NULL игнорируются при проверке и не считаются дублированием.
|
|
1116
|
-
"""
|
|
1117
|
-
for unique_constraint in self.nullable_unique_constraints:
|
|
1118
|
-
query = {}
|
|
1119
|
-
if any(in_obj[field] is None for field in unique_constraint):
|
|
1120
|
-
continue
|
|
1121
|
-
|
|
1122
|
-
for field in unique_constraint:
|
|
1123
|
-
query[field] = in_obj[field]
|
|
1124
|
-
object_exists = await self.exists(
|
|
1125
|
-
session, **query, where=(self.model.id != in_obj.get("id"))
|
|
1126
|
-
)
|
|
1127
|
-
if object_exists:
|
|
1128
|
-
conflicting_fields = ", ".join(unique_constraint)
|
|
1129
|
-
raise HTTPException(
|
|
1130
|
-
status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
|
|
1131
|
-
detail=(
|
|
1132
|
-
f"{self.model.__tablename__} с такими "
|
|
1133
|
-
+ conflicting_fields
|
|
1134
|
-
+ " уже существует."
|
|
1135
|
-
),
|
|
1082
|
+
if query:
|
|
1083
|
+
object_exists = await self.exists(
|
|
1084
|
+
session, **query, where=(self.model.id != in_obj.get("id"))
|
|
1136
1085
|
)
|
|
1086
|
+
if object_exists:
|
|
1087
|
+
conflicting_fields = ", ".join(unique_constraint)
|
|
1088
|
+
raise HTTPException(
|
|
1089
|
+
status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
|
|
1090
|
+
detail=(
|
|
1091
|
+
f"{self.model.__tablename__} с такими "
|
|
1092
|
+
+ conflicting_fields
|
|
1093
|
+
+ " уже существует."
|
|
1094
|
+
),
|
|
1095
|
+
)
|
|
1137
1096
|
|
|
1138
1097
|
async def validate_unique_fields(
|
|
1139
1098
|
self,
|
|
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
|
{fastapi_sqlalchemy_toolkit-0.7.14 → fastapi_sqlalchemy_toolkit-0.7.16}/docs/db_validation.md
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{fastapi_sqlalchemy_toolkit-0.7.14 → fastapi_sqlalchemy_toolkit-0.7.16}/docs/ru/db_validation.md
RENAMED
|
File without changes
|
{fastapi_sqlalchemy_toolkit-0.7.14 → fastapi_sqlalchemy_toolkit-0.7.16}/docs/ru/extension.md
RENAMED
|
File without changes
|
{fastapi_sqlalchemy_toolkit-0.7.14 → fastapi_sqlalchemy_toolkit-0.7.16}/docs/ru/filtering.md
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{fastapi_sqlalchemy_toolkit-0.7.14 → fastapi_sqlalchemy_toolkit-0.7.16}/docs/ru/transactions.md
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{fastapi_sqlalchemy_toolkit-0.7.14 → fastapi_sqlalchemy_toolkit-0.7.16}/docs/transactions.md
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{fastapi_sqlalchemy_toolkit-0.7.14 → fastapi_sqlalchemy_toolkit-0.7.16}/examples/app/__init__.py
RENAMED
|
File without changes
|
{fastapi_sqlalchemy_toolkit-0.7.14 → fastapi_sqlalchemy_toolkit-0.7.16}/examples/app/api/__init__.py
RENAMED
|
File without changes
|
{fastapi_sqlalchemy_toolkit-0.7.14 → fastapi_sqlalchemy_toolkit-0.7.16}/examples/app/api/api.py
RENAMED
|
File without changes
|
{fastapi_sqlalchemy_toolkit-0.7.14 → fastapi_sqlalchemy_toolkit-0.7.16}/examples/app/api/deps.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{fastapi_sqlalchemy_toolkit-0.7.14 → fastapi_sqlalchemy_toolkit-0.7.16}/examples/app/config.py
RENAMED
|
File without changes
|
|
File without changes
|
{fastapi_sqlalchemy_toolkit-0.7.14 → fastapi_sqlalchemy_toolkit-0.7.16}/examples/app/main.py
RENAMED
|
File without changes
|
{fastapi_sqlalchemy_toolkit-0.7.14 → fastapi_sqlalchemy_toolkit-0.7.16}/examples/app/managers.py
RENAMED
|
File without changes
|
{fastapi_sqlalchemy_toolkit-0.7.14 → fastapi_sqlalchemy_toolkit-0.7.16}/examples/app/models.py
RENAMED
|
File without changes
|
{fastapi_sqlalchemy_toolkit-0.7.14 → fastapi_sqlalchemy_toolkit-0.7.16}/examples/app/schemas.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{fastapi_sqlalchemy_toolkit-0.7.14 → fastapi_sqlalchemy_toolkit-0.7.16}/requirements/base.txt
RENAMED
|
File without changes
|
{fastapi_sqlalchemy_toolkit-0.7.14 → fastapi_sqlalchemy_toolkit-0.7.16}/requirements/docs.txt
RENAMED
|
File without changes
|
{fastapi_sqlalchemy_toolkit-0.7.14 → fastapi_sqlalchemy_toolkit-0.7.16}/requirements/lint.txt
RENAMED
|
File without changes
|
{fastapi_sqlalchemy_toolkit-0.7.14 → fastapi_sqlalchemy_toolkit-0.7.16}/requirements/test.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{fastapi_sqlalchemy_toolkit-0.7.14 → fastapi_sqlalchemy_toolkit-0.7.16}/tests/docker-compose.yml
RENAMED
|
File without changes
|
|
File without changes
|
{fastapi_sqlalchemy_toolkit-0.7.14 → fastapi_sqlalchemy_toolkit-0.7.16}/tests/test_public_methods.py
RENAMED
|
File without changes
|