xn-model 0.10.3.dev1__py3-none-any.whl → 0.10.4__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.
- x_model/__init__.py +0 -19
- x_model/model.py +87 -245
- x_model/pydantic.py +0 -28
- {xn_model-0.10.3.dev1.dist-info → xn_model-0.10.4.dist-info}/METADATA +1 -3
- xn_model-0.10.4.dist-info/RECORD +9 -0
- x_model/enum.py +0 -31
- xn_model-0.10.3.dev1.dist-info/RECORD +0 -10
- {xn_model-0.10.3.dev1.dist-info → xn_model-0.10.4.dist-info}/WHEEL +0 -0
- {xn_model-0.10.3.dev1.dist-info → xn_model-0.10.4.dist-info}/top_level.txt +0 -0
x_model/__init__.py
CHANGED
|
@@ -3,25 +3,6 @@ from tortoise import Tortoise, connections, ConfigurationError
|
|
|
3
3
|
from tortoise.backends.asyncpg import AsyncpgDBClient
|
|
4
4
|
from tortoise.exceptions import DBConnectionError
|
|
5
5
|
|
|
6
|
-
from .enum import FieldType
|
|
7
|
-
from .field import PointField, RangeField, PolygonField, CollectionField, ListField, DatetimeSecField
|
|
8
|
-
from .model import Model, TsModel, User
|
|
9
|
-
from .func import Array
|
|
10
|
-
|
|
11
|
-
__all__ = [
|
|
12
|
-
"FieldType",
|
|
13
|
-
"PointField",
|
|
14
|
-
"RangeField",
|
|
15
|
-
"PolygonField",
|
|
16
|
-
"CollectionField",
|
|
17
|
-
"ListField",
|
|
18
|
-
"DatetimeSecField",
|
|
19
|
-
"Model",
|
|
20
|
-
"TsModel",
|
|
21
|
-
"User",
|
|
22
|
-
"Array",
|
|
23
|
-
]
|
|
24
|
-
|
|
25
6
|
|
|
26
7
|
async def init_db(dsn: str, models: ModuleType, create_tables: bool = False) -> AsyncpgDBClient | str:
|
|
27
8
|
try:
|
x_model/model.py
CHANGED
|
@@ -1,172 +1,43 @@
|
|
|
1
1
|
from datetime import datetime
|
|
2
|
-
from passlib.context import CryptContext
|
|
3
2
|
from pydantic import create_model
|
|
4
|
-
from tortoise import Model as
|
|
5
|
-
from tortoise.contrib.postgres.fields import ArrayField
|
|
3
|
+
from tortoise import Model as TortoiseModel
|
|
6
4
|
from tortoise.contrib.pydantic import pydantic_model_creator, PydanticModel
|
|
7
|
-
from tortoise
|
|
8
|
-
Field,
|
|
9
|
-
CharField,
|
|
10
|
-
IntField,
|
|
11
|
-
SmallIntField,
|
|
12
|
-
BigIntField,
|
|
13
|
-
DecimalField,
|
|
14
|
-
FloatField,
|
|
15
|
-
TextField,
|
|
16
|
-
BooleanField,
|
|
17
|
-
DatetimeField,
|
|
18
|
-
DateField,
|
|
19
|
-
TimeField,
|
|
20
|
-
JSONField,
|
|
21
|
-
ForeignKeyRelation,
|
|
22
|
-
OneToOneRelation,
|
|
23
|
-
ManyToManyRelation,
|
|
24
|
-
ForeignKeyNullableRelation,
|
|
25
|
-
OneToOneNullableRelation,
|
|
26
|
-
IntEnumField,
|
|
27
|
-
)
|
|
28
|
-
from tortoise.fields.data import IntEnumFieldInstance, CharEnumFieldInstance
|
|
29
|
-
from tortoise.fields.relational import (
|
|
30
|
-
BackwardFKRelation,
|
|
31
|
-
ForeignKeyFieldInstance,
|
|
32
|
-
ManyToManyFieldInstance,
|
|
33
|
-
OneToOneFieldInstance,
|
|
34
|
-
BackwardOneToOneRelation,
|
|
35
|
-
RelationalField,
|
|
36
|
-
)
|
|
5
|
+
from tortoise import fields
|
|
37
6
|
from tortoise.models import MetaInfo
|
|
38
7
|
from tortoise.queryset import QuerySet
|
|
39
8
|
|
|
40
|
-
from x_model import
|
|
41
|
-
from x_model.enum import UserStatus, UserRole
|
|
42
|
-
from x_model.field import DatetimeSecField, SetField
|
|
9
|
+
from x_model.field import DatetimeSecField
|
|
43
10
|
from x_model.pydantic import PydList
|
|
44
11
|
|
|
45
12
|
|
|
46
|
-
class
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
_sorts: list[str] = ["-id"]
|
|
51
|
-
_ownable_fields: dict[str, str | None] = {"one": None, "list": None, "in": None}
|
|
52
|
-
_pydIn: type[PydanticModel] = None
|
|
53
|
-
_pyd: type[PydanticModel] = None
|
|
54
|
-
_pydListItem: type[PydanticModel] = None
|
|
55
|
-
_permissions: tuple[bool, bool, bool] = True, True, True
|
|
56
|
-
|
|
57
|
-
@classmethod
|
|
58
|
-
def cols(cls) -> list[dict]:
|
|
59
|
-
meta = cls._meta
|
|
60
|
-
return [
|
|
61
|
-
{"data": c, "orderable": c not in meta.fetch_fields or c in meta.fk_fields}
|
|
62
|
-
for c in meta.fields_map
|
|
63
|
-
if not c.endswith("_id")
|
|
64
|
-
]
|
|
65
|
-
|
|
66
|
-
@classmethod
|
|
67
|
-
def pyd(cls) -> type[PydanticModel]:
|
|
68
|
-
cls._pyd = cls._pyd or pydantic_model_creator(cls)
|
|
69
|
-
return cls._pyd
|
|
70
|
-
|
|
71
|
-
@classmethod
|
|
72
|
-
def pydIn(cls) -> type[PydanticModel]:
|
|
73
|
-
if not cls._pydIn:
|
|
74
|
-
opts = tuple(k for k, v in cls._meta.fields_map.items() if not v.required)
|
|
75
|
-
cls._pydIn = pydantic_model_creator(
|
|
76
|
-
cls,
|
|
77
|
-
name=cls.__name__ + "In",
|
|
78
|
-
meta_override=cls.PydanticMetaIn,
|
|
79
|
-
optional=opts,
|
|
80
|
-
exclude_readonly=True,
|
|
81
|
-
exclude=("created_at", "updated_at"),
|
|
82
|
-
)
|
|
83
|
-
if m2ms := cls._meta.m2m_fields: # hack for direct inserting m2m values
|
|
84
|
-
cls._pydIn = create_model(
|
|
85
|
-
cls._pydIn.__name__, __base__=cls._pydIn, **{m2m: (list[int] | None, None) for m2m in m2ms}
|
|
86
|
-
)
|
|
87
|
-
return cls._pydIn
|
|
88
|
-
|
|
89
|
-
@classmethod
|
|
90
|
-
def pydListItem(cls) -> type[PydanticModel]:
|
|
91
|
-
if not cls._pydListItem:
|
|
92
|
-
cls._pydListItem = pydantic_model_creator(
|
|
93
|
-
cls, name=cls.__name__ + "ListItem", meta_override=cls.PydanticMetaListItem
|
|
94
|
-
)
|
|
95
|
-
return cls._pydListItem
|
|
96
|
-
|
|
97
|
-
@classmethod
|
|
98
|
-
def pydsList(cls) -> type[PydList]:
|
|
99
|
-
return create_model(
|
|
100
|
-
cls.__name__ + "List",
|
|
101
|
-
data=(list[cls.pydListItem()], []),
|
|
102
|
-
total=(int, 0),
|
|
103
|
-
filtered=(int | None, None),
|
|
104
|
-
__base__=PydList[cls.pydListItem()],
|
|
105
|
-
)
|
|
13
|
+
class BaseModel(TortoiseModel):
|
|
14
|
+
# todo: resolve ownable + add only own list method
|
|
15
|
+
# todo: refact: clean old garbage
|
|
16
|
+
id: int = fields.IntField(True)
|
|
106
17
|
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
if owner and (of := cls._ownable_fields.get("one")):
|
|
110
|
-
kwargs.update({of: owner})
|
|
111
|
-
q = cls.get(id=uid, **kwargs)
|
|
112
|
-
return await cls.pyd().from_queryset_single(q)
|
|
113
|
-
|
|
114
|
-
@classmethod
|
|
115
|
-
def pageQuery(
|
|
116
|
-
cls, sorts: list[str], limit: int = 1000, offset: int = 0, q: str = None, owner: int = None, **kwargs
|
|
117
|
-
) -> QuerySet:
|
|
118
|
-
rels, keys = [], ["id"]
|
|
119
|
-
for nam in cls._name:
|
|
120
|
-
parts = nam.split("__")
|
|
121
|
-
if len(parts) > 1:
|
|
122
|
-
rels.append("__".join(parts[:-1]))
|
|
123
|
-
keys.append(nam)
|
|
124
|
-
query = (
|
|
125
|
-
cls.filter(**kwargs)
|
|
126
|
-
.order_by(*sorts)
|
|
127
|
-
.limit(limit)
|
|
128
|
-
.offset(offset)
|
|
129
|
-
.prefetch_related(*(cls._meta.fetch_fields & set(kwargs)), *rels)
|
|
130
|
-
)
|
|
131
|
-
if q:
|
|
132
|
-
query = query.filter(**{f"{cls._name}__icontains": q})
|
|
133
|
-
if owner and (of := cls._ownable_fields.get("list")):
|
|
134
|
-
query = query.filter(**{of: owner})
|
|
135
|
-
return query
|
|
18
|
+
_name: tuple[str] = {"name"}
|
|
19
|
+
_sorts: tuple[str] = ["-id"]
|
|
136
20
|
|
|
137
|
-
|
|
138
|
-
async def pagePyd(
|
|
139
|
-
cls, sorts: list[str], limit: int = 1000, offset: int = 0, q: str = None, owner: int = None, **kwargs
|
|
140
|
-
) -> PydList:
|
|
141
|
-
kwargs = {k: v for k, v in kwargs.items() if v is not None}
|
|
142
|
-
pyd = cls.pydListItem()
|
|
143
|
-
query = cls.pageQuery(sorts, limit, offset, q, owner, **kwargs)
|
|
144
|
-
await query
|
|
145
|
-
data = await pyd.from_queryset(query)
|
|
146
|
-
if limit - (li := len(data)):
|
|
147
|
-
filtered = total = li + offset
|
|
148
|
-
else:
|
|
149
|
-
total = await cls.all().count()
|
|
150
|
-
filtered_query = cls.filter(**kwargs)
|
|
151
|
-
if q:
|
|
152
|
-
filtered_query = filtered_query.filter(**{f"{cls._name}__icontains": q})
|
|
153
|
-
filtered = await filtered_query.count()
|
|
154
|
-
pyds = cls.pydsList()
|
|
155
|
-
return pyds(data=data, total=total, filtered=filtered)
|
|
156
|
-
|
|
157
|
-
def repr(self) -> str:
|
|
21
|
+
def repr(self, sep: str = " ") -> str:
|
|
158
22
|
if self._name in self._meta.db_fields:
|
|
159
|
-
return
|
|
23
|
+
return sep.join(getattr(self, name_fragment) for name_fragment in self._name)
|
|
160
24
|
return self.__repr__()
|
|
161
25
|
|
|
162
26
|
@classmethod
|
|
163
|
-
async def
|
|
27
|
+
async def get_or_create_by_name(cls, name: str, attr_name: str = None, def_dict: dict = None) -> TortoiseModel:
|
|
164
28
|
attr_name = attr_name or list(cls._name)[0]
|
|
165
29
|
if not (obj := await cls.get_or_none(**{attr_name: name})):
|
|
166
30
|
next_id = (await cls.all().order_by("-id").first()).id + 1
|
|
167
31
|
obj = await cls.create(id=next_id, **{attr_name: name}, **(def_dict or {}))
|
|
168
32
|
return obj
|
|
169
33
|
|
|
34
|
+
@classmethod
|
|
35
|
+
def _page_query(cls, sorts: tuple[str], limit: int = 1000, offset: int = 0, q: str = None, **filters) -> QuerySet:
|
|
36
|
+
query = cls.filter(**filters).order_by(*sorts).limit(limit).offset(offset)
|
|
37
|
+
if q:
|
|
38
|
+
query = query.filter(**{f"{cls._name}__icontains": q})
|
|
39
|
+
return query
|
|
40
|
+
|
|
170
41
|
@classmethod
|
|
171
42
|
async def upsert(cls, data: dict, oid=None):
|
|
172
43
|
meta: MetaInfo = cls._meta
|
|
@@ -188,7 +59,7 @@ class Model(BaseModel):
|
|
|
188
59
|
# save relations
|
|
189
60
|
for k, ids in m2ms.items():
|
|
190
61
|
if ids:
|
|
191
|
-
m2m_rel: ManyToManyRelation = getattr(obj, k)
|
|
62
|
+
m2m_rel: fields.ManyToManyRelation = getattr(obj, k)
|
|
192
63
|
items = [await m2m_rel.remote_model[i] for i in ids]
|
|
193
64
|
await m2m_rel.clear() # for updating, not just adding
|
|
194
65
|
await m2m_rel.add(*items)
|
|
@@ -204,73 +75,19 @@ class Model(BaseModel):
|
|
|
204
75
|
await obj.fetch_related(*cls._meta.fetch_fields)
|
|
205
76
|
return obj
|
|
206
77
|
|
|
207
|
-
@classmethod
|
|
208
|
-
def field_input_map(cls) -> dict:
|
|
209
|
-
def type2input(ft: type[Field]):
|
|
210
|
-
dry = {
|
|
211
|
-
"base_field": hasattr(ft, "base_field") and {**type2input(ft.base_field)},
|
|
212
|
-
"step": hasattr(ft, "step") and ft.step,
|
|
213
|
-
"labels": hasattr(ft, "labels") and ft.labels,
|
|
214
|
-
}
|
|
215
|
-
type2inputs: {Field: dict} = {
|
|
216
|
-
CharField: {"input": FieldType.input.name},
|
|
217
|
-
IntField: {"input": FieldType.input.name, "type": "number"},
|
|
218
|
-
SmallIntField: {"input": FieldType.input.name, "type": "number"},
|
|
219
|
-
BigIntField: {"input": FieldType.input.name, "type": "number"},
|
|
220
|
-
DecimalField: {"input": FieldType.input.name, "type": "number", "step": "0.01"},
|
|
221
|
-
FloatField: {"input": FieldType.input.name, "type": "number", "step": "0.001"},
|
|
222
|
-
TextField: {"input": FieldType.textarea.name, "rows": "2"},
|
|
223
|
-
BooleanField: {"input": FieldType.checkbox.name},
|
|
224
|
-
DatetimeField: {"input": FieldType.input.name, "type": "datetime"},
|
|
225
|
-
DatetimeSecField: {"input": FieldType.input.name, "type": "datetime"},
|
|
226
|
-
DateField: {"input": FieldType.input.name, "type": "date"},
|
|
227
|
-
TimeField: {"input": FieldType.input.name, "type": "time"},
|
|
228
|
-
JSONField: {"input": FieldType.input.name},
|
|
229
|
-
IntEnumFieldInstance: {"input": FieldType.select.name},
|
|
230
|
-
CharEnumFieldInstance: {"input": FieldType.select.name},
|
|
231
|
-
ForeignKeyFieldInstance: {"input": FieldType.select.name},
|
|
232
|
-
OneToOneFieldInstance: {"input": FieldType.select.name},
|
|
233
|
-
ManyToManyFieldInstance: {"input": FieldType.select.name, "multiple": True},
|
|
234
|
-
ForeignKeyRelation: {"input": FieldType.select.name, "multiple": True},
|
|
235
|
-
OneToOneRelation: {"input": FieldType.select.name},
|
|
236
|
-
BackwardOneToOneRelation: {"input": FieldType.select.name},
|
|
237
|
-
ManyToManyRelation: {"input": FieldType.select.name, "multiple": True},
|
|
238
|
-
ForeignKeyNullableRelation: {"input": FieldType.select.name, "multiple": True},
|
|
239
|
-
BackwardFKRelation: {"input": FieldType.select.name, "multiple": True},
|
|
240
|
-
ArrayField: {"input": FieldType.select.name, "multiple": True},
|
|
241
|
-
SetField: {"input": FieldType.select.name, "multiple": True},
|
|
242
|
-
OneToOneNullableRelation: {"input": FieldType.select.name},
|
|
243
|
-
PointField: {"input": FieldType.collection.name, **dry},
|
|
244
|
-
PolygonField: {"input": FieldType.list.name, **dry},
|
|
245
|
-
RangeField: {"input": FieldType.collection.name, **dry},
|
|
246
|
-
}
|
|
247
|
-
return type2inputs[ft]
|
|
248
|
-
|
|
249
|
-
def field2input(_key: str, field: Field):
|
|
250
|
-
attrs: dict = {"required": not field.null}
|
|
251
|
-
if isinstance(field, CharEnumFieldInstance):
|
|
252
|
-
attrs.update({"options": {en.name: en.value for en in field.enum_type}})
|
|
253
|
-
elif isinstance(field, IntEnumFieldInstance) or isinstance(field, SetField):
|
|
254
|
-
attrs.update({"options": {en.value: en.name.replace("_", " ") for en in field.enum_type}})
|
|
255
|
-
elif isinstance(field, RelationalField):
|
|
256
|
-
attrs.update({"source_field": field.source_field}) # 'table': attrs[key]['multiple'],
|
|
257
|
-
elif field.generated or ("auto_now" in field.__dict__ and (field.auto_now or field.auto_now_add)): # noqa
|
|
258
|
-
attrs.update({"auto": True})
|
|
259
|
-
return {**type2input(type(field)), **attrs}
|
|
260
|
-
|
|
261
|
-
return {key: field2input(key, field) for key, field in cls._meta.fields_map.items() if not key.endswith("_id")}
|
|
262
|
-
|
|
263
78
|
class Meta:
|
|
264
79
|
abstract = True
|
|
265
80
|
|
|
81
|
+
|
|
82
|
+
class Model(BaseModel):
|
|
83
|
+
_pyd: type[PydanticModel] = None
|
|
84
|
+
_pydIn: type[PydanticModel] = None
|
|
85
|
+
_pydListItem: type[PydanticModel] = None
|
|
86
|
+
|
|
266
87
|
class PydanticMeta:
|
|
267
|
-
#: If not empty, only fields this property contains will be in the pydantic model
|
|
268
88
|
# include: tuple[str, ...] = ()
|
|
269
|
-
# #: Fields listed in this property will be excluded from pydantic model
|
|
270
89
|
# exclude: tuple[str, ...] = ()
|
|
271
|
-
# #: Computed fields can be listed here to use in pydantic model
|
|
272
90
|
# computed: tuple[str, ...] = ()
|
|
273
|
-
|
|
274
91
|
exclude_raw_fields = False # default: True
|
|
275
92
|
max_recursion: int = 1 # default: 3
|
|
276
93
|
|
|
@@ -285,46 +102,71 @@ class Model(BaseModel):
|
|
|
285
102
|
exclude_raw_fields = False # default: True
|
|
286
103
|
sort_alphabetically: bool = True # default: False
|
|
287
104
|
|
|
105
|
+
@classmethod
|
|
106
|
+
def pyd(cls) -> type[PydanticModel]:
|
|
107
|
+
cls._pyd = cls._pyd or pydantic_model_creator(cls)
|
|
108
|
+
return cls._pyd
|
|
288
109
|
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
_name = {"username"}
|
|
307
|
-
|
|
308
|
-
class Meta:
|
|
309
|
-
table_description = "Users"
|
|
310
|
-
|
|
110
|
+
@classmethod
|
|
111
|
+
def pyd_in(cls) -> type[PydanticModel]:
|
|
112
|
+
if not cls._pydIn:
|
|
113
|
+
opts = tuple(k for k, v in cls._meta.fields_map.items() if not v.required)
|
|
114
|
+
cls._pydIn = pydantic_model_creator(
|
|
115
|
+
cls,
|
|
116
|
+
name=cls.__name__ + "In",
|
|
117
|
+
meta_override=cls.PydanticMetaIn,
|
|
118
|
+
optional=opts,
|
|
119
|
+
exclude_readonly=True,
|
|
120
|
+
exclude=("created_at", "updated_at"),
|
|
121
|
+
)
|
|
122
|
+
if m2ms := cls._meta.m2m_fields: # hack for direct inserting m2m values
|
|
123
|
+
cls._pydIn = create_model(
|
|
124
|
+
cls._pydIn.__name__, __base__=cls._pydIn, **{m2m: (list[int] | None, None) for m2m in m2ms}
|
|
125
|
+
)
|
|
126
|
+
return cls._pydIn
|
|
311
127
|
|
|
312
|
-
|
|
313
|
-
|
|
128
|
+
@classmethod
|
|
129
|
+
def pyd_list_item(cls) -> type[PydanticModel]:
|
|
130
|
+
if not cls._pydListItem:
|
|
131
|
+
cls._pydListItem = pydantic_model_creator(
|
|
132
|
+
cls, name=cls.__name__ + "ListItem", meta_override=cls.PydanticMetaListItem
|
|
133
|
+
)
|
|
134
|
+
return cls._pydListItem
|
|
314
135
|
|
|
315
|
-
|
|
136
|
+
@classmethod
|
|
137
|
+
def pyds_list(cls) -> type[PydList]:
|
|
138
|
+
return create_model(
|
|
139
|
+
cls.__name__ + "List",
|
|
140
|
+
data=(list[cls.pyd_list_item()], []),
|
|
141
|
+
total=(int, 0),
|
|
142
|
+
filtered=(int | None, None),
|
|
143
|
+
__base__=PydList[cls.pyd_list_item()],
|
|
144
|
+
)
|
|
316
145
|
|
|
317
|
-
|
|
318
|
-
|
|
146
|
+
# # # CRUD Methods # # #
|
|
147
|
+
@classmethod
|
|
148
|
+
async def one_pyd(cls, uid: int, **filters) -> PydanticModel:
|
|
149
|
+
q = cls.get(id=uid, **filters)
|
|
150
|
+
return await cls.pyd().from_queryset_single(q)
|
|
319
151
|
|
|
320
152
|
@classmethod
|
|
321
|
-
async def
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
153
|
+
async def page_pyd(cls, sorts: tuple[str], limit: int = 1000, offset: int = 0, q: str = None, **filters) -> PydList:
|
|
154
|
+
filters = {k: v for k, v in filters.items() if v is not None}
|
|
155
|
+
pyd_item = cls.pyd_list_item()
|
|
156
|
+
query = cls._page_query(sorts, limit, offset, q, **filters)
|
|
157
|
+
data = await pyd_item.from_queryset(query)
|
|
158
|
+
if limit - (li := len(data)):
|
|
159
|
+
filtered = total = li + offset
|
|
160
|
+
else:
|
|
161
|
+
total = await cls.all().count()
|
|
162
|
+
filtered_query = cls.filter(**filters)
|
|
163
|
+
if q:
|
|
164
|
+
filtered_query = filtered_query.filter(**{f"{cls._name}__icontains": q})
|
|
165
|
+
filtered = await filtered_query.count()
|
|
166
|
+
pyds = cls.pyds_list()
|
|
167
|
+
return pyds(data=data, total=total, filtered=filtered)
|
|
168
|
+
|
|
327
169
|
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
170
|
+
class TsTrait:
|
|
171
|
+
created_at: datetime | None = DatetimeSecField(auto_now_add=True)
|
|
172
|
+
updated_at: datetime | None = DatetimeSecField(auto_now=True)
|
x_model/pydantic.py
CHANGED
|
@@ -1,8 +1,6 @@
|
|
|
1
1
|
from typing import TypeVar, Generic
|
|
2
2
|
from pydantic import BaseModel, ConfigDict
|
|
3
3
|
|
|
4
|
-
from x_model.enum import UserStatus, UserRole
|
|
5
|
-
|
|
6
4
|
|
|
7
5
|
RootModelType = TypeVar("RootModelType")
|
|
8
6
|
|
|
@@ -13,32 +11,6 @@ class PydList(BaseModel, Generic[RootModelType]):
|
|
|
13
11
|
total: int
|
|
14
12
|
|
|
15
13
|
|
|
16
|
-
class UserPwd(BaseModel):
|
|
17
|
-
password: str
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
class UserReg(UserPwd):
|
|
21
|
-
username: str
|
|
22
|
-
email: str | None = None
|
|
23
|
-
phone: int | None = None
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
class UserUpdate(BaseModel):
|
|
27
|
-
username: str
|
|
28
|
-
status: UserStatus
|
|
29
|
-
email: str | None
|
|
30
|
-
phone: int | None
|
|
31
|
-
role: UserRole
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
class UserAuth(UserUpdate):
|
|
35
|
-
id: int
|
|
36
|
-
username: str
|
|
37
|
-
status: UserStatus
|
|
38
|
-
role: UserRole
|
|
39
|
-
# ref_id: int | None
|
|
40
|
-
|
|
41
|
-
|
|
42
14
|
class Names(BaseModel):
|
|
43
15
|
# models for name endpoint for select2 inputs
|
|
44
16
|
class Name(BaseModel):
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: xn-model
|
|
3
|
-
Version: 0.10.
|
|
3
|
+
Version: 0.10.4
|
|
4
4
|
Summary: Base model for xn-api
|
|
5
5
|
Author-email: Mike Artemiev <mixartemev@gmail.com>
|
|
6
6
|
License: MIT
|
|
@@ -10,8 +10,6 @@ Keywords: tortoise,model,crud,generator,api,admin
|
|
|
10
10
|
Requires-Python: >=3.12
|
|
11
11
|
Description-Content-Type: text/markdown
|
|
12
12
|
Requires-Dist: tortoise-orm[accel,asyncpg]
|
|
13
|
-
Requires-Dist: passlib[bcrypt]
|
|
14
|
-
Requires-Dist: pydantic
|
|
15
13
|
Requires-Dist: python-dotenv
|
|
16
14
|
Provides-Extra: dev
|
|
17
15
|
Requires-Dist: pytest ; extra == 'dev'
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
x_model/__init__.py,sha256=HBOZMb1HheFkak6Ih7YkSGiNtGkQq7L_fiWgL_zpEC0,607
|
|
2
|
+
x_model/field.py,sha256=S461M94ryQG7yu8lreXtWnZo3YdCP97xhbcCJ3BzXsY,2751
|
|
3
|
+
x_model/func.py,sha256=E7jDoHJGaFpKvxbHnT_lyBxUZeMo-GRd5gv9dLw7B9s,289
|
|
4
|
+
x_model/model.py,sha256=0KICJmgVffe0pQfFNHYTADUtkwuT6Szs0Os_vNBagQg,6893
|
|
5
|
+
x_model/pydantic.py,sha256=OjNCp4ZFGvUIxZSbDCmXISl9mOjI_UnWi5JMVntSqjM,590
|
|
6
|
+
xn_model-0.10.4.dist-info/METADATA,sha256=yLU0mFuqDdBv3zQengXTfsRfFjcP54_7goExIT_qG3M,1002
|
|
7
|
+
xn_model-0.10.4.dist-info/WHEEL,sha256=GV9aMThwP_4oNCtvEC2ec3qUYutgWeAzklro_0m4WJQ,91
|
|
8
|
+
xn_model-0.10.4.dist-info/top_level.txt,sha256=QCYyfv5AA_8jPPtCpShkBXzQRUCGuuW7Ro0mqysDE8E,8
|
|
9
|
+
xn_model-0.10.4.dist-info/RECORD,,
|
x_model/enum.py
DELETED
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
from enum import IntEnum
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
class FieldType(IntEnum):
|
|
5
|
-
input = 1
|
|
6
|
-
checkbox = 2
|
|
7
|
-
select = 3
|
|
8
|
-
textarea = 4
|
|
9
|
-
collection = 5
|
|
10
|
-
list = 6
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
class UserStatus(IntEnum):
|
|
14
|
-
BANNED = 0
|
|
15
|
-
WAIT = 1 # waiting for approve
|
|
16
|
-
TEST = 2 # trial
|
|
17
|
-
ACTIVE = 3
|
|
18
|
-
PREMIUM = 4
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
class Scope(IntEnum):
|
|
22
|
-
READ = 4
|
|
23
|
-
WRITE = 2
|
|
24
|
-
ALL = 1 # not only my
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
class UserRole(IntEnum):
|
|
28
|
-
CLIENT = Scope.READ # 4
|
|
29
|
-
AUTHOR = Scope.WRITE # 2
|
|
30
|
-
MANAGER = Scope.READ + Scope.WRITE # 6
|
|
31
|
-
ADMIN = Scope.READ + Scope.WRITE + Scope.ALL # 7
|
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
x_model/__init__.py,sha256=LrDAUX7IsIS0HvdPAyefqzNknvnn3-3XVk-UDLBukwA,1007
|
|
2
|
-
x_model/enum.py,sha256=yrTIzMVnqG-kAD4ifhJhMSnYI-DIDLkB236w-Ol2I-M,543
|
|
3
|
-
x_model/field.py,sha256=S461M94ryQG7yu8lreXtWnZo3YdCP97xhbcCJ3BzXsY,2751
|
|
4
|
-
x_model/func.py,sha256=E7jDoHJGaFpKvxbHnT_lyBxUZeMo-GRd5gv9dLw7B9s,289
|
|
5
|
-
x_model/model.py,sha256=rzKwyk6Uu9c6hYCuVFbB4DHgYaMrGUkwIK1Zq0jCwwE,13856
|
|
6
|
-
x_model/pydantic.py,sha256=lTQ4eGNg_jsyGNLu8B1fTO-Ky8C3F057abhyAdhmVoQ,1047
|
|
7
|
-
xn_model-0.10.3.dev1.dist-info/METADATA,sha256=yQ4EovBcmvABOeff2zdqiwpxYxvSaIuMVEJKQaP7MQY,1062
|
|
8
|
-
xn_model-0.10.3.dev1.dist-info/WHEEL,sha256=GV9aMThwP_4oNCtvEC2ec3qUYutgWeAzklro_0m4WJQ,91
|
|
9
|
-
xn_model-0.10.3.dev1.dist-info/top_level.txt,sha256=QCYyfv5AA_8jPPtCpShkBXzQRUCGuuW7Ro0mqysDE8E,8
|
|
10
|
-
xn_model-0.10.3.dev1.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|