Opened 2 years ago
Closed 2 years ago
#34716 closed Bug (fixed)
Class methods from nested classes cannot be used as Field.default.
| Reported by: | Nicolò Intrieri | Owned by: | Nicolò Intrieri |
|---|---|---|---|
| Component: | Migrations | Version: | 4.2 |
| Severity: | Normal | Keywords: | |
| Cc: | Triage Stage: | Accepted | |
| Has patch: | yes | Needs documentation: | no |
| Needs tests: | no | Patch needs improvement: | no |
| Easy pickings: | no | UI/UX: | no |
Description (last modified by )
Given the following model:
class Profile(models.Model): class Capability(models.TextChoices): BASIC = ("BASIC", "Basic") PROFESSIONAL = ("PROFESSIONAL", "Professional") @classmethod def default(cls) -> list[str]: return [cls.BASIC] capabilities = ArrayField( models.CharField(choices=Capability.choices, max_length=30, blank=True), null=True, default=Capability.default )
The resulting migration contained the following:
# ... migrations.AddField( model_name='profile', name='capabilities', field=django.contrib.postgres.fields.ArrayField(base_field=models.CharField(blank=True, choices=[('BASIC', 'Basic'), ('PROFESSIONAL', 'Professional')], max_length=30), default=appname.models.Capability.default, null=True, size=None), ), # ...
As you can see, migrations.AddField is passed as argument "default" a wrong value "appname.models.Capability.default", which leads to an error when trying to migrate. The right value should be "appname.models.Profile.Capability.default".
Change History (9)
follow-up: 5 comment:1 by , 2 years ago
| Description: | modified (diff) |
|---|---|
| Summary: | Using subclass method as a callable for a field's default value results in wrong reference in the corresponding migration → Class methods from subclasses cannot be used as Field.default. |
| Triage Stage: | Unreviewed → Accepted |
follow-up: 4 comment:2 by , 2 years ago
Also to nitpick the terminology: Capability is a nested class, not a subclass. (fyi for anyone preparing tests/commit message)
comment:3 by , 2 years ago
| Summary: | Class methods from subclasses cannot be used as Field.default. → Class methods from nested classes cannot be used as Field.default. |
|---|
comment:4 by , 2 years ago
Replying to David Sanders:
Also to nitpick the terminology:
Capabilityis a nested class, not a subclass. (fyi for anyone preparing tests/commit message)
You're right, that was inaccurate. Thanks for having fixed the title
follow-up: 7 comment:5 by , 2 years ago
Replying to Mariusz Felisiak:
Thanks for the report. It seems that
FunctionTypeSerializershould use__qualname__instead of__name__:
django/db/migrations/serializer.py
diff --git a/django/db/migrations/serializer.py b/django/db/migrations/serializer.py index d88cda6e20..06657ebaab 100644
a b class FunctionTypeSerializer(BaseSerializer): 168 168 ): 169 169 klass = self.value.__self__ 170 170 module = klass.__module__ 171 return "%s.%s.%s" % (module, klass.__ name__, self.value.__name__), {171 return "%s.%s.%s" % (module, klass.__qualname__, self.value.__name__), { 172 172 "import %s" % module 173 173 } 174 174 # Further error checking Would you like to prepare a patch? (regression test is required)
I would be very happy to prepare a patch, i will do my best to write a test that's coherent with the current suite
comment:6 by , 2 years ago
| Owner: | changed from to |
|---|---|
| Status: | new → assigned |
comment:7 by , 2 years ago
I would be very happy to prepare a patch, i will do my best to write a test that's coherent with the current suite
You can check tests in tests.migrations.test_writer.WriterTests, e.g. test_serialize_nested_class().
Thanks for the report. It seems that
FunctionTypeSerializershould use__qualname__instead of__name__:django/db/migrations/serializer.py
name__, self.value.__name__), {Would you like to prepare a patch? (regression test is required)