plain.postgres 0.84.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.
Files changed (93) hide show
  1. plain/postgres/CHANGELOG.md +1028 -0
  2. plain/postgres/README.md +925 -0
  3. plain/postgres/__init__.py +120 -0
  4. plain/postgres/agents/.claude/rules/plain-postgres.md +78 -0
  5. plain/postgres/aggregates.py +236 -0
  6. plain/postgres/backups/__init__.py +0 -0
  7. plain/postgres/backups/cli.py +148 -0
  8. plain/postgres/backups/clients.py +94 -0
  9. plain/postgres/backups/core.py +172 -0
  10. plain/postgres/base.py +1415 -0
  11. plain/postgres/cli/__init__.py +3 -0
  12. plain/postgres/cli/db.py +142 -0
  13. plain/postgres/cli/migrations.py +1085 -0
  14. plain/postgres/config.py +18 -0
  15. plain/postgres/connection.py +1331 -0
  16. plain/postgres/connections.py +77 -0
  17. plain/postgres/constants.py +13 -0
  18. plain/postgres/constraints.py +495 -0
  19. plain/postgres/database_url.py +94 -0
  20. plain/postgres/db.py +59 -0
  21. plain/postgres/default_settings.py +38 -0
  22. plain/postgres/deletion.py +475 -0
  23. plain/postgres/dialect.py +640 -0
  24. plain/postgres/entrypoints.py +4 -0
  25. plain/postgres/enums.py +103 -0
  26. plain/postgres/exceptions.py +217 -0
  27. plain/postgres/expressions.py +1912 -0
  28. plain/postgres/fields/__init__.py +2118 -0
  29. plain/postgres/fields/encrypted.py +354 -0
  30. plain/postgres/fields/json.py +413 -0
  31. plain/postgres/fields/mixins.py +30 -0
  32. plain/postgres/fields/related.py +1192 -0
  33. plain/postgres/fields/related_descriptors.py +290 -0
  34. plain/postgres/fields/related_lookups.py +223 -0
  35. plain/postgres/fields/related_managers.py +661 -0
  36. plain/postgres/fields/reverse_descriptors.py +229 -0
  37. plain/postgres/fields/reverse_related.py +328 -0
  38. plain/postgres/fields/timezones.py +143 -0
  39. plain/postgres/forms.py +773 -0
  40. plain/postgres/functions/__init__.py +189 -0
  41. plain/postgres/functions/comparison.py +127 -0
  42. plain/postgres/functions/datetime.py +454 -0
  43. plain/postgres/functions/math.py +140 -0
  44. plain/postgres/functions/mixins.py +59 -0
  45. plain/postgres/functions/text.py +282 -0
  46. plain/postgres/functions/window.py +125 -0
  47. plain/postgres/indexes.py +286 -0
  48. plain/postgres/lookups.py +758 -0
  49. plain/postgres/meta.py +584 -0
  50. plain/postgres/migrations/__init__.py +53 -0
  51. plain/postgres/migrations/autodetector.py +1379 -0
  52. plain/postgres/migrations/exceptions.py +54 -0
  53. plain/postgres/migrations/executor.py +188 -0
  54. plain/postgres/migrations/graph.py +364 -0
  55. plain/postgres/migrations/loader.py +377 -0
  56. plain/postgres/migrations/migration.py +180 -0
  57. plain/postgres/migrations/operations/__init__.py +34 -0
  58. plain/postgres/migrations/operations/base.py +139 -0
  59. plain/postgres/migrations/operations/fields.py +373 -0
  60. plain/postgres/migrations/operations/models.py +798 -0
  61. plain/postgres/migrations/operations/special.py +184 -0
  62. plain/postgres/migrations/optimizer.py +74 -0
  63. plain/postgres/migrations/questioner.py +340 -0
  64. plain/postgres/migrations/recorder.py +119 -0
  65. plain/postgres/migrations/serializer.py +378 -0
  66. plain/postgres/migrations/state.py +882 -0
  67. plain/postgres/migrations/utils.py +147 -0
  68. plain/postgres/migrations/writer.py +302 -0
  69. plain/postgres/options.py +207 -0
  70. plain/postgres/otel.py +231 -0
  71. plain/postgres/preflight.py +336 -0
  72. plain/postgres/query.py +2242 -0
  73. plain/postgres/query_utils.py +456 -0
  74. plain/postgres/registry.py +217 -0
  75. plain/postgres/schema.py +1885 -0
  76. plain/postgres/sql/__init__.py +40 -0
  77. plain/postgres/sql/compiler.py +1869 -0
  78. plain/postgres/sql/constants.py +22 -0
  79. plain/postgres/sql/datastructures.py +222 -0
  80. plain/postgres/sql/query.py +2947 -0
  81. plain/postgres/sql/where.py +374 -0
  82. plain/postgres/test/__init__.py +0 -0
  83. plain/postgres/test/pytest.py +117 -0
  84. plain/postgres/test/utils.py +18 -0
  85. plain/postgres/transaction.py +222 -0
  86. plain/postgres/types.py +92 -0
  87. plain/postgres/types.pyi +751 -0
  88. plain/postgres/utils.py +345 -0
  89. plain_postgres-0.84.0.dist-info/METADATA +937 -0
  90. plain_postgres-0.84.0.dist-info/RECORD +93 -0
  91. plain_postgres-0.84.0.dist-info/WHEEL +4 -0
  92. plain_postgres-0.84.0.dist-info/entry_points.txt +5 -0
  93. plain_postgres-0.84.0.dist-info/licenses/LICENSE +61 -0
@@ -0,0 +1,1028 @@
1
+ # plain-postgres changelog
2
+
3
+ ## [0.84.0](https://github.com/dropseed/plain/releases/plain-postgres@0.84.0) (2026-03-12)
4
+
5
+ ### What's changed
6
+
7
+ - Renamed package from `plain-models` to `plain-postgres` — the pip package, module path, and package label (`plainmodels` to `plainpostgres`) all reflect the PostgreSQL-only scope.
8
+ - All internal imports updated from `plain.models` to `plain.postgres`.
9
+ - Flattened `plain.models.postgres` subpackage into top-level `plain.postgres`.
10
+
11
+ ### Upgrade instructions
12
+
13
+ - Update imports: `from plain.models` to `from plain.postgres`, `from plain import models` to `from plain import postgres`.
14
+ - In `pyproject.toml`, change `plain-models` to `plain-postgres` and `plain.models` to `plain.postgres` in dependencies.
15
+ - In `INSTALLED_PACKAGES`, change `"plain.models"` to `"plain.postgres"`.
16
+
17
+ ## [0.83.0](https://github.com/dropseed/plain/releases/plain-postgres@0.83.0) (2026-03-12)
18
+
19
+ ### What's changed
20
+
21
+ - Renamed `plain.models` to `plain.postgres` — the package name now reflects its PostgreSQL-only scope.
22
+ - Flattened the `plain.models.postgres` subpackage — all internal modules now live at the top level.
23
+
24
+ ### Upgrade instructions
25
+
26
+ - Change `from plain import models` → `from plain import postgres` and update all `models.X` usages to `postgres.X` (e.g. `postgres.Model`, `postgres.register_model`, `postgres.CASCADE`).
27
+ - Change `from plain.models import ...` → `from plain.postgres import ...`.
28
+ - In `pyproject.toml`, change `plain.models` → `plain.postgres` and `plain-models` → `plain-postgres` in dependencies.
29
+ - In `INSTALLED_PACKAGES`, change `"plain.models"` → `"plain.postgres"`.
30
+
31
+ ## [0.82.3](https://github.com/dropseed/plain/releases/plain-models@0.82.3) (2026-03-10)
32
+
33
+ ### What's changed
34
+
35
+ - Removed `type: ignore` comments on `POSTGRES_PASSWORD` default values, now that `Secret` is type-transparent ([997afd9a558f](https://github.com/dropseed/plain/commit/997afd9a558f))
36
+ - Adopted PEP 695 type parameter syntax across `Field`, `QuerySet`, `register_model`, type stubs, and other generics ([aa5b2db6e8ed](https://github.com/dropseed/plain/commit/aa5b2db6e8ed))
37
+ - Added migration docs reminder to AI rules ([09deb5d5a382](https://github.com/dropseed/plain/commit/09deb5d5a382))
38
+
39
+ ### Upgrade instructions
40
+
41
+ - No changes required.
42
+
43
+ ## [0.82.2](https://github.com/dropseed/plain/releases/plain-models@0.82.2) (2026-03-10)
44
+
45
+ ### What's changed
46
+
47
+ - Updated all README code examples to use `types.*` with Python type annotations as the default pattern ([772345d4e1f1](https://github.com/dropseed/plain/commit/772345d4e1f1))
48
+ - Removed separate "Typed fields" and "Typing reverse relationships" doc sections — typed fields are now the default in all examples ([772345d4e1f1](https://github.com/dropseed/plain/commit/772345d4e1f1))
49
+ - Added "Field Imports" section and "Differences from Django" section to AI rules ([772345d4e1f1](https://github.com/dropseed/plain/commit/772345d4e1f1))
50
+ - Broadened AI rules to apply to all Python files, not just model files ([772345d4e1f1](https://github.com/dropseed/plain/commit/772345d4e1f1))
51
+
52
+ ### Upgrade instructions
53
+
54
+ - No changes required.
55
+
56
+ ## [0.82.1](https://github.com/dropseed/plain/releases/plain-models@0.82.1) (2026-03-10)
57
+
58
+ ### What's changed
59
+
60
+ - Replaced `SET()` closure with a `_SetOnDelete` class to eliminate `type: ignore` comments for dynamic attribute assignment (`deconstruct`, `lazy_sub_objs`) ([cda461b1b4f6](https://github.com/dropseed/plain/commit/cda461b1b4f6))
61
+ - Replaced `lazy_sub_objs` function attribute on `SET_NULL` and `SET_DEFAULT` with a module-level `_LAZY_ON_DELETE` set ([cda461b1b4f6](https://github.com/dropseed/plain/commit/cda461b1b4f6))
62
+ - Narrowed `_relation_tree` type and used `get_forward_field` in migration operations ([eb5af6a525b5](https://github.com/dropseed/plain/commit/eb5af6a525b5))
63
+ - Type annotation improvements across expressions, indexes, related fields, and deletion modules ([f56c6454b164](https://github.com/dropseed/plain/commit/f56c6454b164))
64
+
65
+ ### Upgrade instructions
66
+
67
+ - No changes required.
68
+
69
+ ## [0.82.0](https://github.com/dropseed/plain/releases/plain-models@0.82.0) (2026-03-09)
70
+
71
+ ### What's changed
72
+
73
+ - Added `EncryptedTextField` and `EncryptedJSONField` for transparent encryption at rest using Fernet (AES-128-CBC + HMAC-SHA256) with keys derived from `SECRET_KEY` ([73f3534f9334](https://github.com/dropseed/plain/commit/73f3534f9334))
74
+ - Encrypted fields support key rotation via `SECRET_KEY_FALLBACKS` and gradual migration from plaintext columns ([73f3534f9334](https://github.com/dropseed/plain/commit/73f3534f9334))
75
+ - Preflight checks prevent encrypted fields from being used in indexes or constraints ([73f3534f9334](https://github.com/dropseed/plain/commit/73f3534f9334))
76
+
77
+ ### Upgrade instructions
78
+
79
+ - No changes required. Install the `cryptography` package to use the new encrypted fields.
80
+
81
+ ## [0.81.1](https://github.com/dropseed/plain/releases/plain-models@0.81.1) (2026-03-09)
82
+
83
+ ### What's changed
84
+
85
+ - Use `connection.execute()` instead of opening a cursor for internal one-off queries (timezone configuration, role assumption, connection health checks) ([828d665979df](https://github.com/dropseed/plain/commit/828d665979df))
86
+
87
+ ### Upgrade instructions
88
+
89
+ - No changes required.
90
+
91
+ ## [0.81.0](https://github.com/dropseed/plain/releases/plain-models@0.81.0) (2026-03-09)
92
+
93
+ ### What's changed
94
+
95
+ - **psycopg3 `cursor.stream()` for iterator queries** — `QuerySet.iterator()` now uses psycopg3's native server-side streaming instead of `fetchmany()` chunking, reducing memory overhead for large result sets ([49f4d1d996b4](https://github.com/dropseed/plain/commit/49f4d1d996b4))
96
+ - **Minimum PostgreSQL 16 enforced** — a preflight check now validates the connected PostgreSQL version is 16 or higher ([e1f21c4b251a](https://github.com/dropseed/plain/commit/e1f21c4b251a))
97
+ - **Renamed `DatabaseWrapper` → `DatabaseConnection`** and moved from `postgres/wrapper.py` to `postgres/connection.py` to better reflect the class's purpose ([7f17a96a7f8e](https://github.com/dropseed/plain/commit/7f17a96a7f8e), [4a79279d01dd](https://github.com/dropseed/plain/commit/4a79279d01dd))
98
+ - **Replaced `db_connection` proxy with `get_connection()`** — the stateless `DatabaseConnection` proxy class is removed in favor of module-level `get_connection()` and `has_connection()` functions, giving type checkers direct access to the real `DatabaseConnection` class and eliminating proxy overhead ([4a79279d01dd](https://github.com/dropseed/plain/commit/4a79279d01dd))
99
+ - **Replaced `threading.local()` with `ContextVar` for DB connection storage** — database connections are now stored per-context instead of per-thread, enabling proper async support ([cc2469b1260a](https://github.com/dropseed/plain/commit/cc2469b1260a))
100
+ - Removed `validate_thread_sharing()` from `DatabaseConnection` — thread sharing validation is no longer needed with ContextVar-based connection storage ([3a6d6efd09d2](https://github.com/dropseed/plain/commit/3a6d6efd09d2))
101
+ - Extracted `get_converters()` and `apply_converters()` as standalone functions from `SQLCompiler` and added type annotations ([ed18d3c97142](https://github.com/dropseed/plain/commit/ed18d3c97142))
102
+
103
+ ### Upgrade instructions
104
+
105
+ - Replace `from plain.models import db_connection` with `from plain.models import get_connection`, and change `db_connection.cursor()` to `get_connection().cursor()` (and similar attribute access).
106
+ - If you imported `DatabaseWrapper`, it is now `DatabaseConnection` from `plain.models.postgres.connection`.
107
+ - PostgreSQL 16 or higher is now required.
108
+
109
+ ## [0.80.0](https://github.com/dropseed/plain/releases/plain-models@0.80.0) (2026-02-25)
110
+
111
+ ### What's changed
112
+
113
+ - Replaced the `DATABASE` dict setting with individual `POSTGRES_*` settings (`POSTGRES_HOST`, `POSTGRES_PORT`, `POSTGRES_DATABASE`, `POSTGRES_USER`, `POSTGRES_PASSWORD`, etc.) configurable via `PLAIN_POSTGRES_*` environment variables or `app/settings.py` ([e3c5a32d4da6](https://github.com/dropseed/plain/commit/e3c5a32d4da6))
114
+ - `DATABASE_URL` still works and takes priority — individual settings are parsed from it automatically ([e3c5a32d4da6](https://github.com/dropseed/plain/commit/e3c5a32d4da6))
115
+ - Added `DATABASE_URL=none` to explicitly disable the database (e.g. during Docker builds) ([e3c5a32d4da6](https://github.com/dropseed/plain/commit/e3c5a32d4da6))
116
+ - Removed the `AUTOCOMMIT` config setting — Plain always runs with autocommit=True ([5dc1995615d9](https://github.com/dropseed/plain/commit/5dc1995615d9))
117
+ - Refactored backup client internals with shared `_get_conn_args()` and `_run()` helpers ([e3c5a32d4da6](https://github.com/dropseed/plain/commit/e3c5a32d4da6))
118
+
119
+ ### Upgrade instructions
120
+
121
+ - If you use `DATABASE_URL`, no changes are required — it continues to work as before.
122
+ - If you manually defined the `DATABASE` dict in settings, replace it with individual `POSTGRES_*` settings:
123
+
124
+ ```python
125
+ # Before
126
+ DATABASE = {"NAME": "mydb", "USER": "me", "HOST": "localhost"}
127
+
128
+ # After
129
+ POSTGRES_DATABASE = "mydb"
130
+ POSTGRES_USER = "me"
131
+ POSTGRES_HOST = "localhost"
132
+ ```
133
+
134
+ - The `DATABASE` dict key `"NAME"` is now `"DATABASE"` internally — update any code that accessed `settings_dict["NAME"]` directly.
135
+ - Remove any `AUTOCOMMIT` setting from your database config — it is no longer recognized.
136
+
137
+ ## [0.79.0](https://github.com/dropseed/plain/releases/plain-models@0.79.0) (2026-02-24)
138
+
139
+ ### What's changed
140
+
141
+ - Added `plain db drop-unknown-tables` command to remove database tables not associated with any Plain model ([108b0bce59e6](https://github.com/dropseed/plain/commit/108b0bce59e6))
142
+ - The unknown-tables preflight warning now suggests running `plain db drop-unknown-tables` instead of manual SQL ([108b0bce59e6](https://github.com/dropseed/plain/commit/108b0bce59e6))
143
+
144
+ ### Upgrade instructions
145
+
146
+ - No changes required.
147
+
148
+ ## [0.78.0](https://github.com/dropseed/plain/releases/plain-models@0.78.0) (2026-02-16)
149
+
150
+ ### What's changed
151
+
152
+ - **PostgreSQL is now the only supported database** — MySQL and SQLite backends have been removed ([6f3a066bf80f](https://github.com/dropseed/plain/commit/6f3a066bf80f))
153
+ - The `ENGINE` key has been removed from the `DATABASE` setting — it is no longer needed since PostgreSQL is implicit ([6f3a066bf80f](https://github.com/dropseed/plain/commit/6f3a066bf80f))
154
+ - Database backends consolidated from `backends/base/`, `backends/postgresql/`, `backends/mysql/`, and `backends/sqlite3/` into a single `postgres/` module ([6f3a066bf80f](https://github.com/dropseed/plain/commit/6f3a066bf80f))
155
+ - Removed `DatabaseOperations` indirection layer — compilers are now created directly by `Query.get_compiler()` ([6f3a066bf80f](https://github.com/dropseed/plain/commit/6f3a066bf80f))
156
+ - Removed backend feature flags and multi-database conditional code throughout expressions, aggregates, schema editor, and migrations ([6f3a066bf80f](https://github.com/dropseed/plain/commit/6f3a066bf80f))
157
+ - Installation now recommends `uv add plain.models psycopg[binary]` to include the PostgreSQL driver ([6f3a066bf80f](https://github.com/dropseed/plain/commit/6f3a066bf80f))
158
+
159
+ ### Upgrade instructions
160
+
161
+ - Remove `"ENGINE"` from your `DATABASE` setting — it will be ignored
162
+ - If you were using MySQL or SQLite, you must migrate to PostgreSQL
163
+ - Update any imports from `plain.models.backends.base` or `plain.models.backends.postgresql` to `plain.models.postgres`
164
+ - Install a PostgreSQL driver if you haven't already: `uv add psycopg[binary]`
165
+
166
+ ## [0.77.1](https://github.com/dropseed/plain/releases/plain-models@0.77.1) (2026-02-13)
167
+
168
+ ### What's changed
169
+
170
+ - Added migration development workflow documentation covering how to consolidate uncommitted and committed migrations ([0b30f98b5346](https://github.com/dropseed/plain/commit/0b30f98b5346))
171
+ - Added migration cleanup guidance to agent rules: consolidate before committing, use squash only for deployed migrations ([0b30f98b5346](https://github.com/dropseed/plain/commit/0b30f98b5346))
172
+
173
+ ### Upgrade instructions
174
+
175
+ - No changes required.
176
+
177
+ ## [0.77.0](https://github.com/dropseed/plain/releases/plain-models@0.77.0) (2026-02-13)
178
+
179
+ ### What's changed
180
+
181
+ - `makemigrations --dry-run` now shows a SQL preview of the statements each migration would execute, making it easier to review schema changes before writing migration files ([c994703f9a28](https://github.com/dropseed/plain/commit/c994703f9a28))
182
+ - `makemigrations` now warns when packages have models but no `migrations/` directory, which can cause "No changes detected" confusion for new apps ([c994703f9a28](https://github.com/dropseed/plain/commit/c994703f9a28))
183
+ - Restructured README documentation: consolidated Querying section with Custom QuerySets, Typing, and Raw SQL; added N+1 avoidance and query efficiency subsections; reorganized Relationships and Constraints into clearer sections with schema design guidance ([f5d2731ebda0](https://github.com/dropseed/plain/commit/f5d2731ebda0), [8c2189a896d2](https://github.com/dropseed/plain/commit/8c2189a896d2))
184
+ - Slimmed agent rules to concise bullet reminders with `paths:` scoping for `**/models.py` files ([f5d2731ebda0](https://github.com/dropseed/plain/commit/f5d2731ebda0))
185
+
186
+ ### Upgrade instructions
187
+
188
+ - No changes required.
189
+
190
+ ## [0.76.5](https://github.com/dropseed/plain/releases/plain-models@0.76.5) (2026-02-12)
191
+
192
+ ### What's changed
193
+
194
+ - Updated README model validation example to use `@models.register_model`, `UniqueConstraint`, and `model_options` ([9db8e0aa5d43](https://github.com/dropseed/plain/commit/9db8e0aa5d43))
195
+ - Added schema planning guidance to agent rules ([eaf55cb1b893](https://github.com/dropseed/plain/commit/eaf55cb1b893))
196
+
197
+ ### Upgrade instructions
198
+
199
+ - No changes required.
200
+
201
+ ## [0.76.4](https://github.com/dropseed/plain/releases/plain-models@0.76.4) (2026-02-04)
202
+
203
+ ### What's changed
204
+
205
+ - Added `__all__` exports to `expressions` module for explicit public API boundaries ([e7164d3891b2](https://github.com/dropseed/plain/commit/e7164d3891b2))
206
+ - Refactored internal imports to use explicit module paths instead of the `sql` namespace ([e7164d3891b2](https://github.com/dropseed/plain/commit/e7164d3891b2))
207
+ - Updated agent rules to use `--api` instead of `--symbols` for `plain docs` command ([e7164d3891b2](https://github.com/dropseed/plain/commit/e7164d3891b2))
208
+
209
+ ### Upgrade instructions
210
+
211
+ - No changes required.
212
+
213
+ ## [0.76.3](https://github.com/dropseed/plain/releases/plain-models@0.76.3) (2026-02-02)
214
+
215
+ ### What's changed
216
+
217
+ - Fixed observer query summaries for SQL statements starting with parentheses (e.g., UNION queries) by stripping leading `(` before extracting the operation ([bfbcb5a256f2](https://github.com/dropseed/plain/commit/bfbcb5a256f2))
218
+ - UNION queries now display with a "UNION" suffix in query summaries for better identification ([bfbcb5a256f2](https://github.com/dropseed/plain/commit/bfbcb5a256f2))
219
+ - Agent rules now include query examples showing the `Model.query` pattern ([02e11328dbf5](https://github.com/dropseed/plain/commit/02e11328dbf5))
220
+
221
+ ### Upgrade instructions
222
+
223
+ - No changes required.
224
+
225
+ ## [0.76.2](https://github.com/dropseed/plain/releases/plain-models@0.76.2) (2026-01-28)
226
+
227
+ ### What's changed
228
+
229
+ - Converted the `plain-models` skill to a passive `.claude/rules/` file ([512040ac51](https://github.com/dropseed/plain/commit/512040ac51))
230
+
231
+ ### Upgrade instructions
232
+
233
+ - Run `plain agent install` to update your `.claude/` directory.
234
+
235
+ ## [0.76.1](https://github.com/dropseed/plain/releases/plain-models@0.76.1) (2026-01-28)
236
+
237
+ ### What's changed
238
+
239
+ - Added Settings section to README ([803fee1ad5](https://github.com/dropseed/plain/commit/803fee1ad5))
240
+
241
+ ### Upgrade instructions
242
+
243
+ - No changes required.
244
+
245
+ ## [0.76.0](https://github.com/dropseed/plain/releases/plain-models@0.76.0) (2026-01-22)
246
+
247
+ ### What's changed
248
+
249
+ - Removed the `db_column` field parameter - column names are now always derived from the field name ([eed1bb6](https://github.com/dropseed/plain/commit/eed1bb6811))
250
+ - Removed the `db_collation` field parameter from `CharField` and `TextField` - use raw SQL or database-level collation settings instead ([49b362d](https://github.com/dropseed/plain/commit/49b362d3d3))
251
+ - Removed the `Collate` database function from `plain.models.functions` ([49b362d](https://github.com/dropseed/plain/commit/49b362d3d3))
252
+ - Removed the `db_comment` field parameter and `db_table_comment` model option - database comments are no longer supported ([eb5aabb](https://github.com/dropseed/plain/commit/eb5aabb5ca))
253
+ - Removed the `AlterModelTableComment` migration operation ([eb5aabb](https://github.com/dropseed/plain/commit/eb5aabb5ca))
254
+ - Added `BaseDatabaseSchemaEditor` and `StateModelsRegistry` exports from `plain.models.migrations` for use in type annotations in `RunPython` functions ([672aa88](https://github.com/dropseed/plain/commit/672aa8861a))
255
+
256
+ ### Upgrade instructions
257
+
258
+ - Remove any `db_column` arguments from field definitions - the column name will always match the field's attribute name (with `_id` suffix for foreign keys)
259
+ - Remove `db_column` from all migrations
260
+ - Remove any `db_collation` arguments from `CharField` and `TextField` definitions
261
+ - Replace any usage of `Collate()` function with raw SQL queries or configure collation at the database level
262
+ - Remove any `db_comment` arguments from field definitions
263
+ - Remove `db_comment` from all migrations
264
+ - Remove any `db_table_comment` from `model_options` definitions
265
+ - Replace `AlterModelTableComment` migration operations with `RunSQL` if database comments are still needed
266
+
267
+ ## [0.75.0](https://github.com/dropseed/plain/releases/plain-models@0.75.0) (2026-01-15)
268
+
269
+ ### What's changed
270
+
271
+ - Added type annotations to `CursorWrapper` fetch methods (`fetchone`, `fetchmany`, `fetchall`) for better type checker support ([7635258](https://github.com/dropseed/plain/commit/7635258de0))
272
+ - Internal cleanup: removed redundant `tzinfo` class attribute from `TruncBase` ([0cb5a84](https://github.com/dropseed/plain/commit/0cb5a84718))
273
+
274
+ ### Upgrade instructions
275
+
276
+ - No changes required
277
+
278
+ ## [0.74.0](https://github.com/dropseed/plain/releases/plain-models@0.74.0) (2026-01-15)
279
+
280
+ ### What's changed
281
+
282
+ - Internal skill configuration update - no user-facing changes ([fac8673](https://github.com/dropseed/plain/commit/fac8673436))
283
+
284
+ ### Upgrade instructions
285
+
286
+ - No changes required
287
+
288
+ ## [0.73.0](https://github.com/dropseed/plain/releases/plain-models@0.73.0) (2026-01-15)
289
+
290
+ ### What's changed
291
+
292
+ - The `__repr__` method on models now returns `<ClassName: id>` instead of `<ClassName: str(self)>`, avoiding potential side effects from custom `__str__` implementations ([0fc4dd3](https://github.com/dropseed/plain/commit/0fc4dd345f))
293
+
294
+ ### Upgrade instructions
295
+
296
+ - No changes required
297
+
298
+ ## [0.72.0](https://github.com/dropseed/plain/releases/plain-models@0.72.0) (2026-01-13)
299
+
300
+ ### What's changed
301
+
302
+ - Fixed `TimezoneField` deconstruct path to correctly resolve to `plain.models` instead of `plain.models.fields.timezones`, preventing migration churn when using `TimezoneField` ([03cc263](https://github.com/dropseed/plain/commit/03cc263ffa))
303
+
304
+ ### Upgrade instructions
305
+
306
+ - No changes required
307
+
308
+ ## [0.71.0](https://github.com/dropseed/plain/releases/plain-models@0.71.0) (2026-01-13)
309
+
310
+ ### What's changed
311
+
312
+ - `TimeZoneField` choices are no longer serialized in migrations, preventing spurious migration diffs when timezone data differs between machines ([0ede3aae](https://github.com/dropseed/plain/commit/0ede3aae5d))
313
+ - `TimeZoneField` no longer accepts custom choices - the field's purpose is to provide the canonical timezone list ([0ede3aae](https://github.com/dropseed/plain/commit/0ede3aae5d))
314
+ - Simplified `plain migrate` output - package name is only shown when explicitly targeting a specific package ([006efae9](https://github.com/dropseed/plain/commit/006efae92d))
315
+ - Field ordering is now explicit (primary key first, then alphabetically by name) instead of using an internal creation counter ([3ffa44bd](https://github.com/dropseed/plain/commit/3ffa44bdcb))
316
+
317
+ ### Upgrade instructions
318
+
319
+ - If you have existing migrations that contain `TimeZoneField` with serialized `choices`, you can safely remove the `choices` parameter from those migrations as they are now computed dynamically
320
+ - If you were passing custom `choices` to `TimeZoneField`, this is no longer supported - use a regular `CharField` with choices instead
321
+
322
+ ## [0.70.0](https://github.com/dropseed/plain/releases/plain-models@0.70.0) (2025-12-26)
323
+
324
+ ### What's changed
325
+
326
+ - Added `TimeZoneField` for storing timezone information - stores timezone names as strings in the database but provides `zoneinfo.ZoneInfo` objects when accessed, similar to how `DateField` works with `datetime.date` ([b533189](https://github.com/dropseed/plain/commit/b533189576))
327
+ - Documentation improvements listing all available field types in the README ([11837ad](https://github.com/dropseed/plain/commit/11837ad2f2))
328
+
329
+ ### Upgrade instructions
330
+
331
+ - No changes required
332
+
333
+ ## [0.69.1](https://github.com/dropseed/plain/releases/plain-models@0.69.1) (2025-12-22)
334
+
335
+ ### What's changed
336
+
337
+ - Internal type annotation improvements for better type checker compatibility ([539a706](https://github.com/dropseed/plain/commit/539a706760), [5c0e403](https://github.com/dropseed/plain/commit/5c0e403863))
338
+
339
+ ### Upgrade instructions
340
+
341
+ - No changes required
342
+
343
+ ## [0.69.0](https://github.com/dropseed/plain/releases/plain-models@0.69.0) (2025-12-12)
344
+
345
+ ### What's changed
346
+
347
+ - The `queryset.all()` method now preserves the prefetch cache, fixing an issue where accessing prefetched related objects through `.all()` would trigger additional database queries instead of using the cached results ([8b899a8](https://github.com/dropseed/plain/commit/8b899a807a))
348
+
349
+ ### Upgrade instructions
350
+
351
+ - No changes required
352
+
353
+ ## [0.68.0](https://github.com/dropseed/plain/releases/plain-models@0.68.0) (2025-12-09)
354
+
355
+ ### What's changed
356
+
357
+ - Database backups now store git metadata (branch and commit) and the `plain db backups list` command displays this information along with source and size in a table format ([287fa89f](https://github.com/dropseed/plain/commit/287fa89fb1))
358
+ - Added `--branch` option to `plain db backups list` to filter backups by git branch ([287fa89f](https://github.com/dropseed/plain/commit/287fa89fb1))
359
+ - `ReverseForeignKey` and `ReverseManyToMany` now support an optional second type parameter for custom QuerySet types, enabling type checkers to recognize custom QuerySet methods on reverse relations ([487c6195](https://github.com/dropseed/plain/commit/487c6195bf))
360
+ - Internal cleanup: removed legacy generic foreign key related code ([c9ca1b67](https://github.com/dropseed/plain/commit/c9ca1b670a))
361
+
362
+ ### Upgrade instructions
363
+
364
+ - To get type checking for custom QuerySet methods on reverse relations, you can optionally add a second type parameter: `books: types.ReverseForeignKey[Book, BookQuerySet] = types.ReverseForeignKey(to="Book", field="author")`. This is optional and existing code without the second parameter continues to work.
365
+
366
+ ## [0.67.0](https://github.com/dropseed/plain/releases/plain-models@0.67.0) (2025-12-05)
367
+
368
+ ### What's changed
369
+
370
+ - Simplified Query/Compiler architecture by moving compiler selection from Query classes to DatabaseOperations ([1d1ae5a6](https://github.com/dropseed/plain/commit/1d1ae5a61f))
371
+ - The `raw()` method now accepts any `Sequence` for params (e.g., lists) instead of requiring tuples ([1d1ae5a6](https://github.com/dropseed/plain/commit/1d1ae5a61f))
372
+ - Internal type annotation improvements across database backends and SQL compiler modules ([bc02184d](https://github.com/dropseed/plain/commit/bc02184de7), [e068dcf2](https://github.com/dropseed/plain/commit/e068dcf201), [33fa09d6](https://github.com/dropseed/plain/commit/33fa09d66f))
373
+
374
+ ### Upgrade instructions
375
+
376
+ - No changes required
377
+
378
+ ## [0.66.0](https://github.com/dropseed/plain/releases/plain-models@0.66.0) (2025-12-05)
379
+
380
+ ### What's changed
381
+
382
+ - Removed `union()`, `intersection()`, and `difference()` combinator methods from QuerySet - use raw SQL for set operations instead ([0bae6abd](https://github.com/dropseed/plain/commit/0bae6abd94))
383
+ - Removed `dates()` and `datetimes()` methods from QuerySet ([62ba81a6](https://github.com/dropseed/plain/commit/62ba81a627))
384
+ - Removed `in_bulk()` method from QuerySet ([62ba81a6](https://github.com/dropseed/plain/commit/62ba81a627))
385
+ - Removed `contains()` method from QuerySet ([62ba81a6](https://github.com/dropseed/plain/commit/62ba81a627))
386
+ - Internal cleanup: removed unused database backend feature flags and operations (`autoinc_sql`, `allows_group_by_selected_pks_on_model`, `connection_persists_old_columns`, `implied_column_null`, `for_update_after_from`, `select_for_update_of_column`, `modify_insert_params`) ([defe5015](https://github.com/dropseed/plain/commit/defe5015e6), [7e62b635](https://github.com/dropseed/plain/commit/7e62b635ba), [30073da1](https://github.com/dropseed/plain/commit/30073da128))
387
+
388
+ ### Upgrade instructions
389
+
390
+ - Replace any usage of `queryset.union(other_qs)`, `queryset.intersection(other_qs)`, or `queryset.difference(other_qs)` with raw SQL queries using `Model.query.raw()` or database cursors
391
+ - Replace `queryset.dates(field, kind)` with equivalent annotate/values_list queries using `Trunc` and `DateField`
392
+ - Replace `queryset.datetimes(field, kind)` with equivalent annotate/values_list queries using `Trunc` and `DateTimeField`
393
+ - Replace `queryset.in_bulk(id_list)` with a dictionary comprehension like `{obj.id: obj for obj in queryset.filter(id__in=id_list)}`
394
+ - Replace `queryset.contains(obj)` with `queryset.filter(id=obj.id).exists()`
395
+
396
+ ## [0.65.1](https://github.com/dropseed/plain/releases/plain-models@0.65.1) (2025-12-04)
397
+
398
+ ### What's changed
399
+
400
+ - Fixed type annotations for `get_rhs_op` method in lookup classes to accept `str | list[str]` parameter, resolving type checker errors when using `Range` and other lookups that return list-based RHS values ([7030cd0](https://github.com/dropseed/plain/commit/7030cd0ee0))
401
+
402
+ ### Upgrade instructions
403
+
404
+ - No changes required
405
+
406
+ ## [0.65.0](https://github.com/dropseed/plain/releases/plain-models@0.65.0) (2025-12-04)
407
+
408
+ ### What's changed
409
+
410
+ - Improved type annotations for `ReverseForeignKey` and `ReverseManyToMany` descriptors - they are now proper generic descriptor classes with `__get__` overloads, providing better type inference when accessed on class vs instance ([ac1eeb0](https://github.com/dropseed/plain/commit/ac1eeb0ea0))
411
+ - Internal type annotation improvements across aggregates, expressions, database backends, and SQL compiler modules ([ac1eeb0](https://github.com/dropseed/plain/commit/ac1eeb0ea0))
412
+
413
+ ### Upgrade instructions
414
+
415
+ - No changes required
416
+
417
+ ## [0.64.0](https://github.com/dropseed/plain/releases/plain-models@0.64.0) (2025-11-24)
418
+
419
+ ### What's changed
420
+
421
+ - `bulk_create()` and `bulk_update()` now accept any `Sequence` type (e.g., tuples, generators) instead of requiring a `list` ([6c7469f](https://github.com/dropseed/plain/commit/6c7469f92a))
422
+
423
+ ### Upgrade instructions
424
+
425
+ - No changes required
426
+
427
+ ## [0.63.1](https://github.com/dropseed/plain/releases/plain-models@0.63.1) (2025-11-21)
428
+
429
+ ### What's changed
430
+
431
+ - Fixed `ManyToManyField` preflight checks that could fail when the intermediate model contained non-related fields (e.g., `CharField`, `IntegerField`) by properly filtering to only check `RelatedField` instances when counting foreign keys ([4a3fe5d](https://github.com/dropseed/plain/commit/4a3fe5d530))
432
+
433
+ ### Upgrade instructions
434
+
435
+ - No changes required
436
+
437
+ ## [0.63.0](https://github.com/dropseed/plain/releases/plain-models@0.63.0) (2025-11-21)
438
+
439
+ ### What's changed
440
+
441
+ - `ForeignKey` has been renamed to `ForeignKeyField` for consistency with other field naming conventions ([8010204](https://github.com/dropseed/plain/commit/8010204b36))
442
+ - Improved type annotations for `ManyToManyField` - now returns `ManyToManyManager[T]` instead of `Any` for better IDE support ([4536097](https://github.com/dropseed/plain/commit/4536097be1))
443
+ - Related managers (`ReverseForeignKeyManager` and `ManyToManyManager`) are now generic classes with proper type parameters for improved type checking ([3f61b6e](https://github.com/dropseed/plain/commit/3f61b6e51f))
444
+ - Added `ManyToManyManager` and `ReverseForeignKeyManager` exports to `plain.models.types` for use in type annotations ([4536097](https://github.com/dropseed/plain/commit/4536097be1))
445
+
446
+ ### Upgrade instructions
447
+
448
+ - Replace all usage of `models.ForeignKey` with `models.ForeignKeyField` (e.g., `category = models.ForeignKey("Category", on_delete=models.CASCADE)` becomes `category = models.ForeignKeyField("Category", on_delete=models.CASCADE)`)
449
+ - Replace all usage of `types.ForeignKey` with `types.ForeignKeyField` in typed model definitions
450
+ - Update migrations to use `ForeignKeyField` instead of `ForeignKey`
451
+
452
+ ## [0.62.1](https://github.com/dropseed/plain/releases/plain-models@0.62.1) (2025-11-20)
453
+
454
+ ### What's changed
455
+
456
+ - Fixed a bug where non-related fields could cause errors in migrations and schema operations by incorrectly assuming all fields have a `remote_field` attribute ([60b1bcc](https://github.com/dropseed/plain/commit/60b1bcc1c5))
457
+
458
+ ### Upgrade instructions
459
+
460
+ - No changes required
461
+
462
+ ## [0.62.0](https://github.com/dropseed/plain/releases/plain-models@0.62.0) (2025-11-20)
463
+
464
+ ### What's changed
465
+
466
+ - The `named` parameter has been removed from `QuerySet.values_list()` - named tuples are no longer supported for values lists ([0e39711](https://github.com/dropseed/plain/commit/0e397114c2))
467
+ - Internal method `get_extra_restriction()` has been removed from related fields and query data structures ([6157bd9](https://github.com/dropseed/plain/commit/6157bd90385137faf2cafbbd423a99326eedcd3b))
468
+ - Internal helper function `get_model_meta()` has been removed in favor of direct attribute access ([cb5a50e](https://github.com/dropseed/plain/commit/cb5a50ef1a0c5af61b97b96459bb14ed85df6f7f))
469
+ - Extensive type annotation improvements across the entire package, including database backends, query compilers, fields, migrations, and SQL modules ([a43145e](https://github.com/dropseed/plain/commit/a43145e69732a792b376e6548c6aac384df0ce28))
470
+ - Added `isinstance` checks for related fields and improved type narrowing throughout the codebase ([5b4bdf4](https://github.com/dropseed/plain/commit/5b4bdf47e74964780300e20c5fabfce68fa424c7))
471
+ - Improved type annotations for `Options.get_fields()` and related meta methods with more specific return types ([2c26f86](https://github.com/dropseed/plain/commit/2c26f86573df0cef473153d6224abdb99082e893))
472
+
473
+ ### Upgrade instructions
474
+
475
+ - Remove any usage of the `named=True` parameter in `values_list()` calls - if you need named access to query results, use `.values()` which returns dictionaries instead
476
+
477
+ ## [0.61.1](https://github.com/dropseed/plain/releases/plain-models@0.61.1) (2025-11-17)
478
+
479
+ ### What's changed
480
+
481
+ - The `@dataclass_transform` decorator has been removed from `ModelBase` to avoid type checker issues ([e0dbedb](https://github.com/dropseed/plain/commit/e0dbedb73f))
482
+ - Documentation and examples no longer suggest using `ClassVar` for QuerySet type annotations - the simpler `query: models.QuerySet[Model] = models.QuerySet()` pattern is now recommended ([1c624ff](https://github.com/dropseed/plain/commit/1c624ff29e), [99aecbc](https://github.com/dropseed/plain/commit/99aecbc17e))
483
+
484
+ ### Upgrade instructions
485
+
486
+ - If you were using `ClassVar` annotations for the `query` attribute, you can optionally remove the `ClassVar` wrapper and the `from typing import ClassVar` import. Both patterns work, but the simpler version without `ClassVar` is now recommended.
487
+
488
+ ## [0.61.0](https://github.com/dropseed/plain/releases/plain-models@0.61.0) (2025-11-14)
489
+
490
+ ### What's changed
491
+
492
+ - The `related_name` parameter has been removed from `ForeignKey` and `ManyToManyField` - reverse relationships are now declared explicitly using `ReverseForeignKey` and `ReverseManyToMany` descriptors on the related model ([a4b630969d](https://github.com/dropseed/plain/commit/a4b630969d))
493
+ - Added `ReverseForeignKey` and `ReverseManyToMany` descriptor classes to `plain.models.types` for declaring reverse relationships with full type support ([a4b630969d](https://github.com/dropseed/plain/commit/a4b630969d))
494
+ - The new reverse descriptors are exported from `plain.models` for easy access ([97fa112975](https://github.com/dropseed/plain/commit/97fa112975))
495
+ - Renamed internal references from `ManyToOne` to `ForeignKey` for consistency ([93c30f9caf](https://github.com/dropseed/plain/commit/93c30f9caf))
496
+ - Fixed a preflight check bug related to reverse relationships ([9191ae6e4b](https://github.com/dropseed/plain/commit/9191ae6e4b))
497
+ - Added comprehensive documentation for reverse relationships in the README ([5abf330e06](https://github.com/dropseed/plain/commit/5abf330e06))
498
+
499
+ ### Upgrade instructions
500
+
501
+ - Remove all `related_name` parameters from `ForeignKey` and `ManyToManyField` definitions
502
+ - Remove `related_name` from all migrations
503
+ - On the related model, add explicit reverse relationship descriptors using `ReverseForeignKey` or `ReverseManyToMany` from `plain.models.types`:
504
+ - For the reverse side of a `ForeignKey`, use: `children: types.ReverseForeignKey[Child] = types.ReverseForeignKey(to="Child", field="parent")`
505
+ - For the reverse side of a `ManyToManyField`, use: `cars: types.ReverseManyToMany[Car] = types.ReverseManyToMany(to="Car", field="features")`
506
+ - Remove any `TYPE_CHECKING` blocks that were used to declare reverse relationship types - the new descriptors provide full type support without these hacks
507
+ - The `to` parameter accepts either a string (model name) or the model class itself
508
+ - The `field` parameter should be the name of the forward field on the related model
509
+
510
+ ## [0.60.0](https://github.com/dropseed/plain/releases/plain-models@0.60.0) (2025-11-13)
511
+
512
+ ### What's changed
513
+
514
+ - Type annotations for QuerySets using `ClassVar` to improve type checking when accessing `Model.query` ([c3b00a6](https://github.com/dropseed/plain/commit/c3b00a693c))
515
+ - The `id` field on the Model base class now uses a type annotation (`id: int = types.PrimaryKeyField()`) for better type checking ([9febc80](https://github.com/dropseed/plain/commit/9febc801f4))
516
+ - Replaced wildcard imports (`import *`) with explicit imports in internal modules for better code clarity ([eff36f3](https://github.com/dropseed/plain/commit/eff36f31e8))
517
+
518
+ ### Upgrade instructions
519
+
520
+ - Optionally (but recommended) add `ClassVar` type annotations to custom QuerySets on your models using `query: ClassVar[models.QuerySet[YourModel]] = models.QuerySet()` for improved type checking and IDE autocomplete
521
+
522
+ ## [0.59.1](https://github.com/dropseed/plain/releases/plain-models@0.59.1) (2025-11-13)
523
+
524
+ ### What's changed
525
+
526
+ - Added documentation for typed field definitions in the README, showing examples of using `plain.models.types` with type annotations ([f95d32d](https://github.com/dropseed/plain/commit/f95d32df5a))
527
+
528
+ ### Upgrade instructions
529
+
530
+ - Optionally (but recommended) move to typed model field definitions by using `name: str = types.CharField(...)` instead of `name = models.CharField(...)`. Types can be imported with `from plain.models import types`.
531
+
532
+ ## [0.59.0](https://github.com/dropseed/plain/releases/plain-models@0.59.0) (2025-11-13)
533
+
534
+ ### What's changed
535
+
536
+ - Added a new `plain.models.types` module with type stub support (.pyi) for improved IDE and type checker experience when defining models ([c8f40fc](https://github.com/dropseed/plain/commit/c8f40fc75a))
537
+ - Added `@dataclass_transform` decorator to `ModelBase` to enable better type checking for model field definitions ([c8f40fc](https://github.com/dropseed/plain/commit/c8f40fc75a))
538
+
539
+ ### Upgrade instructions
540
+
541
+ - No changes required
542
+
543
+ ## [0.58.0](https://github.com/dropseed/plain/releases/plain-models@0.58.0) (2025-11-12)
544
+
545
+ ### What's changed
546
+
547
+ - Internal base classes have been converted to use Python's ABC (Abstract Base Class) module with `@abstractmethod` decorators, improving type checking and making the codebase more maintainable ([b1f40759](https://github.com/dropseed/plain/commit/b1f40759eb), [7146cabc](https://github.com/dropseed/plain/commit/7146cabc42), [74f9a171](https://github.com/dropseed/plain/commit/74f9a1717a), [b647d156](https://github.com/dropseed/plain/commit/b647d156ce), [6f3e35d9](https://github.com/dropseed/plain/commit/6f3e35d9b0), [95620673](https://github.com/dropseed/plain/commit/95620673d9), [7ff5e98c](https://github.com/dropseed/plain/commit/7ff5e98c6f), [78323300](https://github.com/dropseed/plain/commit/78323300df), [df82434d](https://github.com/dropseed/plain/commit/df82434d50), [16350d98](https://github.com/dropseed/plain/commit/16350d98b1), [066eaa4b](https://github.com/dropseed/plain/commit/066eaa4bd7), [60fabefa](https://github.com/dropseed/plain/commit/60fabefa77), [9f822ccc](https://github.com/dropseed/plain/commit/9f822cccc8), [6b31752c](https://github.com/dropseed/plain/commit/6b31752c95))
548
+ - Type annotations have been improved across database backends, query compilers, and migrations for better IDE support ([f4dbcefa](https://github.com/dropseed/plain/commit/f4dbcefa92), [dc182c2e](https://github.com/dropseed/plain/commit/dc182c2e51))
549
+
550
+ ### Upgrade instructions
551
+
552
+ - No changes required
553
+
554
+ ## [0.57.0](https://github.com/dropseed/plain/releases/plain-models@0.57.0) (2025-11-11)
555
+
556
+ ### What's changed
557
+
558
+ - The `plain.models` import namespace has been cleaned up to only include the most commonly used APIs for defining models ([e9edf61](https://github.com/dropseed/plain/commit/e9edf61c6b), [22b798c](https://github.com/dropseed/plain/commit/22b798cf57), [d5a2167](https://github.com/dropseed/plain/commit/d5a2167d14))
559
+ - Field classes are now descriptors themselves, eliminating the need for a separate descriptor class ([93f8bd7](https://github.com/dropseed/plain/commit/93f8bd72e9))
560
+ - Model initialization no longer accepts positional arguments - all field values must be passed as keyword arguments ([685f99a](https://github.com/dropseed/plain/commit/685f99a33a))
561
+ - Attempting to set a primary key during model initialization now raises a clear `ValueError` instead of silently accepting the value ([ecf490c](https://github.com/dropseed/plain/commit/ecf490cb2a))
562
+
563
+ ### Upgrade instructions
564
+
565
+ - Import advanced query features from their specific modules instead of `plain.models`:
566
+ - Aggregates: `from plain.models.aggregates import Avg, Count, Max, Min, Sum`
567
+ - Expressions: `from plain.models.expressions import Case, Exists, Expression, ExpressionWrapper, F, Func, OuterRef, Subquery, Value, When, Window`
568
+ - Query utilities: `from plain.models.query import Prefetch, prefetch_related_objects`
569
+ - Lookups: `from plain.models.lookups import Lookup, Transform`
570
+ - Remove any positional arguments in model instantiation and use keyword arguments instead (e.g., `User("John", "Doe")` becomes `User(first_name="John", last_name="Doe")`)
571
+
572
+ ## [0.56.1](https://github.com/dropseed/plain/releases/plain-models@0.56.1) (2025-11-03)
573
+
574
+ ### What's changed
575
+
576
+ - Fixed preflight checks and README to reference the correct new command names (`plain db shell` and `plain migrations prune`) instead of the old `plain models` commands ([b293750](https://github.com/dropseed/plain/commit/b293750f6f))
577
+
578
+ ### Upgrade instructions
579
+
580
+ - No changes required
581
+
582
+ ## [0.56.0](https://github.com/dropseed/plain/releases/plain-models@0.56.0) (2025-11-03)
583
+
584
+ ### What's changed
585
+
586
+ - The CLI has been reorganized into separate `plain db` and `plain migrations` command groups for better organization ([7910a06](https://github.com/dropseed/plain/commit/7910a06e86132ef1fc1720bd960916ee009e27cf))
587
+ - The `plain models` command group has been removed - use `plain db` and `plain migrations` instead ([7910a06](https://github.com/dropseed/plain/commit/7910a06e86132ef1fc1720bd960916ee009e27cf))
588
+ - The `plain backups` command group has been removed - use `plain db backups` instead ([dd87b76](https://github.com/dropseed/plain/commit/dd87b762babb370751cffdc27be3c6a53c6c98b4))
589
+ - Database backup output has been simplified to show file size and timestamp on a single line ([765d118](https://github.com/dropseed/plain/commit/765d1184c6d0bdb1f91a85bf511d049da74a6276))
590
+
591
+ ### Upgrade instructions
592
+
593
+ - Replace `plain models db-shell` with `plain db shell`
594
+ - Replace `plain models db-wait` with `plain db wait`
595
+ - Replace `plain models list` with `plain db list` (note: this command was moved to the main plain package)
596
+ - Replace `plain models show-migrations` with `plain migrations list`
597
+ - Replace `plain models prune-migrations` with `plain migrations prune`
598
+ - Replace `plain models squash-migrations` with `plain migrations squash`
599
+ - Replace `plain backups` commands with `plain db backups` (e.g., `plain backups list` becomes `plain db backups list`)
600
+ - The shortcuts `plain makemigrations` and `plain migrate` continue to work unchanged
601
+
602
+ ## [0.55.1](https://github.com/dropseed/plain/releases/plain-models@0.55.1) (2025-10-31)
603
+
604
+ ### What's changed
605
+
606
+ - Added `license = "BSD-3-Clause"` to package metadata ([8477355](https://github.com/dropseed/plain/commit/8477355e65b62be6e4618bcc814c912e050dc388))
607
+
608
+ ### Upgrade instructions
609
+
610
+ - No changes required
611
+
612
+ ## [0.55.0](https://github.com/dropseed/plain/releases/plain-models@0.55.0) (2025-10-24)
613
+
614
+ ### What's changed
615
+
616
+ - The plain-models package now uses an explicit `package_label = "plainmodels"` to avoid conflicts with other packages ([d1783dd](https://github.com/dropseed/plain/commit/d1783dd564cb48380e59cb4598722649a7d9574f))
617
+ - Fixed migration loader to correctly check for `plainmodels` package label instead of `models` ([c41d11c](https://github.com/dropseed/plain/commit/c41d11c70d02bab59c6951ef1074b13a392d04a6))
618
+
619
+ ### Upgrade instructions
620
+
621
+ - No changes required
622
+
623
+ ## [0.54.0](https://github.com/dropseed/plain/releases/plain-models@0.54.0) (2025-10-22)
624
+
625
+ ### What's changed
626
+
627
+ - SQLite migrations are now always run separately instead of in atomic batches, fixing issues with foreign key constraint handling ([5082453](https://github.com/dropseed/plain/commit/508245375960f694cfac4e17a6bfbb2301969a5c))
628
+
629
+ ### Upgrade instructions
630
+
631
+ - No changes required
632
+
633
+ ## [0.53.1](https://github.com/dropseed/plain/releases/plain-models@0.53.1) (2025-10-20)
634
+
635
+ ### What's changed
636
+
637
+ - Internal packaging update to use `dependency-groups` standard instead of `tool.uv.dev-dependencies` ([1b43a3a](https://github.com/dropseed/plain/commit/1b43a3a272))
638
+
639
+ ### Upgrade instructions
640
+
641
+ - No changes required
642
+
643
+ ## [0.53.0](https://github.com/dropseed/plain/releases/plain-models@0.53.0) (2025-10-12)
644
+
645
+ ### What's changed
646
+
647
+ - Added new `plain models prune-migrations` command to identify and remove stale migration records from the database ([998aa49](https://github.com/dropseed/plain/commit/998aa49140))
648
+ - The `--prune` option has been removed from `plain migrate` command in favor of the dedicated `prune-migrations` command ([998aa49](https://github.com/dropseed/plain/commit/998aa49140))
649
+ - Added new preflight check `models.prunable_migrations` that warns about stale migration records in the database ([9b43617](https://github.com/dropseed/plain/commit/9b4361765c))
650
+ - The `show-migrations` command no longer displays prunable migrations in its output ([998aa49](https://github.com/dropseed/plain/commit/998aa49140))
651
+
652
+ ### Upgrade instructions
653
+
654
+ - Replace any usage of `plain migrate --prune` with the new `plain models prune-migrations` command
655
+
656
+ ## [0.52.0](https://github.com/dropseed/plain/releases/plain-models@0.52.0) (2025-10-10)
657
+
658
+ ### What's changed
659
+
660
+ - The `plain migrate` command now shows detailed operation descriptions and SQL statements for each migration step, replacing the previous verbosity levels with a cleaner `--quiet` flag ([d6b041bd24](https://github.com/dropseed/plain/commit/d6b041bd24))
661
+ - Migration output format has been improved to display each operation's description and the actual SQL being executed, making it easier to understand what changes are being made to the database ([d6b041bd24](https://github.com/dropseed/plain/commit/d6b041bd24))
662
+ - The `-v/--verbosity` option has been removed from `plain migrate` in favor of the simpler `--quiet` flag for suppressing output ([d6b041bd24](https://github.com/dropseed/plain/commit/d6b041bd24))
663
+
664
+ ### Upgrade instructions
665
+
666
+ - Replace any usage of `-v` or `--verbosity` flags in `plain migrate` commands with `--quiet` if you want to suppress migration output
667
+
668
+ ## [0.51.1](https://github.com/dropseed/plain/releases/plain-models@0.51.1) (2025-10-08)
669
+
670
+ ### What's changed
671
+
672
+ - Fixed a bug in `Subquery` and `Exists` expressions that was using the old `query` attribute name instead of `sql_query` when extracting the SQL query from a QuerySet ([79ca52d](https://github.com/dropseed/plain/commit/79ca52d32e))
673
+
674
+ ### Upgrade instructions
675
+
676
+ - No changes required
677
+
678
+ ## [0.51.0](https://github.com/dropseed/plain/releases/plain-models@0.51.0) (2025-10-07)
679
+
680
+ ### What's changed
681
+
682
+ - Model metadata has been split into two separate descriptors: `model_options` for user-defined configuration and `_model_meta` for internal metadata ([73ba469](https://github.com/dropseed/plain/commit/73ba469ba0), [17a378d](https://github.com/dropseed/plain/commit/17a378dcfb))
683
+ - The `_meta` attribute has been replaced with `model_options` for user-defined options like indexes, constraints, and database settings ([17a378d](https://github.com/dropseed/plain/commit/17a378dcfb))
684
+ - Custom QuerySets are now assigned directly to the `query` class attribute instead of using `Meta.queryset_class` ([2578301](https://github.com/dropseed/plain/commit/2578301819))
685
+ - Added comprehensive type improvements to model metadata and related fields for better IDE support ([3b477a0](https://github.com/dropseed/plain/commit/3b477a0d43))
686
+
687
+ ### Upgrade instructions
688
+
689
+ - Replace `Meta.queryset_class = CustomQuerySet` with `query = CustomQuerySet()` as a class attribute on your models
690
+ - Replace `class Meta:` with `model_options = models.Options(...)` in your models
691
+
692
+ ## [0.50.0](https://github.com/dropseed/plain/releases/plain-models@0.50.0) (2025-10-06)
693
+
694
+ ### What's changed
695
+
696
+ - Added comprehensive type annotations throughout plain-models, improving IDE support and type checking capabilities ([ea1a7df](https://github.com/dropseed/plain/commit/ea1a7df622), [f49ee32](https://github.com/dropseed/plain/commit/f49ee32a90), [369353f](https://github.com/dropseed/plain/commit/369353f9d6), [13b7d16](https://github.com/dropseed/plain/commit/13b7d16f8d), [e23a0ca](https://github.com/dropseed/plain/commit/e23a0cae7c), [02d8551](https://github.com/dropseed/plain/commit/02d85518f0))
697
+ - The `QuerySet` class is now generic and the `model` parameter is now required in the `__init__` method ([719e792](https://github.com/dropseed/plain/commit/719e792c96))
698
+ - Database wrapper classes have been renamed for consistency: `DatabaseWrapper` classes are now named `MySQLDatabaseWrapper`, `PostgreSQLDatabaseWrapper`, and `SQLiteDatabaseWrapper` ([5a39e85](https://github.com/dropseed/plain/commit/5a39e851e5))
699
+ - The plain-models package now has 100% type annotation coverage and is validated in CI to prevent regressions
700
+
701
+ ### Upgrade instructions
702
+
703
+ - No changes required
704
+
705
+ ## [0.49.2](https://github.com/dropseed/plain/releases/plain-models@0.49.2) (2025-10-02)
706
+
707
+ ### What's changed
708
+
709
+ - Updated dependency to use the latest plain package version
710
+
711
+ ### Upgrade instructions
712
+
713
+ - No changes required
714
+
715
+ ## [0.49.1](https://github.com/dropseed/plain/releases/plain-models@0.49.1) (2025-09-29)
716
+
717
+ ### What's changed
718
+
719
+ - Fixed `get_field_display()` method to accept field name as string instead of field object ([1c20405](https://github.com/dropseed/plain/commit/1c20405ac3))
720
+
721
+ ### Upgrade instructions
722
+
723
+ - No changes required
724
+
725
+ ## [0.49.0](https://github.com/dropseed/plain/releases/plain-models@0.49.0) (2025-09-29)
726
+
727
+ ### What's changed
728
+
729
+ - Model exceptions (`FieldDoesNotExist`, `FieldError`, `ObjectDoesNotExist`, `MultipleObjectsReturned`, `EmptyResultSet`, `FullResultSet`) have been moved from `plain.exceptions` to `plain.models.exceptions` ([1c02564](https://github.com/dropseed/plain/commit/1c02564561))
730
+ - The `get_FOO_display()` methods for fields with choices have been replaced with a single `get_field_display(field_name)` method ([e796e71](https://github.com/dropseed/plain/commit/e796e71e02))
731
+ - The `get_next_by_*` and `get_previous_by_*` methods for date fields have been removed ([3a5b8a8](https://github.com/dropseed/plain/commit/3a5b8a89d1))
732
+ - The `id` primary key field is now defined directly on the Model base class instead of being added dynamically via Options ([e164dc7](https://github.com/dropseed/plain/commit/e164dc7982))
733
+ - Model `DoesNotExist` and `MultipleObjectsReturned` exceptions now use descriptors for better performance ([8f54ea3](https://github.com/dropseed/plain/commit/8f54ea3a62))
734
+
735
+ ### Upgrade instructions
736
+
737
+ - Update imports for model exceptions from `plain.exceptions` to `plain.models.exceptions` (e.g., `from plain.exceptions import ObjectDoesNotExist` becomes `from plain.models.exceptions import ObjectDoesNotExist`)
738
+ - Replace any usage of `instance.get_FOO_display()` with `instance.get_field_display("FOO")` where FOO is the field name
739
+ - Remove any usage of `get_next_by_*` and `get_previous_by_*` methods - use QuerySet ordering instead (e.g., `Model.query.filter(date__gt=obj.date).order_by("date").first()`)
740
+
741
+ ## [0.48.0](https://github.com/dropseed/plain/releases/plain-models@0.48.0) (2025-09-26)
742
+
743
+ ### What's changed
744
+
745
+ - Migrations now run in a single transaction by default for databases that support transactional DDL, providing all-or-nothing migration batches for better safety and consistency ([6d0c105](https://github.com/dropseed/plain/commit/6d0c105fa9))
746
+ - Added `--atomic-batch/--no-atomic-batch` options to `plain migrate` to explicitly control whether migrations are run in a single transaction ([6d0c105](https://github.com/dropseed/plain/commit/6d0c105fa9))
747
+
748
+ ### Upgrade instructions
749
+
750
+ - No changes required
751
+
752
+ ## [0.47.0](https://github.com/dropseed/plain/releases/plain-models@0.47.0) (2025-09-25)
753
+
754
+ ### What's changed
755
+
756
+ - The `QuerySet.query` property has been renamed to `QuerySet.sql_query` to better distinguish it from the `Model.query` manager interface ([d250eea](https://github.com/dropseed/plain/commit/d250eeac03))
757
+
758
+ ### Upgrade instructions
759
+
760
+ - If you directly accessed the `QuerySet.query` property in your code (typically for advanced query manipulation or debugging), rename it to `QuerySet.sql_query`
761
+
762
+ ## [0.46.1](https://github.com/dropseed/plain/releases/plain-models@0.46.1) (2025-09-25)
763
+
764
+ ### What's changed
765
+
766
+ - Fixed `prefetch_related` for reverse foreign key relationships by correctly handling related managers in the prefetch query process ([2c04e80](https://github.com/dropseed/plain/commit/2c04e80dcd))
767
+
768
+ ### Upgrade instructions
769
+
770
+ - No changes required
771
+
772
+ ## [0.46.0](https://github.com/dropseed/plain/releases/plain-models@0.46.0) (2025-09-25)
773
+
774
+ ### What's changed
775
+
776
+ - The preflight system has been completely reworked with a new `PreflightResult` class that unifies messages and hints into a single `fix` field, providing clearer and more actionable error messages ([b0b610d](https://github.com/dropseed/plain/commit/b0b610d461), [c7cde12](https://github.com/dropseed/plain/commit/c7cde12149))
777
+ - Preflight check IDs have been renamed to use descriptive names instead of numbers for better clarity (e.g., `models.E003` becomes `models.duplicate_many_to_many_relations`) ([cd96c97](https://github.com/dropseed/plain/commit/cd96c97b25))
778
+ - Removed deprecated field types: `CommaSeparatedIntegerField`, `IPAddressField`, and `NullBooleanField` ([345295dc](https://github.com/dropseed/plain/commit/345295dc8a))
779
+ - Removed `system_check_deprecated_details` and `system_check_removed_details` from fields ([e3a7d2dd](https://github.com/dropseed/plain/commit/e3a7d2dd10))
780
+
781
+ ### Upgrade instructions
782
+
783
+ - Remove any usage of the deprecated field types `CommaSeparatedIntegerField`, `IPAddressField`, and `NullBooleanField` - use `CharField`, `GenericIPAddressField`, and `BooleanField(null=True)` respectively
784
+
785
+ ## [0.45.0](https://github.com/dropseed/plain/releases/plain-models@0.45.0) (2025-09-21)
786
+
787
+ ### What's changed
788
+
789
+ - Added unlimited varchar support to SQLite - CharField fields without a max_length now generate `varchar` columns instead of `varchar()` with no length specified ([c5c0c3a](https://github.com/dropseed/plain/commit/c5c0c3a743))
790
+
791
+ ### Upgrade instructions
792
+
793
+ - No changes required
794
+
795
+ ## [0.44.0](https://github.com/dropseed/plain/releases/plain-models@0.44.0) (2025-09-19)
796
+
797
+ ### What's changed
798
+
799
+ - PostgreSQL backup restoration now drops and recreates the database instead of using `pg_restore --clean`, providing more reliable restoration by terminating active connections and ensuring a completely clean database state ([a8865fe](https://github.com/dropseed/plain/commit/a8865fe5d6))
800
+ - Added `_meta` type annotation to the `Model` class for improved type checking and IDE support ([387b92e](https://github.com/dropseed/plain/commit/387b92e08b))
801
+
802
+ ### Upgrade instructions
803
+
804
+ - No changes required
805
+
806
+ ## [0.43.0](https://github.com/dropseed/plain/releases/plain-models@0.43.0) (2025-09-12)
807
+
808
+ ### What's changed
809
+
810
+ - The `related_name` parameter is now required for ForeignKey and ManyToManyField relationships if you want a reverse accessor. The `"+"` suffix to disable reverse relations has been removed, and automatic `_set` suffixes are no longer generated ([89fa03979f](https://github.com/dropseed/plain/commit/89fa03979f))
811
+ - Refactored related descriptors and managers for better internal organization and type safety ([9f0b03957a](https://github.com/dropseed/plain/commit/9f0b03957a))
812
+ - Added docstrings and return type annotations to model `query` property and related manager methods for improved developer experience ([544d85b60b](https://github.com/dropseed/plain/commit/544d85b60b))
813
+
814
+ ### Upgrade instructions
815
+
816
+ - Remove any `related_name="+"` usage - if you don't want a reverse accessor, simply omit the `related_name` parameter entirely
817
+ - Update any code that relied on automatic `_set` suffixes - these are no longer generated, so you must use explicit `related_name` values
818
+ - Add explicit `related_name` arguments to all ForeignKey and ManyToManyField definitions where you want reverse access (e.g., `models.ForeignKey(User, on_delete=models.CASCADE, related_name="articles")`)
819
+ - Consider removing `related_name` arguments that are not used in practice
820
+
821
+ ## [0.42.0](https://github.com/dropseed/plain/releases/plain-models@0.42.0) (2025-09-12)
822
+
823
+ ### What's changed
824
+
825
+ - The model manager interface has been renamed from `.objects` to `.query` ([037a239](https://github.com/dropseed/plain/commit/037a239ef4))
826
+ - Manager functionality has been merged into QuerySet, simplifying the architecture - custom QuerySets can now be set directly via `Meta.queryset_class` ([bbaee93](https://github.com/dropseed/plain/commit/bbaee93839))
827
+ - The `objects` manager is now set directly on the Model class for better type checking ([fccc5be](https://github.com/dropseed/plain/commit/fccc5be13e))
828
+ - Database backups are now created automatically during migrations when in DEBUG mode ([c8023074](https://github.com/dropseed/plain/commit/c8023074e9))
829
+ - Removed several legacy manager features: `default_related_name`, `base_manager_name`, `creation_counter`, `use_in_migrations`, `auto_created`, and routing hints ([multiple commits](https://github.com/dropseed/plain/compare/plain-models@0.41.1...037a239ef4))
830
+
831
+ ### Upgrade instructions
832
+
833
+ - Replace all usage of `Model.objects` with `Model.query` in your codebase (e.g., `User.objects.filter()` becomes `User.query.filter()`)
834
+ - If you have custom managers, convert them to custom QuerySets and set them using `Meta.queryset_class` instead of assigning to class attributes (if there is more than one custom manager on a class, invoke the new QuerySet class directly or add a shortcut on the Model using `@classmethod`)
835
+ - Remove any usage of the removed manager features: `default_related_name`, `base_manager_name`, manager `creation_counter`, `use_in_migrations`, `auto_created`, and database routing hints
836
+ - Any reverse accessors (typically `<related_model>_set` or defined by `related_name`) will now return a manager class for the additional `add()`, `remove()`, `clear()`, etc. methods and the regular queryset methods will be available via `.query` (e.g., `user.articles.first()` becomes `user.articles.query.first()`)
837
+
838
+ ## [0.41.1](https://github.com/dropseed/plain/releases/plain-models@0.41.1) (2025-09-09)
839
+
840
+ ### What's changed
841
+
842
+ - Improved stack trace filtering in OpenTelemetry spans to exclude internal plain/models frames, making debugging traces cleaner and more focused on user code ([5771dd5](https://github.com/dropseed/plain/commit/5771dd5))
843
+
844
+ ### Upgrade instructions
845
+
846
+ - No changes required
847
+
848
+ ## [0.41.0](https://github.com/dropseed/plain/releases/plain-models@0.41.0) (2025-09-09)
849
+
850
+ ### What's changed
851
+
852
+ - Python 3.13 is now the minimum required version ([d86e307](https://github.com/dropseed/plain/commit/d86e307))
853
+ - Removed the `earliest()`, `latest()`, and `get_latest_by` model meta option - use `order_by().first()` and `order_by().last()` instead ([b6093a8](https://github.com/dropseed/plain/commit/b6093a8))
854
+ - Removed automatic ordering in `first()` and `last()` queryset methods - they now respect the existing queryset ordering without adding default ordering ([adc19a6](https://github.com/dropseed/plain/commit/adc19a6))
855
+ - Added code location attributes to database operation tracing, showing the source file, line number, and function where the query originated ([da36a17](https://github.com/dropseed/plain/commit/da36a17))
856
+
857
+ ### Upgrade instructions
858
+
859
+ - Replace usage of `earliest()`, `latest()`, and model `Meta` `get_latest_by` queryset methods with equivalent `order_by().first()` or `order_by().last()` calls
860
+ - The `first()` and `last()` methods no longer automatically add ordering by `id` - explicitly add `.order_by()` to your querysets or `ordering` to your models `Meta` class if needed
861
+
862
+ ## [0.40.1](https://github.com/dropseed/plain/releases/plain-models@0.40.1) (2025-09-03)
863
+
864
+ ### What's changed
865
+
866
+ - Internal documentation updates for agent commands ([df3edbf0bd](https://github.com/dropseed/plain/commit/df3edbf0bd))
867
+
868
+ ### Upgrade instructions
869
+
870
+ - No changes required
871
+
872
+ ## [0.40.0](https://github.com/dropseed/plain/releases/plain-models@0.40.0) (2025-08-05)
873
+
874
+ ### What's changed
875
+
876
+ - Foreign key fields now accept lazy objects (like `SimpleLazyObject` used for `request.user`) by automatically evaluating them ([eb78dcc76d](https://github.com/dropseed/plain/commit/eb78dcc76d))
877
+ - Added `--no-input` option to `plain migrate` command to skip user prompts ([0bdaf0409e](https://github.com/dropseed/plain/commit/0bdaf0409e))
878
+ - Removed the `plain models optimize-migration` command ([6e4131ab29](https://github.com/dropseed/plain/commit/6e4131ab29))
879
+ - Removed the `--fake-initial` option from `plain migrate` command ([6506a8bfb9](https://github.com/dropseed/plain/commit/6506a8bfb9))
880
+ - Fixed CLI help text to reference `plain` commands instead of `manage.py` ([8071854d61](https://github.com/dropseed/plain/commit/8071854d61))
881
+
882
+ ### Upgrade instructions
883
+
884
+ - Remove any usage of `plain models optimize-migration` command - it is no longer available
885
+ - Remove any usage of `--fake-initial` option from `plain migrate` commands - it is no longer supported
886
+ - It is no longer necessary to do `user=request.user or None`, for example, when setting foreign key fields with a lazy object like `request.user`. These will now be automatically evaluated.
887
+
888
+ ## [0.39.2](https://github.com/dropseed/plain/releases/plain-models@0.39.2) (2025-07-25)
889
+
890
+ ### What's changed
891
+
892
+ - Fixed remaining `to_field_name` attribute usage in `ModelMultipleChoiceField` validation to use `id` directly ([26c80356d3](https://github.com/dropseed/plain/commit/26c80356d3))
893
+
894
+ ### Upgrade instructions
895
+
896
+ - No changes required
897
+
898
+ ## [0.39.1](https://github.com/dropseed/plain/releases/plain-models@0.39.1) (2025-07-22)
899
+
900
+ ### What's changed
901
+
902
+ - Added documentation for sharing fields across models using Python class mixins ([cad3af01d2](https://github.com/dropseed/plain/commit/cad3af01d2))
903
+ - Added note about `PrimaryKeyField()` replacement requirement for migrations ([70ea931660](https://github.com/dropseed/plain/commit/70ea931660))
904
+
905
+ ### Upgrade instructions
906
+
907
+ - No changes required
908
+
909
+ ## [0.39.0](https://github.com/dropseed/plain/releases/plain-models@0.39.0) (2025-07-22)
910
+
911
+ ### What's changed
912
+
913
+ - Models now use a single automatic `id` field as the primary key, replacing the previous `pk` alias and automatic field system ([4b8fa6a](https://github.com/dropseed/plain/commit/4b8fa6a))
914
+ - Removed the `to_field` option for ForeignKey - foreign keys now always reference the primary key of the related model ([7fc3c88](https://github.com/dropseed/plain/commit/7fc3c88))
915
+ - Removed the internal `from_fields` and `to_fields` system used for multi-column foreign keys ([0e9eda3](https://github.com/dropseed/plain/commit/0e9eda3))
916
+ - Removed the `parent_link` parameter on ForeignKey and ForeignObject ([6658647](https://github.com/dropseed/plain/commit/6658647))
917
+ - Removed `InlineForeignKeyField` from forms ([ede6265](https://github.com/dropseed/plain/commit/ede6265))
918
+ - Merged ForeignObject functionality into ForeignKey, simplifying the foreign key implementation ([e6d9aaa](https://github.com/dropseed/plain/commit/e6d9aaa))
919
+ - Cleaned up unused code in ForeignKey and fixed ForeignObjectRel imports ([b656ee6](https://github.com/dropseed/plain/commit/b656ee6))
920
+
921
+ ### Upgrade instructions
922
+
923
+ - Replace any direct references to `pk` with `id` in your models and queries (e.g., `user.pk` becomes `user.id`)
924
+ - Remove any `to_field` arguments from ForeignKey definitions - they are no longer supported
925
+ - Remove any `parent_link=True` arguments from ForeignKey definitions - they are no longer supported
926
+ - Replace any usage of `InlineForeignKeyField` in forms with standard form fields
927
+ - `models.BigAutoField(auto_created=True, primary_key=True)` need to be replaced with `models.PrimaryKeyField()` in migrations
928
+
929
+ ## [0.38.0](https://github.com/dropseed/plain/releases/plain-models@0.38.0) (2025-07-21)
930
+
931
+ ### What's changed
932
+
933
+ - Added `get_or_none()` method to QuerySet which returns a single object matching the given arguments or None if no object is found ([48e07bf](https://github.com/dropseed/plain/commit/48e07bf))
934
+
935
+ ### Upgrade instructions
936
+
937
+ - No changes required
938
+
939
+ ## [0.37.0](https://github.com/dropseed/plain/releases/plain-models@0.37.0) (2025-07-18)
940
+
941
+ ### What's changed
942
+
943
+ - Added OpenTelemetry instrumentation for database operations - all SQL queries now automatically generate OpenTelemetry spans with standardized attributes following semantic conventions ([b0224d0](https://github.com/dropseed/plain/commit/b0224d0))
944
+ - Database operations in tests are now wrapped with tracing suppression to avoid generating telemetry noise during test execution ([b0224d0](https://github.com/dropseed/plain/commit/b0224d0))
945
+
946
+ ### Upgrade instructions
947
+
948
+ - No changes required
949
+
950
+ ## [0.36.0](https://github.com/dropseed/plain/releases/plain-models@0.36.0) (2025-07-18)
951
+
952
+ ### What's changed
953
+
954
+ - Removed the `--merge` option from the `makemigrations` command ([d366663](https://github.com/dropseed/plain/commit/d366663))
955
+ - Improved error handling in the `restore-backup` command using Click's error system ([88f06c5](https://github.com/dropseed/plain/commit/88f06c5))
956
+
957
+ ### Upgrade instructions
958
+
959
+ - No changes required
960
+
961
+ ## [0.35.0](https://github.com/dropseed/plain/releases/plain-models@0.35.0) (2025-07-07)
962
+
963
+ ### What's changed
964
+
965
+ - Added the `plain models list` CLI command which prints a nicely formatted list of all installed models, including their table name, fields, and originating package. You can pass package labels to filter the output or use the `--app-only` flag to only show first-party app models ([1bc40ce](https://github.com/dropseed/plain/commit/1bc40ce)).
966
+ - The MySQL backend no longer enforces a strict `mysqlclient >= 1.4.3` version check and had several unused constraint-handling methods removed, reducing boilerplate and improving compatibility with a wider range of `mysqlclient` versions ([6322400](https://github.com/dropseed/plain/commit/6322400), [67f21f6](https://github.com/dropseed/plain/commit/67f21f6)).
967
+
968
+ ### Upgrade instructions
969
+
970
+ - No changes required
971
+
972
+ ## [0.34.4](https://github.com/dropseed/plain/releases/plain-models@0.34.4) (2025-07-02)
973
+
974
+ ### What's changed
975
+
976
+ - The built-in `on_delete` behaviors (`CASCADE`, `PROTECT`, `RESTRICT`, `SET_NULL`, `SET_DEFAULT`, and the callables returned by `SET(...)`) no longer receive the legacy `using` argument. Their signatures are now `(collector, field, sub_objs)` ([20325a1](https://github.com/dropseed/plain/commit/20325a1)).
977
+ - Removed the unused `interprets_empty_strings_as_nulls` backend feature flag and the related fallback logic ([285378c](https://github.com/dropseed/plain/commit/285378c)).
978
+
979
+ ### Upgrade instructions
980
+
981
+ - No changes required
982
+
983
+ ## [0.34.3](https://github.com/dropseed/plain/releases/plain-models@0.34.3) (2025-06-29)
984
+
985
+ ### What's changed
986
+
987
+ - Simplified log output when creating or destroying test databases during test setup. The messages now display the test database name directly and no longer reference the deprecated "alias" terminology ([a543706](https://github.com/dropseed/plain/commit/a543706)).
988
+
989
+ ### Upgrade instructions
990
+
991
+ - No changes required
992
+
993
+ ## [0.34.2](https://github.com/dropseed/plain/releases/plain-models@0.34.2) (2025-06-27)
994
+
995
+ ### What's changed
996
+
997
+ - Fixed PostgreSQL `_nodb_cursor` fallback that could raise `TypeError: __init__() got an unexpected keyword argument 'alias'` when the maintenance database wasn't available ([3e49683](https://github.com/dropseed/plain/commit/3e49683)).
998
+ - Restored support for the `USING` clause when creating PostgreSQL indexes; custom index types such as `GIN` and `GIST` are now generated correctly again ([9d2b8fe](https://github.com/dropseed/plain/commit/9d2b8fe)).
999
+
1000
+ ### Upgrade instructions
1001
+
1002
+ - No changes required
1003
+
1004
+ ## [0.34.1](https://github.com/dropseed/plain/releases/plain-models@0.34.1) (2025-06-23)
1005
+
1006
+ ### What's changed
1007
+
1008
+ - Fixed Markdown bullet indentation in the 0.34.0 release notes so they render correctly ([2fc81de](https://github.com/dropseed/plain/commit/2fc81de)).
1009
+
1010
+ ### Upgrade instructions
1011
+
1012
+ - No changes required
1013
+
1014
+ ## [0.34.0](https://github.com/dropseed/plain/releases/plain-models@0.34.0) (2025-06-23)
1015
+
1016
+ ### What's changed
1017
+
1018
+ - Switched to a single `DATABASE` setting instead of `DATABASES` and removed `DATABASE_ROUTERS`. A helper still automatically populates `DATABASE` from `DATABASE_URL` just like before ([d346d81](https://github.com/dropseed/plain/commit/d346d81)).
1019
+ - The `plain.models.db` module now exposes a `db_connection` object that lazily represents the active database connection. Previous `connections`, `router`, and `DEFAULT_DB_ALIAS` exports were removed ([d346d81](https://github.com/dropseed/plain/commit/d346d81)).
1020
+
1021
+ ### Upgrade instructions
1022
+
1023
+ - Replace any `DATABASES` definition in your settings with a single `DATABASE` dict (keys are identical to the inner dict you were previously using).
1024
+ - Remove any `DATABASE_ROUTERS` configuration – multiple databases are no longer supported.
1025
+ - Update import sites:
1026
+ - `from plain.models import connections` → `from plain.models import db_connection`
1027
+ - `from plain.models import router` → (no longer needed; remove usage or switch to `db_connection` where appropriate)
1028
+ - `from plain.models.connections import DEFAULT_DB_ALIAS` → (constant removed; default database is implicit)