Opened 71 minutes ago
Last modified 49 minutes ago
#37304 assigned Bug
Incorrect migration generated when a JSONField have a local scope defined Decoder
| Reported by: | takuyozora | Owned by: | Yassin Bahri |
|---|---|---|---|
| Component: | Migrations | Version: | 6.1 |
| Severity: | Normal | Keywords: | JSONField migration |
| Cc: | takuyozora | Triage Stage: | Accepted |
| Has patch: | yes | Needs documentation: | no |
| Needs tests: | no | Patch needs improvement: | no |
| Easy pickings: | no | UI/UX: | no |
Description
Hi,
I have a JSONField on one of my model with a custom JSONDecoder :
class UnitAbstract(models.Model): class Meta: abstract = True # ... base_stats = models.JSONField(default=rpg.stats.RPGBaseStats( pv={'maximum': 100}, mana={'maximum': 0} ).toJSON(), encoder=RPGJSONEncoder, decoder=rpg.stats.RPGBaseStats.getJSONDecoder()) class Unit(UnitAbstract): pass
But the migration file generated by makemigration is incorrect (because of this part : decoder=terrarpg.rpg.mixins.DeconstructibleMixin.getJSONDecoder.<locals>.RPGJSONDecoder) :
class Migration(migrations.Migration): dependencies = [ ('terrarpg', '0035_unitgroup_formation_rank_alter_unit_base_stats_and_more'), ] operations = [ migrations.AlterField( model_name='unit', name='base_stats', field=models.JSONField(decoder=terrarpg.rpg.mixins.DeconstructibleMixin.getJSONDecoder.<locals>.RPGJSONDecoder, default=[ #... ], encoder=terrarpg.rpg.parsers.RPGJSONEncoder), ),
I assume the <locals> that produce the syntax error is here because my decoder is a dynamically generated class as you can see here :
class DeconstructibleMixin(abc.ABC): # ... @classmethod def getJSONDecoder(cls): class RPGJSONDecoder(json.JSONDecoder): def decode(self, *args, **kwargs) -> cls: data = json.JSONDecoder.decode(self, *args, **kwargs) if isinstance(data, list) and len(data) >= 1: return cls.fromJSON(data) return data return RPGJSONDecoder
If I do not apply the migration everything is working properly (because the field have been created before without the custom decoder).
So maybe either Django should not produce a migration file when only the decoder part change on a JSONField because it's not link to the DB schema, or it should handle properly the fact that the decoder is a local scope defined class.
I hope that the bug issue is filled properly and that my English is compressible enough.
Change History (1)
comment:1 by , 49 minutes ago
| Has patch: | set |
|---|---|
| Owner: | set to |
| Status: | new → assigned |
| Triage Stage: | Unreviewed → Accepted |
I reproduced this issue and prepared a patch with regression tests.
The issue is that migration serialization currently allows local classes to be serialized by TypeSerializer, producing invalid migration code containing
<locals>. FunctionTypeSerializer already rejects local functions, so the patch applies the same kind of early failure to local classes.The regression tests cover both direct local class serialization and the reported JSONField(decoder=...) case.
Tested with:
Branch: https://github.com/yassinbahri/django/tree/ticket-37304