Opened 2 years ago

Closed 2 years ago

#33323 closed Bug (invalid)

On custom migrations, import of model classes with app.get_model('appname', 'ModelName') ignores overwritten models.Model methods

Reported by: Andreas Scheucher Owned by: nobody
Component: Migrations Version: 3.2
Severity: Normal Keywords:
Cc: Triage Stage: Unreviewed
Has patch: no Needs documentation: no
Needs tests: no Patch needs improvement: no
Easy pickings: no UI/UX: no

Description

Given migration:

from django.db import migrations
from designs.models import Design


def fix_wrong_design_sheet_data(apps, schema_editor):
    # do not import Model classes like in the line below. Overwritten methods are not executed.
    # Design = apps.get_model('designs', 'Design')

    for design in Design.objects.all().iterator():
        if design. uuid in ['79f53b09-7069-480e-a8d9-d88ec0aad8d0', 'e26230cb-a9c7-4ee1-9523-0f2f70cf5c98']:
            design.language = 'nt'
        design.save(
            force_insert=False,
            force_update=True,
            using='default',
            update_fields=['id_slug', 'language'])


class Migration(migrations.Migration):

    dependencies = [
        ('designs', '0027_related_design_cols_to_many_many_remove_old_col'),
    ]

    operations = [
        migrations.RunPython(fix_wrong_design_sheet_data),
    ]

Model class:

class Design(models_mixins.PkUUID, models_mixins.TrackingMixin):
    niche = models.CharField(blank=False, null=True, max_length=50)
    id = models.CharField(blank=False, null=True, max_length=4)
    variant = models.CharField(blank=False, null=True, max_length=1)
    language = models.CharField(max_length=2, default=None)

    # this field is filled by the .save() method
    id_slug = models.CharField(max_length=61, blank=False, null=True)
    ...

    def save(self, force_insert: bool, force_update: bool, using: Optional[str], update_fields: Optional[Iterable[str]]) -> None:
        print('new save')
        int_id = int(self.id)
        nslid = f'{self.niche}-{int_id:04}-{self.variant}--{self.language}'
        self.id_slug = nslid
        return super().save(force_insert=force_insert, force_update=force_update, using=using, update_fields=update_fields)

When imported with from designs.models import Design, then the Design.save method is called.

BUG:
Importing the Design model class with Design = apps.get_model('designs', 'Design') the Design.save method is not called.

Change History (1)

comment:1 by Tim Graham, 2 years ago

Resolution: invalid
Status: newclosed

As documented:

Because it’s impossible to serialize arbitrary Python code, these historical models will not have any custom methods that you have defined. They will, however, have the same fields, relationships, managers (limited to those with use_in_migrations = True) and Meta options (also versioned, so they may be different from your current ones).

This means that you will NOT have custom save() methods called on objects when you access them in migrations, and you will NOT have any custom constructors or instance methods.

Note: See TracTickets for help on using tickets.
Back to Top