Changes between Initial Version and Version 1 of Ticket #37431
- Timestamp:
- Oct 15, 2026, 9:07:50 PM (95 minutes ago)
Legend:
- Unmodified
- Added
- Removed
- Modified
-
Ticket #37431
- Property Component Uncategorized → Migrations
- Property Version 6.1 → dev
-
Ticket #37431 – Description
initial v1 1 **Ticket title:**2 3 ```4 MigrationWriter silently serializes Python 3.15 frozendict values as tuples of keys5 ```6 7 **Ticket description:**8 9 ````10 1 On Python 3.15.0, Django's migration serializer treats built-in frozendict instances as generic iterables, preserving only their keys and silently discarding their values. 11 2 … … 14 5 Minimal reproducer: 15 6 16 ```python7 {{{#!python 17 8 from django.db.migrations.writer import MigrationWriter 18 9 19 10 MigrationWriter.serialize(frozendict(answer=42)) 20 ``` 11 }}} 21 12 22 13 Actual result: 23 14 24 ```python15 {{{#!python 25 16 ("('answer',)", set()) 26 ``` 17 }}} 27 18 28 Expected behavior: preserve the mapping's keys and values , rather than serializeit as a tuple of keys.19 Expected behavior: preserve the mapping's keys and values instead of serializing it as a tuple of keys. 29 20 30 This affects field defaults . For example:21 This affects field defaults: 31 22 32 ```python23 {{{#!python 33 24 models.JSONField(default=frozendict(answer=42)) 34 ``` 25 }}} 35 26 36 is written into a migration as:27 The generated migration contains: 37 28 38 ```python29 {{{#!python 39 30 models.JSONField(default=('answer',)) 40 ``` 31 }}} 41 32 42 I reproduced the database consequence on SQLite: after executing a generated AddField migration against a table containing an existing row, the new JSON field contains ["answer"] instead of {"answer": 42}.33 The database consequence was reproduced on SQLite: executing a generated AddField migration against an existing row stores {{{["answer"]}}} instead of {{{{"answer": 42}}}}. 43 34 44 35 The serializer registry handles dict explicitly, but frozendict is not a dict subclass and falls through to IterableSerializer. 45 36 46 A proposed patch adds a dedicated frozendict serializer, regression tests in the existingmigration writer and operation suites, and documentation noting that generated migrations containing frozendict require Python 3.15+.37 A proposed patch adds a dedicated serializer, regression tests in the migration writer and operation suites, and documentation noting that generated migrations containing frozendict require Python 3.15+. 47 38 48 39 Validation: 49 - Python 3.15: all75 writer/regression tests passed.50 -Python 3.15: 181 migration operation tests ran successfully, with 2 skipped.51 -Python 3.14: 75 writer/regression tests ran successfully, with 3 skipped.52 -Formatting and whitespace checks passed.53 -The full Django test suite has not been run.40 * Python 3.15: 75 writer/regression tests passed. 41 * Python 3.15: 181 migration operation tests ran successfully, with 2 skipped. 42 * Python 3.14: 75 writer/regression tests ran successfully, with 3 skipped. 43 * Formatting and whitespace checks passed. 44 * The full Django test suite has not been run. 54 45 55 46 AI disclosure: OpenAI Codex (GPT-6) assisted with investigation, implementation, regression tests, documentation, and commit preparation. 56 ````