async-easy-model 0.1.12__tar.gz → 0.2.1__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 (20) hide show
  1. async_easy_model-0.2.1/PKG-INFO +343 -0
  2. async_easy_model-0.2.1/README.md +305 -0
  3. {async_easy_model-0.1.12 → async_easy_model-0.2.1}/async_easy_model/auto_relationships.py +12 -0
  4. async_easy_model-0.2.1/async_easy_model/model.py +1197 -0
  5. async_easy_model-0.2.1/async_easy_model.egg-info/PKG-INFO +343 -0
  6. {async_easy_model-0.1.12 → async_easy_model-0.2.1}/setup.py +1 -1
  7. async_easy_model-0.1.12/PKG-INFO +0 -533
  8. async_easy_model-0.1.12/README.md +0 -495
  9. async_easy_model-0.1.12/async_easy_model/model.py +0 -646
  10. async_easy_model-0.1.12/async_easy_model.egg-info/PKG-INFO +0 -533
  11. {async_easy_model-0.1.12 → async_easy_model-0.2.1}/LICENSE +0 -0
  12. {async_easy_model-0.1.12 → async_easy_model-0.2.1}/async_easy_model/__init__.py +0 -0
  13. {async_easy_model-0.1.12 → async_easy_model-0.2.1}/async_easy_model/migrations.py +0 -0
  14. {async_easy_model-0.1.12 → async_easy_model-0.2.1}/async_easy_model/relationships.py +0 -0
  15. {async_easy_model-0.1.12 → async_easy_model-0.2.1}/async_easy_model.egg-info/SOURCES.txt +0 -0
  16. {async_easy_model-0.1.12 → async_easy_model-0.2.1}/async_easy_model.egg-info/dependency_links.txt +0 -0
  17. {async_easy_model-0.1.12 → async_easy_model-0.2.1}/async_easy_model.egg-info/requires.txt +0 -0
  18. {async_easy_model-0.1.12 → async_easy_model-0.2.1}/async_easy_model.egg-info/top_level.txt +0 -0
  19. {async_easy_model-0.1.12 → async_easy_model-0.2.1}/setup.cfg +0 -0
  20. {async_easy_model-0.1.12 → async_easy_model-0.2.1}/tests/test_easy_model.py +0 -0
@@ -0,0 +1,343 @@
1
+ Metadata-Version: 2.2
2
+ Name: async-easy-model
3
+ Version: 0.2.1
4
+ Summary: A simplified SQLModel-based ORM for async database operations
5
+ Home-page: https://github.com/puntorigen/easy-model
6
+ Author: Pablo Schaffner
7
+ Author-email: pablo@puntorigen.com
8
+ Keywords: orm,sqlmodel,database,async,postgresql,sqlite
9
+ Classifier: Development Status :: 3 - Alpha
10
+ Classifier: Intended Audience :: Developers
11
+ Classifier: License :: OSI Approved :: MIT License
12
+ Classifier: Operating System :: OS Independent
13
+ Classifier: Programming Language :: Python :: 3
14
+ Classifier: Programming Language :: Python :: 3.7
15
+ Classifier: Programming Language :: Python :: 3.8
16
+ Classifier: Programming Language :: Python :: 3.9
17
+ Classifier: Programming Language :: Python :: 3.10
18
+ Classifier: Programming Language :: Python :: 3.11
19
+ Requires-Python: >=3.7
20
+ Description-Content-Type: text/markdown
21
+ License-File: LICENSE
22
+ Requires-Dist: sqlmodel>=0.0.8
23
+ Requires-Dist: sqlalchemy>=2.0.0
24
+ Requires-Dist: asyncpg>=0.25.0
25
+ Requires-Dist: aiosqlite>=0.19.0
26
+ Requires-Dist: greenlet>=3.1.1
27
+ Requires-Dist: inflection>=0.5.1
28
+ Dynamic: author
29
+ Dynamic: author-email
30
+ Dynamic: classifier
31
+ Dynamic: description
32
+ Dynamic: description-content-type
33
+ Dynamic: home-page
34
+ Dynamic: keywords
35
+ Dynamic: requires-dist
36
+ Dynamic: requires-python
37
+ Dynamic: summary
38
+
39
+ # EasyModel
40
+
41
+ A simplified SQLModel-based ORM for async database operations in Python. EasyModel provides a clean and intuitive interface for common database operations while leveraging the power of SQLModel and SQLAlchemy.
42
+
43
+ ## Features
44
+
45
+ - Easy-to-use async database operations with standardized methods
46
+ - Intuitive APIs with sensible defaults (relationships loaded by default)
47
+ - Dictionary-based CRUD operations (select, insert, update, delete)
48
+ - Built on top of SQLModel and SQLAlchemy
49
+ - Support for both PostgreSQL and SQLite databases
50
+ - Type hints for better IDE support
51
+ - Automatic `id`, `created_at` and `updated_at` fields provided by default
52
+ - Enhanced relationship handling with eager loading and nested operations
53
+ - Flexible ordering of query results with support for relationship fields
54
+ - Automatic relationship detection
55
+ - Automatic schema migrations for evolving database models
56
+
57
+ ## Installation
58
+
59
+ ```bash
60
+ pip install async-easy-model
61
+ ```
62
+
63
+ ## Quick Start with Standardized API
64
+
65
+ This section demonstrates the preferred usage of EasyModel with its standardized API methods.
66
+
67
+ ```python
68
+ from async_easy_model import EasyModel, init_db, db_config, Field
69
+ from typing import Optional
70
+ from datetime import datetime
71
+
72
+ # Configure your database
73
+ db_config.configure_sqlite("database.db")
74
+
75
+ # Define your model
76
+ class User(EasyModel, table=True):
77
+ # id field is automatically created (primary key)
78
+ username: str = Field(unique=True)
79
+ email: str
80
+ is_active: bool = Field(default=True)
81
+ # created_at and updated_at fields are automatically included
82
+
83
+ class Post(EasyModel, table=True):
84
+ # id field is automatically created (primary key)
85
+ title: str
86
+ content: str
87
+ user_id: Optional[int] = Field(default=None, foreign_key="user.id")
88
+ # created_at and updated_at fields are automatically included
89
+
90
+ # Initialize your database
91
+ async def setup():
92
+ await init_db()
93
+
94
+ # Use the standardized methods in your code
95
+ async def main():
96
+ # Insert a new user
97
+ user = await User.insert({
98
+ "username": "john_doe",
99
+ "email": "john@example.com"
100
+ })
101
+
102
+ # Insert with relationships
103
+ post = await Post.insert({
104
+ "title": "My First Post",
105
+ "content": "Hello world!",
106
+ "user": {"username": "john_doe"} # Will find the user by username
107
+ })
108
+
109
+ # Select with criteria
110
+ active_users = await User.select({"is_active": True}, all=True)
111
+
112
+ # Select with wildcard search
113
+ gmail_users = await User.select({"email": "*@gmail.com"}, all=True)
114
+
115
+ # Select with ordering and limit
116
+ recent_posts = await Post.select({}, order_by="-id", limit=5)
117
+ # Note: limit > 1 automatically sets all=True
118
+
119
+ # Update by criteria
120
+ await User.update(
121
+ {"is_active": False},
122
+ {"last_login": None} # Update users with no login
123
+ )
124
+
125
+ # Delete with criteria
126
+ await Post.delete({"user": {"username": "john_doe"}})
127
+ ```
128
+
129
+ ## Standardized API Methods
130
+
131
+ EasyModel provides a set of standardized methods that make it easy and intuitive to perform common database operations.
132
+
133
+ ### Select Method
134
+
135
+ The `select()` method is a powerful and flexible way to query data:
136
+
137
+ ```python
138
+ # Get active users
139
+ active_users = await User.select({"is_active": True}, all=True)
140
+
141
+ # Get single user by username (returns first match)
142
+ user = await User.select({"username": "john_doe"})
143
+
144
+ # Explicitly get first result
145
+ first_admin = await User.select({"role": "admin"}, first=True)
146
+
147
+ # With wildcard pattern matching
148
+ gmail_users = await User.select({"email": "*@gmail.com"}, all=True)
149
+
150
+ # With ordering and limit (automatically sets all=True)
151
+ newest_users = await User.select({}, order_by="-created_at", limit=5)
152
+
153
+ # With ordering by multiple fields
154
+ sorted_users = await User.select({}, order_by=["last_name", "first_name"], all=True)
155
+
156
+ # With ordering by nested relationship fields using dot notation
157
+ books_by_author = await Book.select({}, order_by="author.name", all=True)
158
+ posts_by_popularity = await Post.select({}, order_by=["-comments.count", "title"], all=True)
159
+ ```
160
+
161
+ ### Insert Method
162
+
163
+ The `insert()` method supports both single and multiple records with relationship handling and returns the newly created records with assigned IDs and auto-generated fields (`created_at`, `updated_at`):
164
+
165
+ ```python
166
+ # Insert single record
167
+ user = await User.insert({
168
+ "username": "john_doe",
169
+ "email": "john@example.com"
170
+ })
171
+ print(user.id) # Newly assigned ID is available
172
+ print(user.created_at) # Auto-generated timestamp is available
173
+
174
+ # Insert with relationship
175
+ comment = await Comment.insert({
176
+ "text": "Great post!",
177
+ "post": {"id": 1}, # Link by ID
178
+ "author": {"username": "jane_doe"} # Link by attribute lookup
179
+ })
180
+
181
+ # Insert multiple records
182
+ products = await Product.insert([
183
+ {"name": "Product 1", "price": 10.99},
184
+ {"name": "Product 2", "price": 24.99}
185
+ ])
186
+ ```
187
+
188
+ ### Update Method
189
+
190
+ The `update()` method allows updates based on ID or criteria:
191
+
192
+ ```python
193
+ # Update by ID
194
+ user = await User.update({"email": "new@example.com"}, 1)
195
+
196
+ # Update by criteria
197
+ count = await User.update(
198
+ {"is_active": False},
199
+ {"last_login": None} # Set all users without login to inactive
200
+ )
201
+
202
+ # Update with relationships
203
+ await User.update(
204
+ {"department": {"name": "Sales"}}, # Update department relationship
205
+ {"username": "john_doe"}
206
+ )
207
+ ```
208
+
209
+ ### Delete Method
210
+
211
+ The `delete()` method provides a consistent way to delete records:
212
+
213
+ ```python
214
+ # Delete by ID
215
+ success = await User.delete(1)
216
+
217
+ # Delete by criteria
218
+ deleted_count = await User.delete({"is_active": False})
219
+
220
+ # Delete with compound criteria
221
+ await Post.delete({"author": {"username": "john_doe"}, "is_published": False})
222
+ ```
223
+
224
+ ## Convenience Query Methods
225
+
226
+ EasyModel also provides convenient shorthand methods for common queries:
227
+
228
+ ```python
229
+ # Get all records with relationships loaded (default)
230
+ users = await User.all()
231
+
232
+ # Get all records ordered by a field
233
+ users = await User.all(order_by="username")
234
+
235
+ # Get the first record
236
+ user = await User.first()
237
+
238
+ # Get the most recently created user
239
+ newest_user = await User.first(order_by="-created_at")
240
+
241
+ # Get limited records
242
+ recent_users = await User.limit(10, order_by="-created_at")
243
+ ```
244
+
245
+ ## Automatic Relationship Detection
246
+
247
+ EasyModel supports automatic relationship detection based on foreign key fields:
248
+
249
+ ```python
250
+ from async_easy_model import enable_auto_relationships, EasyModel, init_db, Field
251
+ from typing import Optional
252
+
253
+ # Enable automatic relationship detection
254
+ enable_auto_relationships()
255
+
256
+ # Define models with foreign keys but without explicit relationships
257
+ class Author(EasyModel, table=True):
258
+ # id field is automatically created (primary key)
259
+ name: str
260
+
261
+ class Book(EasyModel, table=True):
262
+ title: str
263
+ author_id: Optional[int] = Field(default=None, foreign_key="author.id")
264
+ # No need to define Relationship attributes - they're detected automatically!
265
+
266
+ # Use the automatically detected relationships
267
+ async def main():
268
+ await init_db()
269
+ author = await Author.insert({"name": "Jane Author"})
270
+
271
+ book = await Book.insert({
272
+ "title": "Auto-detected Relationships",
273
+ "author_id": author.id
274
+ })
275
+
276
+ # Show the book with its author
277
+ print(f"Book: {book.title}, Author: {book.author.name}")
278
+ ```
279
+
280
+ ### Another Example
281
+ ```python
282
+ # Using the standard insert with nested dictionaries (recommended)
283
+ new_book = await Book.insert({
284
+ "title": "New Book",
285
+ "author": {"name": "Jane Author"} # Will create or find the author
286
+ })
287
+ ```
288
+
289
+ ## Automatic Schema Migrations
290
+
291
+ EasyModel includes automatic database migration capabilities, similar to alembic:
292
+
293
+ ```python
294
+ from async_easy_model import MigrationManager
295
+
296
+ async def apply_migrations():
297
+ migration_manager = MigrationManager()
298
+ results = await migration_manager.migrate_models([User, Post])
299
+
300
+ if results:
301
+ print("Migrations applied:")
302
+ for model_name, changes in results.items():
303
+ print(f" {model_name}:")
304
+ for change in changes:
305
+ print(f" - {change}")
306
+ ```
307
+
308
+ ## Legacy API Methods
309
+
310
+ The following methods are still supported but the standardized methods above are recommended for new code:
311
+
312
+ ### Traditional CRUD Operations
313
+
314
+ ```python
315
+ # Create a record (consider using insert() instead)
316
+ user = User(username="john_doe", email="john@example.com")
317
+ await user.save()
318
+
319
+ # Get by ID (consider using select() instead)
320
+ user = await User.get_by_id(1)
321
+
322
+ # Get by attribute (consider using select() instead)
323
+ users = await User.get_by_attribute(is_active=True, all=True)
324
+
325
+ # Update by ID (consider using update() instead)
326
+ updated_user = await User.update_by_id(1, {"email": "new_email@example.com"})
327
+
328
+ # Update by attribute (consider using update() instead)
329
+ await User.update_by_attribute(
330
+ {"is_active": False}, # Update data
331
+ is_active=True, role="guest" # Filter criteria
332
+ )
333
+
334
+ # Delete by ID (consider using delete() instead)
335
+ success = await User.delete_by_id(1)
336
+
337
+ # Delete by attribute (consider using delete() instead)
338
+ deleted_count = await User.delete_by_attribute(is_active=False)
339
+ ```
340
+
341
+ ## Complete Documentation
342
+
343
+ For complete documentation, including advanced features, please see the [full documentation](DOCS.md).
@@ -0,0 +1,305 @@
1
+ # EasyModel
2
+
3
+ A simplified SQLModel-based ORM for async database operations in Python. EasyModel provides a clean and intuitive interface for common database operations while leveraging the power of SQLModel and SQLAlchemy.
4
+
5
+ ## Features
6
+
7
+ - Easy-to-use async database operations with standardized methods
8
+ - Intuitive APIs with sensible defaults (relationships loaded by default)
9
+ - Dictionary-based CRUD operations (select, insert, update, delete)
10
+ - Built on top of SQLModel and SQLAlchemy
11
+ - Support for both PostgreSQL and SQLite databases
12
+ - Type hints for better IDE support
13
+ - Automatic `id`, `created_at` and `updated_at` fields provided by default
14
+ - Enhanced relationship handling with eager loading and nested operations
15
+ - Flexible ordering of query results with support for relationship fields
16
+ - Automatic relationship detection
17
+ - Automatic schema migrations for evolving database models
18
+
19
+ ## Installation
20
+
21
+ ```bash
22
+ pip install async-easy-model
23
+ ```
24
+
25
+ ## Quick Start with Standardized API
26
+
27
+ This section demonstrates the preferred usage of EasyModel with its standardized API methods.
28
+
29
+ ```python
30
+ from async_easy_model import EasyModel, init_db, db_config, Field
31
+ from typing import Optional
32
+ from datetime import datetime
33
+
34
+ # Configure your database
35
+ db_config.configure_sqlite("database.db")
36
+
37
+ # Define your model
38
+ class User(EasyModel, table=True):
39
+ # id field is automatically created (primary key)
40
+ username: str = Field(unique=True)
41
+ email: str
42
+ is_active: bool = Field(default=True)
43
+ # created_at and updated_at fields are automatically included
44
+
45
+ class Post(EasyModel, table=True):
46
+ # id field is automatically created (primary key)
47
+ title: str
48
+ content: str
49
+ user_id: Optional[int] = Field(default=None, foreign_key="user.id")
50
+ # created_at and updated_at fields are automatically included
51
+
52
+ # Initialize your database
53
+ async def setup():
54
+ await init_db()
55
+
56
+ # Use the standardized methods in your code
57
+ async def main():
58
+ # Insert a new user
59
+ user = await User.insert({
60
+ "username": "john_doe",
61
+ "email": "john@example.com"
62
+ })
63
+
64
+ # Insert with relationships
65
+ post = await Post.insert({
66
+ "title": "My First Post",
67
+ "content": "Hello world!",
68
+ "user": {"username": "john_doe"} # Will find the user by username
69
+ })
70
+
71
+ # Select with criteria
72
+ active_users = await User.select({"is_active": True}, all=True)
73
+
74
+ # Select with wildcard search
75
+ gmail_users = await User.select({"email": "*@gmail.com"}, all=True)
76
+
77
+ # Select with ordering and limit
78
+ recent_posts = await Post.select({}, order_by="-id", limit=5)
79
+ # Note: limit > 1 automatically sets all=True
80
+
81
+ # Update by criteria
82
+ await User.update(
83
+ {"is_active": False},
84
+ {"last_login": None} # Update users with no login
85
+ )
86
+
87
+ # Delete with criteria
88
+ await Post.delete({"user": {"username": "john_doe"}})
89
+ ```
90
+
91
+ ## Standardized API Methods
92
+
93
+ EasyModel provides a set of standardized methods that make it easy and intuitive to perform common database operations.
94
+
95
+ ### Select Method
96
+
97
+ The `select()` method is a powerful and flexible way to query data:
98
+
99
+ ```python
100
+ # Get active users
101
+ active_users = await User.select({"is_active": True}, all=True)
102
+
103
+ # Get single user by username (returns first match)
104
+ user = await User.select({"username": "john_doe"})
105
+
106
+ # Explicitly get first result
107
+ first_admin = await User.select({"role": "admin"}, first=True)
108
+
109
+ # With wildcard pattern matching
110
+ gmail_users = await User.select({"email": "*@gmail.com"}, all=True)
111
+
112
+ # With ordering and limit (automatically sets all=True)
113
+ newest_users = await User.select({}, order_by="-created_at", limit=5)
114
+
115
+ # With ordering by multiple fields
116
+ sorted_users = await User.select({}, order_by=["last_name", "first_name"], all=True)
117
+
118
+ # With ordering by nested relationship fields using dot notation
119
+ books_by_author = await Book.select({}, order_by="author.name", all=True)
120
+ posts_by_popularity = await Post.select({}, order_by=["-comments.count", "title"], all=True)
121
+ ```
122
+
123
+ ### Insert Method
124
+
125
+ The `insert()` method supports both single and multiple records with relationship handling and returns the newly created records with assigned IDs and auto-generated fields (`created_at`, `updated_at`):
126
+
127
+ ```python
128
+ # Insert single record
129
+ user = await User.insert({
130
+ "username": "john_doe",
131
+ "email": "john@example.com"
132
+ })
133
+ print(user.id) # Newly assigned ID is available
134
+ print(user.created_at) # Auto-generated timestamp is available
135
+
136
+ # Insert with relationship
137
+ comment = await Comment.insert({
138
+ "text": "Great post!",
139
+ "post": {"id": 1}, # Link by ID
140
+ "author": {"username": "jane_doe"} # Link by attribute lookup
141
+ })
142
+
143
+ # Insert multiple records
144
+ products = await Product.insert([
145
+ {"name": "Product 1", "price": 10.99},
146
+ {"name": "Product 2", "price": 24.99}
147
+ ])
148
+ ```
149
+
150
+ ### Update Method
151
+
152
+ The `update()` method allows updates based on ID or criteria:
153
+
154
+ ```python
155
+ # Update by ID
156
+ user = await User.update({"email": "new@example.com"}, 1)
157
+
158
+ # Update by criteria
159
+ count = await User.update(
160
+ {"is_active": False},
161
+ {"last_login": None} # Set all users without login to inactive
162
+ )
163
+
164
+ # Update with relationships
165
+ await User.update(
166
+ {"department": {"name": "Sales"}}, # Update department relationship
167
+ {"username": "john_doe"}
168
+ )
169
+ ```
170
+
171
+ ### Delete Method
172
+
173
+ The `delete()` method provides a consistent way to delete records:
174
+
175
+ ```python
176
+ # Delete by ID
177
+ success = await User.delete(1)
178
+
179
+ # Delete by criteria
180
+ deleted_count = await User.delete({"is_active": False})
181
+
182
+ # Delete with compound criteria
183
+ await Post.delete({"author": {"username": "john_doe"}, "is_published": False})
184
+ ```
185
+
186
+ ## Convenience Query Methods
187
+
188
+ EasyModel also provides convenient shorthand methods for common queries:
189
+
190
+ ```python
191
+ # Get all records with relationships loaded (default)
192
+ users = await User.all()
193
+
194
+ # Get all records ordered by a field
195
+ users = await User.all(order_by="username")
196
+
197
+ # Get the first record
198
+ user = await User.first()
199
+
200
+ # Get the most recently created user
201
+ newest_user = await User.first(order_by="-created_at")
202
+
203
+ # Get limited records
204
+ recent_users = await User.limit(10, order_by="-created_at")
205
+ ```
206
+
207
+ ## Automatic Relationship Detection
208
+
209
+ EasyModel supports automatic relationship detection based on foreign key fields:
210
+
211
+ ```python
212
+ from async_easy_model import enable_auto_relationships, EasyModel, init_db, Field
213
+ from typing import Optional
214
+
215
+ # Enable automatic relationship detection
216
+ enable_auto_relationships()
217
+
218
+ # Define models with foreign keys but without explicit relationships
219
+ class Author(EasyModel, table=True):
220
+ # id field is automatically created (primary key)
221
+ name: str
222
+
223
+ class Book(EasyModel, table=True):
224
+ title: str
225
+ author_id: Optional[int] = Field(default=None, foreign_key="author.id")
226
+ # No need to define Relationship attributes - they're detected automatically!
227
+
228
+ # Use the automatically detected relationships
229
+ async def main():
230
+ await init_db()
231
+ author = await Author.insert({"name": "Jane Author"})
232
+
233
+ book = await Book.insert({
234
+ "title": "Auto-detected Relationships",
235
+ "author_id": author.id
236
+ })
237
+
238
+ # Show the book with its author
239
+ print(f"Book: {book.title}, Author: {book.author.name}")
240
+ ```
241
+
242
+ ### Another Example
243
+ ```python
244
+ # Using the standard insert with nested dictionaries (recommended)
245
+ new_book = await Book.insert({
246
+ "title": "New Book",
247
+ "author": {"name": "Jane Author"} # Will create or find the author
248
+ })
249
+ ```
250
+
251
+ ## Automatic Schema Migrations
252
+
253
+ EasyModel includes automatic database migration capabilities, similar to alembic:
254
+
255
+ ```python
256
+ from async_easy_model import MigrationManager
257
+
258
+ async def apply_migrations():
259
+ migration_manager = MigrationManager()
260
+ results = await migration_manager.migrate_models([User, Post])
261
+
262
+ if results:
263
+ print("Migrations applied:")
264
+ for model_name, changes in results.items():
265
+ print(f" {model_name}:")
266
+ for change in changes:
267
+ print(f" - {change}")
268
+ ```
269
+
270
+ ## Legacy API Methods
271
+
272
+ The following methods are still supported but the standardized methods above are recommended for new code:
273
+
274
+ ### Traditional CRUD Operations
275
+
276
+ ```python
277
+ # Create a record (consider using insert() instead)
278
+ user = User(username="john_doe", email="john@example.com")
279
+ await user.save()
280
+
281
+ # Get by ID (consider using select() instead)
282
+ user = await User.get_by_id(1)
283
+
284
+ # Get by attribute (consider using select() instead)
285
+ users = await User.get_by_attribute(is_active=True, all=True)
286
+
287
+ # Update by ID (consider using update() instead)
288
+ updated_user = await User.update_by_id(1, {"email": "new_email@example.com"})
289
+
290
+ # Update by attribute (consider using update() instead)
291
+ await User.update_by_attribute(
292
+ {"is_active": False}, # Update data
293
+ is_active=True, role="guest" # Filter criteria
294
+ )
295
+
296
+ # Delete by ID (consider using delete() instead)
297
+ success = await User.delete_by_id(1)
298
+
299
+ # Delete by attribute (consider using delete() instead)
300
+ deleted_count = await User.delete_by_attribute(is_active=False)
301
+ ```
302
+
303
+ ## Complete Documentation
304
+
305
+ For complete documentation, including advanced features, please see the [full documentation](DOCS.md).
@@ -22,8 +22,20 @@ _auto_processed_models = set()
22
22
  _auto_relationships_processed = False
23
23
 
24
24
  # Flag to enable/disable automatic relationship detection
25
+ # Disabled by default and will be enabled during init_db
25
26
  _auto_relationships_enabled = False
26
27
 
28
+ # Automatically disable auto-relationships at module import time
29
+ # This ensures models can be defined without immediate processing
30
+ def _disable_auto_relationships_on_import():
31
+ # This will be automatically called when the module is imported
32
+ global _auto_relationships_enabled
33
+ _auto_relationships_enabled = False
34
+ logger.info("Auto relationships disabled by default at import")
35
+
36
+ # Call the function immediately when this module is imported
37
+ _disable_auto_relationships_on_import()
38
+
27
39
  def pluralize_name(name: str) -> str:
28
40
  """Convert a singular noun to its plural form."""
29
41
  # Check if the name already ends with 's'