Commit 391bb09b authored by Ulrich Petri's avatar Ulrich Petri Committed by Tim Graham
Browse files

Refs #22608 -- Optimized migration optimizer and migrate by caching calls to str.lower()

parent ee86e590
Loading
Loading
Loading
Loading
+19 −19
Original line number Diff line number Diff line
@@ -168,7 +168,7 @@ class MigrationAutodetector(object):
                        and not old_field.rel.through._meta.auto_created):
                    through_key = (
                        old_field.rel.through._meta.app_label,
                        old_field.rel.through._meta.object_name.lower(),
                        old_field.rel.through._meta.model_name,
                    )
                    self.through_users[through_key] = (app_label, old_model_name, field_name)

@@ -322,47 +322,47 @@ class MigrationAutodetector(object):
        if dependency[2] is None and dependency[3] is True:
            return (
                isinstance(operation, operations.CreateModel) and
                operation.name.lower() == dependency[1].lower()
                operation.name_lower == dependency[1].lower()
            )
        # Created field
        elif dependency[2] is not None and dependency[3] is True:
            return (
                (
                    isinstance(operation, operations.CreateModel) and
                    operation.name.lower() == dependency[1].lower() and
                    operation.name_lower == dependency[1].lower() and
                    any(dependency[2] == x for x, y in operation.fields)
                ) or
                (
                    isinstance(operation, operations.AddField) and
                    operation.model_name.lower() == dependency[1].lower() and
                    operation.name.lower() == dependency[2].lower()
                    operation.model_name_lower == dependency[1].lower() and
                    operation.name_lower == dependency[2].lower()
                )
            )
        # Removed field
        elif dependency[2] is not None and dependency[3] is False:
            return (
                isinstance(operation, operations.RemoveField) and
                operation.model_name.lower() == dependency[1].lower() and
                operation.name.lower() == dependency[2].lower()
                operation.model_name_lower == dependency[1].lower() and
                operation.name_lower == dependency[2].lower()
            )
        # Removed model
        elif dependency[2] is None and dependency[3] is False:
            return (
                isinstance(operation, operations.DeleteModel) and
                operation.name.lower() == dependency[1].lower()
                operation.name_lower == dependency[1].lower()
            )
        # Field being altered
        elif dependency[2] is not None and dependency[3] == "alter":
            return (
                isinstance(operation, operations.AlterField) and
                operation.model_name.lower() == dependency[1].lower() and
                operation.name.lower() == dependency[2].lower()
                operation.model_name_lower == dependency[1].lower() and
                operation.name_lower == dependency[2].lower()
            )
        # order_with_respect_to being unset for a field
        elif dependency[2] is not None and dependency[3] == "order_wrt_unset":
            return (
                isinstance(operation, operations.AlterOrderWithRespectTo) and
                operation.name.lower() == dependency[1].lower() and
                operation.name_lower == dependency[1].lower() and
                (operation.order_with_respect_to or "").lower() != dependency[2].lower()
            )
        # Field is removed and part of an index/unique_together
@@ -370,7 +370,7 @@ class MigrationAutodetector(object):
            return (
                isinstance(operation, (operations.AlterUniqueTogether,
                                       operations.AlterIndexTogether)) and
                operation.name.lower() == dependency[1].lower()
                operation.name_lower == dependency[1].lower()
            )
        # Unknown dependency. Raise an error.
        else:
@@ -696,7 +696,7 @@ class MigrationAutodetector(object):
            for name, field in sorted(related_fields.items()):
                dependencies.append((app_label, model_name, name, False))
            # We're referenced in another field's through=
            through_user = self.through_users.get((app_label, model_state.name.lower()), None)
            through_user = self.through_users.get((app_label, model_state.name_lower), None)
            if through_user:
                dependencies.append((through_user[0], through_user[1], through_user[2], False))
            # Finally, make the operation, deduping any dependencies
@@ -842,7 +842,7 @@ class MigrationAutodetector(object):
            if hasattr(new_field, "rel") and getattr(new_field.rel, "to", None):
                rename_key = (
                    new_field.rel.to._meta.app_label,
                    new_field.rel.to._meta.object_name.lower(),
                    new_field.rel.to._meta.model_name,
                )
                if rename_key in self.renamed_models:
                    new_field.rel.to = old_field.rel.to
@@ -1094,16 +1094,16 @@ class MigrationAutodetector(object):
        """
        if len(ops) == 1:
            if isinstance(ops[0], operations.CreateModel):
                return ops[0].name.lower()
                return ops[0].name_lower
            elif isinstance(ops[0], operations.DeleteModel):
                return "delete_%s" % ops[0].name.lower()
                return "delete_%s" % ops[0].name_lower
            elif isinstance(ops[0], operations.AddField):
                return "%s_%s" % (ops[0].model_name.lower(), ops[0].name.lower())
                return "%s_%s" % (ops[0].model_name_lower, ops[0].name_lower)
            elif isinstance(ops[0], operations.RemoveField):
                return "remove_%s_%s" % (ops[0].model_name.lower(), ops[0].name.lower())
                return "remove_%s_%s" % (ops[0].model_name_lower, ops[0].name_lower)
        elif len(ops) > 1:
            if all(isinstance(o, operations.CreateModel) for o in ops):
                return "_".join(sorted(o.name.lower() for o in ops))
                return "_".join(sorted(o.name_lower for o in ops))
        return "auto_%s" % datetime.datetime.now().strftime("%Y%m%d_%H%M")

    @classmethod
+60 −21
Original line number Diff line number Diff line
@@ -2,6 +2,7 @@ from __future__ import unicode_literals

from django.db.models.fields import NOT_PROVIDED
from django.utils import six
from django.utils.functional import cached_property
from .base import Operation


@@ -16,6 +17,14 @@ class AddField(Operation):
        self.field = field
        self.preserve_default = preserve_default

    @cached_property
    def name_lower(self):
        return self.name.lower()

    @cached_property
    def model_name_lower(self):
        return self.model_name.lower()

    def deconstruct(self):
        kwargs = {
            'model_name': self.model_name,
@@ -37,8 +46,8 @@ class AddField(Operation):
            field.default = NOT_PROVIDED
        else:
            field = self.field
        state.models[app_label, self.model_name.lower()].fields.append((self.name, field))
        state.reload_model(app_label, self.model_name)
        state.models[app_label, self.model_name_lower].fields.append((self.name, field))
        state.reload_model(app_label, self.model_name_lower)

    def database_forwards(self, app_label, schema_editor, from_state, to_state):
        to_model = to_state.apps.get_model(app_label, self.model_name)
@@ -63,10 +72,10 @@ class AddField(Operation):
        return "Add field %s to %s" % (self.name, self.model_name)

    def references_model(self, name, app_label=None):
        return name.lower() == self.model_name.lower()
        return name.lower() == self.model_name_lower

    def references_field(self, model_name, name, app_label=None):
        return self.references_model(model_name) and name.lower() == self.name.lower()
        return self.references_model(model_name) and name.lower() == self.name_lower


class RemoveField(Operation):
@@ -78,6 +87,14 @@ class RemoveField(Operation):
        self.model_name = model_name
        self.name = name

    @cached_property
    def name_lower(self):
        return self.name.lower()

    @cached_property
    def model_name_lower(self):
        return self.model_name.lower()

    def deconstruct(self):
        kwargs = {
            'model_name': self.model_name,
@@ -91,11 +108,11 @@ class RemoveField(Operation):

    def state_forwards(self, app_label, state):
        new_fields = []
        for name, instance in state.models[app_label, self.model_name.lower()].fields:
        for name, instance in state.models[app_label, self.model_name_lower].fields:
            if name != self.name:
                new_fields.append((name, instance))
        state.models[app_label, self.model_name.lower()].fields = new_fields
        state.reload_model(app_label, self.model_name)
        state.models[app_label, self.model_name_lower].fields = new_fields
        state.reload_model(app_label, self.model_name_lower)

    def database_forwards(self, app_label, schema_editor, from_state, to_state):
        from_model = from_state.apps.get_model(app_label, self.model_name)
@@ -112,10 +129,10 @@ class RemoveField(Operation):
        return "Remove field %s from %s" % (self.name, self.model_name)

    def references_model(self, name, app_label=None):
        return name.lower() == self.model_name.lower()
        return name.lower() == self.model_name_lower

    def references_field(self, model_name, name, app_label=None):
        return self.references_model(model_name) and name.lower() == self.name.lower()
        return self.references_model(model_name) and name.lower() == self.name_lower


class AlterField(Operation):
@@ -129,6 +146,14 @@ class AlterField(Operation):
        self.field = field
        self.preserve_default = preserve_default

    @cached_property
    def name_lower(self):
        return self.name.lower()

    @cached_property
    def model_name_lower(self):
        return self.model_name.lower()

    def deconstruct(self):
        kwargs = {
            'model_name': self.model_name,
@@ -149,10 +174,12 @@ class AlterField(Operation):
            field.default = NOT_PROVIDED
        else:
            field = self.field
        state.models[app_label, self.model_name.lower()].fields = [
            (n, field if n == self.name else f) for n, f in state.models[app_label, self.model_name.lower()].fields
        state.models[app_label, self.model_name_lower].fields = [
            (n, field if n == self.name else f)
            for n, f in
            state.models[app_label, self.model_name_lower].fields
        ]
        state.reload_model(app_label, self.model_name)
        state.reload_model(app_label, self.model_name_lower)

    def database_forwards(self, app_label, schema_editor, from_state, to_state):
        to_model = to_state.apps.get_model(app_label, self.model_name)
@@ -181,10 +208,10 @@ class AlterField(Operation):
        return "Alter field %s on %s" % (self.name, self.model_name)

    def references_model(self, name, app_label=None):
        return name.lower() == self.model_name.lower()
        return name.lower() == self.model_name_lower

    def references_field(self, model_name, name, app_label=None):
        return self.references_model(model_name) and name.lower() == self.name.lower()
        return self.references_model(model_name) and name.lower() == self.name_lower


class RenameField(Operation):
@@ -197,6 +224,18 @@ class RenameField(Operation):
        self.old_name = old_name
        self.new_name = new_name

    @cached_property
    def old_name_lower(self):
        return self.old_name.lower()

    @cached_property
    def new_name_lower(self):
        return self.new_name.lower()

    @cached_property
    def model_name_lower(self):
        return self.model_name.lower()

    def deconstruct(self):
        kwargs = {
            'model_name': self.model_name,
@@ -211,19 +250,19 @@ class RenameField(Operation):

    def state_forwards(self, app_label, state):
        # Rename the field
        state.models[app_label, self.model_name.lower()].fields = [
        state.models[app_label, self.model_name_lower].fields = [
            (self.new_name if n == self.old_name else n, f)
            for n, f in state.models[app_label, self.model_name.lower()].fields
            for n, f in state.models[app_label, self.model_name_lower].fields
        ]
        # Fix index/unique_together to refer to the new field
        options = state.models[app_label, self.model_name.lower()].options
        options = state.models[app_label, self.model_name_lower].options
        for option in ('index_together', 'unique_together'):
            if option in options:
                options[option] = [
                    [self.new_name if n == self.old_name else n for n in together]
                    for together in options[option]
                ]
        state.reload_model(app_label, self.model_name)
        state.reload_model(app_label, self.model_name_lower)

    def database_forwards(self, app_label, schema_editor, from_state, to_state):
        to_model = to_state.apps.get_model(app_label, self.model_name)
@@ -249,10 +288,10 @@ class RenameField(Operation):
        return "Rename field %s on %s to %s" % (self.old_name, self.model_name, self.new_name)

    def references_model(self, name, app_label=None):
        return name.lower() == self.model_name.lower()
        return name.lower() == self.model_name_lower

    def references_field(self, model_name, name, app_label=None):
        return self.references_model(model_name) and (
            name.lower() == self.old_name.lower() or
            name.lower() == self.new_name.lower()
            name.lower() == self.old_name_lower or
            name.lower() == self.new_name_lower
        )
+74 −29
Original line number Diff line number Diff line
@@ -5,6 +5,7 @@ from django.db.models.options import normalize_together
from django.db.migrations.state import ModelState
from django.db.migrations.operations.base import Operation
from django.utils import six
from django.utils.functional import cached_property


class CreateModel(Operation):
@@ -21,6 +22,10 @@ class CreateModel(Operation):
        self.bases = bases or (models.Model,)
        self.managers = managers or []

    @cached_property
    def name_lower(self):
        return self.name.lower()

    def deconstruct(self):
        kwargs = {
            'name': self.name,
@@ -87,6 +92,10 @@ class DeleteModel(Operation):
    def __init__(self, name):
        self.name = name

    @cached_property
    def name_lower(self):
        return self.name.lower()

    def deconstruct(self):
        kwargs = {
            'name': self.name,
@@ -98,7 +107,7 @@ class DeleteModel(Operation):
        )

    def state_forwards(self, app_label, state):
        state.remove_model(app_label, self.name)
        state.remove_model(app_label, self.name_lower)

    def database_forwards(self, app_label, schema_editor, from_state, to_state):
        model = from_state.apps.get_model(app_label, self.name)
@@ -111,7 +120,7 @@ class DeleteModel(Operation):
            schema_editor.create_model(model)

    def references_model(self, name, app_label=None):
        return name.lower() == self.name.lower()
        return name.lower() == self.name_lower

    def describe(self):
        return "Delete model %s" % (self.name, )
@@ -126,6 +135,14 @@ class RenameModel(Operation):
        self.old_name = old_name
        self.new_name = new_name

    @cached_property
    def old_name_lower(self):
        return self.old_name.lower()

    @cached_property
    def new_name_lower(self):
        return self.new_name.lower()

    def deconstruct(self):
        kwargs = {
            'old_name': self.old_name,
@@ -147,18 +164,18 @@ class RenameModel(Operation):
            if f.auto_created and not f.concrete and not (f.hidden or f.many_to_many)
        )
        # Rename the model
        state.models[app_label, self.new_name.lower()] = state.models[app_label, self.old_name.lower()]
        state.models[app_label, self.new_name.lower()].name = self.new_name
        state.remove_model(app_label, self.old_name)
        state.models[app_label, self.new_name_lower] = state.models[app_label, self.old_name_lower]
        state.models[app_label, self.new_name_lower].name = self.new_name
        state.remove_model(app_label, self.old_name_lower)
        # Repoint the FKs and M2Ms pointing to us
        for related_object in all_related_objects:
            # Use the new related key for self referential related objects.
            if related_object.related_model == model:
                related_key = (app_label, self.new_name.lower())
                related_key = (app_label, self.new_name_lower)
            else:
                related_key = (
                    related_object.related_model._meta.app_label,
                    related_object.related_model._meta.object_name.lower(),
                    related_object.related_model._meta.model_name,
                )
            new_fields = []
            for name, field in state.models[related_key].fields:
@@ -168,7 +185,7 @@ class RenameModel(Operation):
                new_fields.append((name, field))
            state.models[related_key].fields = new_fields
            state.reload_model(*related_key)
        state.reload_model(app_label, self.new_name)
        state.reload_model(app_label, self.new_name_lower)

    def database_forwards(self, app_label, schema_editor, from_state, to_state):
        new_model = to_state.apps.get_model(app_label, self.new_name)
@@ -184,12 +201,12 @@ class RenameModel(Operation):
            for related_object in old_model._meta.related_objects:
                if related_object.related_model == old_model:
                    model = new_model
                    related_key = (app_label, self.new_name.lower())
                    related_key = (app_label, self.new_name_lower)
                else:
                    model = related_object.related_model
                    related_key = (
                        related_object.related_model._meta.app_label,
                        related_object.related_model._meta.object_name.lower(),
                        related_object.related_model._meta.model_name,
                    )
                to_field = to_state.apps.get_model(
                    *related_key
@@ -201,14 +218,18 @@ class RenameModel(Operation):
                )

    def database_backwards(self, app_label, schema_editor, from_state, to_state):
        self.new_name_lower, self.old_name_lower = self.old_name_lower, self.new_name_lower
        self.new_name, self.old_name = self.old_name, self.new_name

        self.database_forwards(app_label, schema_editor, from_state, to_state)

        self.new_name_lower, self.old_name_lower = self.old_name_lower, self.new_name_lower
        self.new_name, self.old_name = self.old_name, self.new_name

    def references_model(self, name, app_label=None):
        return (
            name.lower() == self.old_name.lower() or
            name.lower() == self.new_name.lower()
            name.lower() == self.old_name_lower or
            name.lower() == self.new_name_lower
        )

    def describe(self):
@@ -224,6 +245,10 @@ class AlterModelTable(Operation):
        self.name = name
        self.table = table

    @cached_property
    def name_lower(self):
        return self.name.lower()

    def deconstruct(self):
        kwargs = {
            'name': self.name,
@@ -236,8 +261,8 @@ class AlterModelTable(Operation):
        )

    def state_forwards(self, app_label, state):
        state.models[app_label, self.name.lower()].options["db_table"] = self.table
        state.reload_model(app_label, self.name)
        state.models[app_label, self.name_lower].options["db_table"] = self.table
        state.reload_model(app_label, self.name_lower)

    def database_forwards(self, app_label, schema_editor, from_state, to_state):
        new_model = to_state.apps.get_model(app_label, self.name)
@@ -261,7 +286,7 @@ class AlterModelTable(Operation):
        return self.database_forwards(app_label, schema_editor, from_state, to_state)

    def references_model(self, name, app_label=None):
        return name.lower() == self.name.lower()
        return name.lower() == self.name_lower

    def describe(self):
        return "Rename table for %s to %s" % (self.name, self.table)
@@ -279,6 +304,10 @@ class AlterUniqueTogether(Operation):
        unique_together = normalize_together(unique_together)
        self.unique_together = set(tuple(cons) for cons in unique_together)

    @cached_property
    def name_lower(self):
        return self.name.lower()

    def deconstruct(self):
        kwargs = {
            'name': self.name,
@@ -291,9 +320,9 @@ class AlterUniqueTogether(Operation):
        )

    def state_forwards(self, app_label, state):
        model_state = state.models[app_label, self.name.lower()]
        model_state = state.models[app_label, self.name_lower]
        model_state.options[self.option_name] = self.unique_together
        state.reload_model(app_label, self.name)
        state.reload_model(app_label, self.name_lower)

    def database_forwards(self, app_label, schema_editor, from_state, to_state):
        new_model = to_state.apps.get_model(app_label, self.name)
@@ -309,7 +338,7 @@ class AlterUniqueTogether(Operation):
        return self.database_forwards(app_label, schema_editor, from_state, to_state)

    def references_model(self, name, app_label=None):
        return name.lower() == self.name.lower()
        return name.lower() == self.name_lower

    def describe(self):
        return "Alter %s for %s (%s constraint(s))" % (self.option_name, self.name, len(self.unique_together or ''))
@@ -327,6 +356,10 @@ class AlterIndexTogether(Operation):
        index_together = normalize_together(index_together)
        self.index_together = set(tuple(cons) for cons in index_together)

    @cached_property
    def name_lower(self):
        return self.name.lower()

    def deconstruct(self):
        kwargs = {
            'name': self.name,
@@ -339,9 +372,9 @@ class AlterIndexTogether(Operation):
        )

    def state_forwards(self, app_label, state):
        model_state = state.models[app_label, self.name.lower()]
        model_state = state.models[app_label, self.name_lower]
        model_state.options[self.option_name] = self.index_together
        state.reload_model(app_label, self.name)
        state.reload_model(app_label, self.name_lower)

    def database_forwards(self, app_label, schema_editor, from_state, to_state):
        new_model = to_state.apps.get_model(app_label, self.name)
@@ -357,7 +390,7 @@ class AlterIndexTogether(Operation):
        return self.database_forwards(app_label, schema_editor, from_state, to_state)

    def references_model(self, name, app_label=None):
        return name.lower() == self.name.lower()
        return name.lower() == self.name_lower

    def describe(self):
        return "Alter %s for %s (%s constraint(s))" % (self.option_name, self.name, len(self.index_together or ''))
@@ -372,6 +405,10 @@ class AlterOrderWithRespectTo(Operation):
        self.name = name
        self.order_with_respect_to = order_with_respect_to

    @cached_property
    def name_lower(self):
        return self.name.lower()

    def deconstruct(self):
        kwargs = {
            'name': self.name,
@@ -384,9 +421,9 @@ class AlterOrderWithRespectTo(Operation):
        )

    def state_forwards(self, app_label, state):
        model_state = state.models[app_label, self.name.lower()]
        model_state = state.models[app_label, self.name_lower]
        model_state.options['order_with_respect_to'] = self.order_with_respect_to
        state.reload_model(app_label, self.name)
        state.reload_model(app_label, self.name_lower)

    def database_forwards(self, app_label, schema_editor, from_state, to_state):
        to_model = to_state.apps.get_model(app_label, self.name)
@@ -410,7 +447,7 @@ class AlterOrderWithRespectTo(Operation):
        self.database_forwards(app_label, schema_editor, from_state, to_state)

    def references_model(self, name, app_label=None):
        return name.lower() == self.name.lower()
        return name.lower() == self.name_lower

    def describe(self):
        return "Set order_with_respect_to on %s to %s" % (self.name, self.order_with_respect_to)
@@ -439,6 +476,10 @@ class AlterModelOptions(Operation):
        self.name = name
        self.options = options

    @cached_property
    def name_lower(self):
        return self.name.lower()

    def deconstruct(self):
        kwargs = {
            'name': self.name,
@@ -451,13 +492,13 @@ class AlterModelOptions(Operation):
        )

    def state_forwards(self, app_label, state):
        model_state = state.models[app_label, self.name.lower()]
        model_state = state.models[app_label, self.name_lower]
        model_state.options = dict(model_state.options)
        model_state.options.update(self.options)
        for key in self.ALTER_OPTION_KEYS:
            if key not in self.options and key in model_state.options:
                del model_state.options[key]
        state.reload_model(app_label, self.name)
        state.reload_model(app_label, self.name_lower)

    def database_forwards(self, app_label, schema_editor, from_state, to_state):
        pass
@@ -466,7 +507,7 @@ class AlterModelOptions(Operation):
        pass

    def references_model(self, name, app_label=None):
        return name.lower() == self.name.lower()
        return name.lower() == self.name_lower

    def describe(self):
        return "Change Meta options on %s" % (self.name, )
@@ -483,6 +524,10 @@ class AlterModelManagers(Operation):
        self.name = name
        self.managers = managers

    @cached_property
    def name_lower(self):
        return self.name.lower()

    def deconstruct(self):
        return (
            self.__class__.__name__,
@@ -491,7 +536,7 @@ class AlterModelManagers(Operation):
        )

    def state_forwards(self, app_label, state):
        model_state = state.models[app_label, self.name.lower()]
        model_state = state.models[app_label, self.name_lower]
        model_state.managers = list(self.managers)

    def database_forwards(self, app_label, schema_editor, from_state, to_state):
@@ -501,7 +546,7 @@ class AlterModelManagers(Operation):
        pass

    def references_model(self, name, app_label=None):
        return name.lower() == self.name.lower()
        return name.lower() == self.name_lower

    def describe(self):
        return "Change managers on %s" % (self.name, )
+21 −18

File changed.

Preview size limit exceeded, changes collapsed.

+6 −4

File changed.

Preview size limit exceeded, changes collapsed.