activemodel 0.5.0__py3-none-any.whl → 0.8.0__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.
@@ -0,0 +1,282 @@
1
+ Metadata-Version: 2.4
2
+ Name: activemodel
3
+ Version: 0.8.0
4
+ Summary: Make SQLModel more like an a real ORM
5
+ Project-URL: Repository, https://github.com/iloveitaly/activemodel
6
+ Author-email: Michael Bianco <iloveitaly@gmail.com>
7
+ License-File: LICENSE
8
+ Keywords: activemodel,activerecord,orm,sqlalchemy,sqlmodel
9
+ Requires-Python: >=3.10
10
+ Requires-Dist: pydash>=8.0.4
11
+ Requires-Dist: python-decouple-typed>=3.11.0
12
+ Requires-Dist: sqlmodel>=0.0.22
13
+ Requires-Dist: typeid-python>=0.3.1
14
+ Description-Content-Type: text/markdown
15
+
16
+ # ActiveModel: ORM Wrapper for SQLModel
17
+
18
+ No, this isn't *really* [ActiveModel](https://guides.rubyonrails.org/active_model_basics.html). It's just a wrapper around SQLModel that provides a more ActiveRecord-like interface.
19
+
20
+ SQLModel is *not* an ORM. It's a SQL query builder and a schema definition tool.
21
+
22
+ This package provides a thin wrapper around SQLModel that provides a more ActiveRecord-like interface with things like:
23
+
24
+ * Timestamp column mixins
25
+ * Lifecycle hooks
26
+
27
+ ## Getting Started
28
+
29
+ First, setup your DB:
30
+
31
+ ```python
32
+ import activemodel
33
+ activemodel.init("sqlite:///database.db")
34
+ ```
35
+
36
+ Create models:
37
+
38
+ ```python
39
+ from activemodel import BaseModel
40
+ from activemodel.mixins import TimestampsMixin, TypeIDMixin
41
+
42
+ class User(
43
+ BaseModel,
44
+ # optionally, obviously
45
+ TimestampsMixin,
46
+ # you can use a different pk type, but why would you?
47
+ # put this mixin last otherwise `id` will not be the first column in the DB
48
+ TypeIDMixin("user"),
49
+ # wire this model into the DB, without this alembic will not generate a migration
50
+ table=True
51
+ ):
52
+ a_field: str
53
+ ```
54
+
55
+ You'll need to create the models in the DB. Alembic is the best way to do it, but you can cheat as well:
56
+
57
+ ```python
58
+ from sqlmodel import SQLModel
59
+
60
+ SQLModel.metadata.create_all(get_engine())
61
+
62
+ # now you can create a user!
63
+ User(a_field="a").save()
64
+ ```
65
+
66
+ Maybe you like JSON:
67
+
68
+ ```python
69
+ from activemodel import BaseModel
70
+ from pydantic import BaseModel as PydanticBaseModel
71
+ from activemodel.mixins import PydanticJSONMixin, TypeIDMixin, TimestampsMixin
72
+
73
+ class SubObject(PydanticBaseModel):
74
+ name: str
75
+ value: int
76
+
77
+ class User(
78
+ BaseModel,
79
+ TimestampsMixin,
80
+ PydanticJSONMixin,
81
+ TypeIDMixin("user"),
82
+ table=True
83
+ ):
84
+ list_field: list[SubObject] = Field(sa_type=JSONB())
85
+ ```
86
+
87
+ ## Usage
88
+
89
+ ### Integrating Alembic
90
+
91
+ `alembic init` will not work out of the box. You need to mutate a handful of files:
92
+
93
+ * To import all of your models you want in your DB. [Here's my recommended way to do this.](https://github.com/iloveitaly/python-starter-template/blob/master/app/models/__init__.py)
94
+ * Use your DB URL from the ENV
95
+ * Target sqlalchemy metadata to the sqlmodel-generated metadata
96
+ * Most likely you'll want to add [alembic-postgresql-enum](https://pypi.org/project/alembic-postgresql-enum/) so migrations work properly
97
+
98
+ [Take a look at these scripts for an example of how to fully integrate Alembic into your development workflow.](https://github.com/iloveitaly/python-starter-template/blob/0af2c7e95217e34bde7357cc95be048900000e48/Justfile#L618-L712)
99
+
100
+ Here's a diff from the bare `alembic init` from version `1.14.1`.
101
+
102
+ ```diff
103
+ diff --git i/test/migrations/alembic.ini w/test/migrations/alembic.ini
104
+ index 0d07420..a63631c 100644
105
+ --- i/test/migrations/alembic.ini
106
+ +++ w/test/migrations/alembic.ini
107
+ @@ -3,13 +3,14 @@
108
+ [alembic]
109
+ # path to migration scripts
110
+ # Use forward slashes (/) also on windows to provide an os agnostic path
111
+ -script_location = .
112
+ +script_location = migrations
113
+
114
+ # template used to generate migration file names; The default value is %%(rev)s_%%(slug)s
115
+ # Uncomment the line below if you want the files to be prepended with date and time
116
+ # see https://alembic.sqlalchemy.org/en/latest/tutorial.html#editing-the-ini-file
117
+ # for all available tokens
118
+ # file_template = %%(year)d_%%(month).2d_%%(day).2d_%%(hour).2d%%(minute).2d-%%(rev)s_%%(slug)s
119
+ +file_template = %%(year)d_%%(month).2d_%%(day).2d_%%(rev)s_%%(slug)s
120
+
121
+ # sys.path path, will be prepended to sys.path if present.
122
+ # defaults to the current working directory.
123
+ diff --git i/test/migrations/env.py w/test/migrations/env.py
124
+ index 36112a3..a1e15c2 100644
125
+ --- i/test/migrations/env.py
126
+ +++ w/test/migrations/env.py
127
+ @@ -1,3 +1,6 @@
128
+ +# fmt: off
129
+ +# isort: off
130
+ +
131
+ from logging.config import fileConfig
132
+
133
+ from sqlalchemy import engine_from_config
134
+ @@ -14,11 +17,17 @@ config = context.config
135
+ if config.config_file_name is not None:
136
+ fileConfig(config.config_file_name)
137
+
138
+ +from sqlmodel import SQLModel
139
+ +from test.models import *
140
+ +from test.utils import database_url
141
+ +
142
+ +config.set_main_option("sqlalchemy.url", database_url())
143
+ +
144
+ # add your model's MetaData object here
145
+ # for 'autogenerate' support
146
+ # from myapp import mymodel
147
+ # target_metadata = mymodel.Base.metadata
148
+ -target_metadata = None
149
+ +target_metadata = SQLModel.metadata
150
+
151
+ # other values from the config, defined by the needs of env.py,
152
+ # can be acquired:
153
+ diff --git i/test/migrations/script.py.mako w/test/migrations/script.py.mako
154
+ index fbc4b07..9dc78bb 100644
155
+ --- i/test/migrations/script.py.mako
156
+ +++ w/test/migrations/script.py.mako
157
+ @@ -9,6 +9,8 @@ from typing import Sequence, Union
158
+
159
+ from alembic import op
160
+ import sqlalchemy as sa
161
+ +import sqlmodel
162
+ +import activemodel
163
+ ${imports if imports else ""}
164
+
165
+ # revision identifiers, used by Alembic.
166
+ ```
167
+
168
+ Here are some useful resources around Alembic + SQLModel:
169
+
170
+ * https://github.com/fastapi/sqlmodel/issues/85
171
+ * https://testdriven.io/blog/fastapi-sqlmodel/
172
+
173
+ ### Query Wrapper
174
+
175
+ This tool is added to all `BaseModel`s and makes it easy to write SQL queries. Some examples:
176
+
177
+
178
+
179
+ ### Easy Database Sessions
180
+
181
+ I hate the idea f
182
+
183
+ * Behavior should be intuitive and easy to understand. If you run `save()`, it should save, not stick the save in a transaction.
184
+ * Don't worry about dead sessions. This makes it easy to lazy-load computed properties and largely eliminates the need to think about database sessions.
185
+
186
+ There are a couple of thorny problems we need to solve for here:
187
+
188
+ * In-memory fastapi servers are not the same as a uvicorn server, which is threaded *and* uses some sort of threadpool model for handling async requests. I don't claim to understand the entire implementation. For global DB session state (a) we can't use global variables (b) we can't use thread-local variables.
189
+ *
190
+
191
+ https://github.com/tomwojcik/starlette-context
192
+
193
+ ### Example Queries
194
+
195
+ * Conditional: `Scrape.select().where(Scrape.id < last_scraped.id).all()`
196
+ * Equality: `MenuItem.select().where(MenuItem.menu_id == menu.id).all()`
197
+ * `IN` example: `CanonicalMenuItem.select().where(col(CanonicalMenuItem.id).in_(canonized_ids)).all()`
198
+ * Compound where query: `User.where((User.last_active_at != None) & (User.last_active_at > last_24_hours)).count()`
199
+
200
+ ### SQLModel Internals
201
+
202
+ SQLModel & SQLAlchemy are tricky. Here are some useful internal tricks:
203
+
204
+ * `__sqlmodel_relationships__` is where any `RelationshipInfo` objects are stored. This is used to generate relationship fields on the object.
205
+ * `ModelClass.relationship_name.property.local_columns`
206
+ * Get cached fields from a model `object_state(instance).dict.get(field_name)`
207
+
208
+ ### TypeID
209
+
210
+ I'm a massive fan of Stripe-style prefixed UUIDs. [There's an excellent project](https://github.com/jetify-com/typeid)
211
+ that defined a clear spec for these IDs. I've used the python implementation of this spec and developed a clean integration
212
+ with SQLModel that plays well with fastapi as well.
213
+
214
+ Here's an example of defining a relationship:
215
+
216
+ ```python
217
+ import uuid
218
+
219
+ from activemodel import BaseModel
220
+ from activemodel.mixins import TimestampsMixin, TypeIDMixin
221
+ from activemodel.types import TypeIDType
222
+ from sqlmodel import Field, Relationship
223
+
224
+ from .patient import Patient
225
+
226
+ class Appointment(
227
+ BaseModel,
228
+ # this adds an `id` field to the model with the correct type
229
+ TypeIDMixin("appointment"),
230
+ table=True
231
+ ):
232
+ # `foreign_key` is a activemodel method to generate the right `Field` for the relationship
233
+ # TypeIDType is really important here for fastapi serialization
234
+ doctor_id: TypeIDType = Doctor.foreign_key()
235
+ doctor: Doctor = Relationship()
236
+ ```
237
+
238
+ ## Limitations
239
+
240
+ ### Validation
241
+
242
+ SQLModel does not currently support pydantic validations (when `table=True`). This is very surprising, but is actually the intended functionality:
243
+
244
+ * https://github.com/fastapi/sqlmodel/discussions/897
245
+ * https://github.com/fastapi/sqlmodel/pull/1041
246
+ * https://github.com/fastapi/sqlmodel/issues/453
247
+ * https://github.com/fastapi/sqlmodel/issues/52#issuecomment-1311987732
248
+
249
+ For validation:
250
+
251
+ * When consuming API data, use a separate shadow model to validate the data with `table=False` and then inherit from that model in a model with `table=True`.
252
+ * When validating ORM data, use SQL Alchemy hooks.
253
+
254
+ <!--
255
+
256
+ This looks neat
257
+ https://github.com/DarylStark/my_data/blob/a17b8b3a8463b9953821b89fee895e272f94d2a4/src/my_model/model.py#L155
258
+ schema_extra={
259
+ 'pattern': r'^[a-z0-9_\-\.]+\@[a-z0-9_\-\.]+\.[a-z\.]+$'
260
+ },
261
+
262
+ extra constraints
263
+
264
+ https://github.com/DarylStark/my_data/blob/a17b8b3a8463b9953821b89fee895e272f94d2a4/src/my_model/model.py#L424C1-L426C6
265
+ -->
266
+ ## Related Projects
267
+
268
+ * https://github.com/woofz/sqlmodel-basecrud
269
+ * https://github.com/0xthiagomartins/sqlmodel-controller
270
+
271
+ ## Inspiration
272
+
273
+ * https://github.com/peterdresslar/fastapi-sqlmodel-alembic-pg
274
+ * [Albemic instructions](https://github.com/fastapi/sqlmodel/pull/899/files)
275
+ * https://github.com/fastapiutils/fastapi-utils/
276
+ * https://github.com/fastapi/full-stack-fastapi-template
277
+ * https://github.com/DarylStark/my_data/
278
+ * https://github.com/petrgazarov/FastAPI-app/tree/main/fastapi_app
279
+
280
+ ## Upstream Changes
281
+
282
+ - [ ] https://github.com/fastapi/sqlmodel/pull/1293
@@ -0,0 +1,24 @@
1
+ activemodel/__init__.py,sha256=q_lHQyIM70ApvjduTo9GtenQjJXsfYZsAAquD_51kF4,137
2
+ activemodel/base_model.py,sha256=MM-TRlf_0DnCZHeNWxQ1S-VMq8JSBYybPfhtLZHZeRE,12066
3
+ activemodel/celery.py,sha256=L1vKcO_HoPA5ZCfsXjxgPpDUMYDuoQMakGA9rppN7Lo,897
4
+ activemodel/errors.py,sha256=wycWYmk9ws4TZpxvTdtXVy2SFESb8NqKgzdivBoF0vw,115
5
+ activemodel/get_column_from_field_patch.py,sha256=wAEDm_ZvSqyJwfgkXVpxsevw11hd-7VLy7zuJG8Ak7Y,4986
6
+ activemodel/logger.py,sha256=vU7QiGSy_AJuJFmClUocqIJ-Ltku_8C24ZU8L6fLJR0,53
7
+ activemodel/query_wrapper.py,sha256=rNdvueppMse2MIi-RafTEC34GPGRal_wqH2CzhmlWS8,2520
8
+ activemodel/session_manager.py,sha256=Vtg8Lf8vUNPegdRW-fyE-Ng5wtN3hTMfUezdFUiJ1fs,4585
9
+ activemodel/utils.py,sha256=g17UqkphzTmb6YdpmYwT1TM00eDiXXuWn39-xNiu0AA,2112
10
+ activemodel/mixins/__init__.py,sha256=05EQl2u_Wgf_wkly-GTaTsR7zWpmpKcb96Js7r_rZTw,160
11
+ activemodel/mixins/pydantic_json.py,sha256=8A5X6QVzMSvDkBIb1impZ9PYskkUviG1UW7kkoxI8Wg,3057
12
+ activemodel/mixins/soft_delete.py,sha256=Ax4mGsQI7AVTE8c4GiWxpyB_W179-dDct79GtjP0owU,461
13
+ activemodel/mixins/timestamps.py,sha256=Q-IFljeVVJQqw3XHdOi7dkqzefiVg1zhJvq_bldpmjg,992
14
+ activemodel/mixins/typeid.py,sha256=DGjlIg8PRBYoaBbWkkxc6jkScyl-p53KuSR98lLgAvE,1284
15
+ activemodel/pytest/__init__.py,sha256=W9KKQHbPkyq0jrMXaiL8hG2Nsbjy_LN9HhvgGm8W_7g,98
16
+ activemodel/pytest/transaction.py,sha256=GfUpGUiTHATooVfxU3FMF28FHljBVdfVcb51g2KMzhY,2593
17
+ activemodel/pytest/truncate.py,sha256=IGiPLkUm2yyOKww6c6CKcVbwi2xAAFBopx9q2ABfu8w,1582
18
+ activemodel/types/__init__.py,sha256=y5fiGVtPJxGEhuf-TvyrkhM2yaKRcIWo6XAx-CFFjM8,31
19
+ activemodel/types/typeid.py,sha256=XrwCMvAkoZSeM5WhKH-aGJeiK0e9HoTXCheEDUgBBgQ,7292
20
+ activemodel-0.8.0.dist-info/METADATA,sha256=niH50sWYcT1c8eprDrEhetodN2bx_otnMsuzpKQZAAk,9651
21
+ activemodel-0.8.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
22
+ activemodel-0.8.0.dist-info/entry_points.txt,sha256=YLX62TP_hR-n3HMBkdBex4W7XRiyOtIPkwy22puIjjQ,61
23
+ activemodel-0.8.0.dist-info/licenses/LICENSE,sha256=L8mmpX47rB-xtJ_HsK0zpfO6viEjxbLYGn70BMp8os4,1071
24
+ activemodel-0.8.0.dist-info/RECORD,,
@@ -1,5 +1,4 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (75.6.0)
2
+ Generator: hatchling 1.27.0
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
-
@@ -1,153 +0,0 @@
1
- """
2
- Adapted from: https://github.com/fastapiutils/fastapi-utils/blob/master/fastapi_utils/session.py
3
- """
4
-
5
- from contextlib import contextmanager
6
-
7
- import sqlalchemy as sa
8
- from sqlalchemy.orm import Session
9
-
10
-
11
- class FastSessionMaker:
12
- """
13
- A convenience class for managing a (cached) sqlalchemy ORM engine and sessionmaker.
14
-
15
- Intended for use creating ORM sessions injected into endpoint functions by FastAPI.
16
- """
17
-
18
- def __init__(self, database_uri: str):
19
- """
20
- `database_uri` should be any sqlalchemy-compatible database URI.
21
-
22
- In particular, `sqlalchemy.create_engine(database_uri)` should work to create an engine.
23
-
24
- Typically, this would look like:
25
-
26
- "<scheme>://<user>:<password>@<host>:<port>/<database>"
27
-
28
- A concrete example looks like "postgresql://db_user:password@db:5432/app"
29
- """
30
- self.database_uri = database_uri
31
-
32
- self._cached_engine: sa.engine.Engine | None = None
33
- self._cached_sessionmaker: sa.orm.sessionmaker | None = None
34
-
35
- @property
36
- def cached_engine(self) -> sa.engine.Engine:
37
- """
38
- Returns a lazily-cached sqlalchemy engine for the instance's database_uri.
39
- """
40
- engine = self._cached_engine
41
- if engine is None:
42
- engine = self.get_new_engine()
43
- self._cached_engine = engine
44
- return engine
45
-
46
- @property
47
- def cached_sessionmaker(self) -> sa.orm.sessionmaker:
48
- """
49
- Returns a lazily-cached sqlalchemy sessionmaker using the instance's (lazily-cached) engine.
50
- """
51
- sessionmaker = self._cached_sessionmaker
52
- if sessionmaker is None:
53
- sessionmaker = self.get_new_sessionmaker(self.cached_engine)
54
- self._cached_sessionmaker = sessionmaker
55
- return sessionmaker
56
-
57
- def get_new_engine(self) -> sa.engine.Engine:
58
- """
59
- Returns a new sqlalchemy engine using the instance's database_uri.
60
- """
61
- return get_engine(self.database_uri)
62
-
63
- def get_new_sessionmaker(
64
- self, engine: sa.engine.Engine | None
65
- ) -> sa.orm.sessionmaker:
66
- """
67
- Returns a new sessionmaker for the provided sqlalchemy engine. If no engine is provided, the
68
- instance's (lazily-cached) engine is used.
69
- """
70
- engine = engine or self.cached_engine
71
- return get_sessionmaker_for_engine(engine)
72
-
73
- def get_db(self) -> Iterator[Session]:
74
- """
75
- A generator function that yields a sqlalchemy orm session and cleans up the session once resumed after yielding.
76
-
77
- Can be used directly as a context-manager FastAPI dependency, or yielded from inside a separate dependency.
78
- """
79
- yield from _get_db(self.cached_sessionmaker)
80
-
81
- @contextmanager
82
- def context_session(self) -> Iterator[Session]:
83
- """
84
- A context-manager wrapped version of the `get_db` method.
85
-
86
- This makes it possible to get a context-managed orm session for the relevant database_uri without
87
- needing to rely on FastAPI's dependency injection.
88
-
89
- Usage looks like:
90
-
91
- session_maker = FastAPISessionMaker(database_uri)
92
- with session_maker.context_session() as session:
93
- session.query(...)
94
- ...
95
- """
96
- yield from self.get_db()
97
-
98
- def reset_cache(self) -> None:
99
- """
100
- Resets the engine and sessionmaker caches.
101
-
102
- After calling this method, the next time you try to use the cached engine or sessionmaker,
103
- new ones will be created.
104
- """
105
- self._cached_engine = None
106
- self._cached_sessionmaker = None
107
-
108
-
109
- def get_engine(uri: str) -> sa.engine.Engine:
110
- """
111
- Returns a sqlalchemy engine with pool_pre_ping enabled.
112
-
113
- This function may be updated over time to reflect recommended engine configuration for use with FastAPI.
114
- """
115
- return sa.create_engine(uri, pool_pre_ping=True)
116
-
117
-
118
- def get_sessionmaker_for_engine(engine: sa.engine.Engine) -> sa.orm.sessionmaker:
119
- """
120
- Returns a sqlalchemy sessionmaker for the provided engine with recommended configuration settings.
121
-
122
- This function may be updated over time to reflect recommended sessionmaker configuration for use with FastAPI.
123
- """
124
- return sa.orm.sessionmaker(autocommit=False, autoflush=False, bind=engine)
125
-
126
-
127
- @contextmanager
128
- def context_session(engine: sa.engine.Engine) -> Iterator[Session]:
129
- """
130
- This contextmanager yields a managed session for the provided engine.
131
-
132
- Usage is similar to `FastAPISessionMaker.context_session`, except that you have to provide the engine to use.
133
-
134
- A new sessionmaker is created for each call, so the FastAPISessionMaker.context_session
135
- method may be preferable in performance-sensitive contexts.
136
- """
137
- sessionmaker = get_sessionmaker_for_engine(engine)
138
- yield from _get_db(sessionmaker)
139
-
140
-
141
- def _get_db(sessionmaker: sa.orm.sessionmaker) -> Iterator[Session]:
142
- """
143
- A generator function that yields an ORM session using the provided sessionmaker, and cleans it up when resumed.
144
- """
145
- session = sessionmaker()
146
- try:
147
- yield session
148
- session.commit()
149
- except Exception as exc:
150
- session.rollback()
151
- raise exc
152
- finally:
153
- session.close()
@@ -1,66 +0,0 @@
1
- Metadata-Version: 2.1
2
- Name: activemodel
3
- Version: 0.5.0
4
- Summary: Make SQLModel more like an a real ORM
5
- Author-email: Michael Bianco <iloveitaly@gmail.com>
6
- Project-URL: Repository, https://github.com/iloveitaly/activemodel
7
- Keywords: sqlmodel,orm,activerecord,activemodel,sqlalchemy
8
- Requires-Python: >=3.10
9
- Description-Content-Type: text/markdown
10
- License-File: LICENSE
11
- Requires-Dist: pydash>=8.0.4
12
- Requires-Dist: python-decouple-typed>=3.11.0
13
- Requires-Dist: sqlmodel>=0.0.22
14
- Requires-Dist: typeid-python>=0.3.1
15
-
16
- # ActiveModel: ORM Wrapper for SQLModel
17
-
18
- No, this isn't *really* [ActiveModel](https://guides.rubyonrails.org/active_model_basics.html). It's just a wrapper around SQLModel that provides a more ActiveRecord-like interface.
19
-
20
- SQLModel is *not* an ORM. It's a SQL query builder and a schema definition tool.
21
-
22
- This package provides a thin wrapper around SQLModel that provides a more ActiveRecord-like interface with things like:
23
-
24
- * Timestamp column mixins
25
- * Lifecycle hooks
26
-
27
- ## Limitations
28
-
29
- ### Validation
30
-
31
- SQLModel does not currently support pydantic validations (when `table=True`). This is very surprising, but is actually the intended functionality:
32
-
33
- * https://github.com/fastapi/sqlmodel/discussions/897
34
- * https://github.com/fastapi/sqlmodel/pull/1041
35
- * https://github.com/fastapi/sqlmodel/issues/453
36
- * https://github.com/fastapi/sqlmodel/issues/52#issuecomment-1311987732
37
-
38
- For validation:
39
-
40
- * When consuming API data, use a separate shadow model to validate the data with `table=False` and then inherit from that model in a model with `table=True`.
41
- * When validating ORM data, use SQL Alchemy hooks.
42
-
43
- <!--
44
-
45
- This looks neat
46
- https://github.com/DarylStark/my_data/blob/a17b8b3a8463b9953821b89fee895e272f94d2a4/src/my_model/model.py#L155
47
- schema_extra={
48
- 'pattern': r'^[a-z0-9_\-\.]+\@[a-z0-9_\-\.]+\.[a-z\.]+$'
49
- },
50
-
51
- extra constraints
52
-
53
- https://github.com/DarylStark/my_data/blob/a17b8b3a8463b9953821b89fee895e272f94d2a4/src/my_model/model.py#L424C1-L426C6
54
- -->
55
- ## Related Projects
56
-
57
- * https://github.com/woofz/sqlmodel-basecrud
58
-
59
- ## Inspiration
60
-
61
- * https://github.com/peterdresslar/fastapi-sqlmodel-alembic-pg
62
- * [Albemic instructions](https://github.com/fastapi/sqlmodel/pull/899/files)
63
- * https://github.com/fastapiutils/fastapi-utils/
64
- * https://github.com/fastapi/full-stack-fastapi-template
65
- * https://github.com/DarylStark/my_data/
66
- * https://github.com/petrgazarov/FastAPI-app/tree/main/fastapi_app
@@ -1,20 +0,0 @@
1
- activemodel/__init__.py,sha256=lO75TeJeSm7spmP4P1_Z5oIXBHlL7kKjr1LS2Z4dNUA,109
2
- activemodel/_session_manager.py,sha256=ojFIpK_fl1-JZsj98zn-zp4RIK1_eyDl-Ga4F1XXbVw,5249
3
- activemodel/base_model.py,sha256=y8gLmowqk950AELE67u69YJAT9pJSmm67apjOd1g2yo,8081
4
- activemodel/logger.py,sha256=vU7QiGSy_AJuJFmClUocqIJ-Ltku_8C24ZU8L6fLJR0,53
5
- activemodel/query_wrapper.py,sha256=zqaA3yAHPTfGLrkzZ6ge6byedV497C7YG1QJe_4ah7Q,2100
6
- activemodel/session_manager.py,sha256=zU4Eu3YeKSlZrYEBkN70XAHJOHka40Rl4qMBZvEgNwA,1822
7
- activemodel/utils.py,sha256=dY6wvAS2RCqMVMQfnpXGJxgWRBet0jV5ZXxGIRX1iRw,476
8
- activemodel/mixins/__init__.py,sha256=VAVLc96oSSultP0BNAlaE3ZBNGlcuVD0JjS1FMCno7k,72
9
- activemodel/mixins/timestamps.py,sha256=Q-IFljeVVJQqw3XHdOi7dkqzefiVg1zhJvq_bldpmjg,992
10
- activemodel/mixins/typeid.py,sha256=0TOJ74As9JL4WVvlRm0yuZB49xHAcX0n1fzwKpgdpys,894
11
- activemodel/pytest/__init__.py,sha256=W9KKQHbPkyq0jrMXaiL8hG2Nsbjy_LN9HhvgGm8W_7g,98
12
- activemodel/pytest/transaction.py,sha256=rrsoHnbu79kNdnI5fZeOZr5hzrLB-cQH10MueQp5jV4,1670
13
- activemodel/pytest/truncate.py,sha256=BdltCtLQNPDgRSxpBnGYGSjB_7DAceV5kHdQ_vLrw74,1583
14
- activemodel/types/typeid.py,sha256=rcr9tSiu5rowD_WOcF4zzBpEUy2izmYEPteDQgCIbhs,1799
15
- activemodel-0.5.0.dist-info/LICENSE,sha256=L8mmpX47rB-xtJ_HsK0zpfO6viEjxbLYGn70BMp8os4,1071
16
- activemodel-0.5.0.dist-info/METADATA,sha256=4nieriFioXBxTPOIuxul3RXzNMwKPiDgSYX4KMkwSbQ,2429
17
- activemodel-0.5.0.dist-info/WHEEL,sha256=PZUExdf71Ui_so67QXpySuHtCi3-J3wvF4ORK6k_S8U,91
18
- activemodel-0.5.0.dist-info/entry_points.txt,sha256=YLX62TP_hR-n3HMBkdBex4W7XRiyOtIPkwy22puIjjQ,61
19
- activemodel-0.5.0.dist-info/top_level.txt,sha256=JCMUN_seFIi6GXtnTQRWfxXDx6Oj1uok8qapQWbWKDM,12
20
- activemodel-0.5.0.dist-info/RECORD,,
@@ -1 +0,0 @@
1
- activemodel