Loading django/db/migrations/autodetector.py +3 −0 Original line number Diff line number Diff line Loading @@ -11,6 +11,7 @@ from django.db.migrations.migration import Migration from django.db.migrations.operations.models import AlterModelOptions from django.db.migrations.optimizer import MigrationOptimizer from django.db.migrations.questioner import MigrationQuestioner from django.db.migrations.utils import COMPILED_REGEX_TYPE, RegexObject from django.utils import six from .topological_sort import stable_topological_sort Loading Loading @@ -62,6 +63,8 @@ class MigrationAutodetector(object): key: self.deep_deconstruct(value) for key, value in obj.items() } elif isinstance(obj, COMPILED_REGEX_TYPE): return RegexObject(obj) elif isinstance(obj, type): # If this is a type that implements 'deconstruct' as an instance method, # avoid treating this as being deconstructible itself - see #22951 Loading django/db/migrations/utils.py 0 → 100644 +12 −0 Original line number Diff line number Diff line import re COMPILED_REGEX_TYPE = type(re.compile('')) class RegexObject(object): def __init__(self, obj): self.pattern = obj.pattern self.flags = obj.flags def __eq__(self, other): return self.pattern == other.pattern and self.flags == other.flags django/db/migrations/writer.py +2 −3 Original line number Diff line number Diff line Loading @@ -14,6 +14,7 @@ from django.apps import apps from django.db import migrations, models from django.db.migrations.loader import MigrationLoader from django.db.migrations.operations.base import Operation from django.db.migrations.utils import COMPILED_REGEX_TYPE, RegexObject from django.utils import datetime_safe, six from django.utils._os import upath from django.utils.encoding import force_text Loading @@ -23,8 +24,6 @@ from django.utils.module_loading import module_dir from django.utils.timezone import utc from django.utils.version import get_docs_version COMPILED_REGEX_TYPE = type(re.compile('')) class SettingsReference(str): """ Loading Loading @@ -506,7 +505,7 @@ class MigrationWriter(object): format = "(%s)" if len(strings) != 1 else "(%s,)" return format % (", ".join(strings)), imports # Compiled regex elif isinstance(value, COMPILED_REGEX_TYPE): elif isinstance(value, (COMPILED_REGEX_TYPE, RegexObject)): imports = {"import re"} regex_pattern, pattern_imports = cls.serialize(value.pattern) regex_flags, flag_imports = cls.serialize(value.flags) Loading tests/migrations/test_autodetector.py +43 −0 Original line number Diff line number Diff line # -*- coding: utf-8 -*- import re from django.conf import settings from django.contrib.auth.models import AbstractBaseUser from django.core.validators import RegexValidator, validate_slug from django.db import connection, models from django.db.migrations.autodetector import MigrationAutodetector from django.db.migrations.graph import MigrationGraph Loading Loading @@ -997,6 +1000,46 @@ class AutodetectorTests(TestCase): self.assertOperationAttributes(changes, "testapp", 0, 0, old_name="Author", new_name="NewAuthor") self.assertOperationAttributes(changes, "testapp", 0, 1, name="newauthor", table="author_three") def test_identical_regex_doesnt_alter(self): from_state = ModelState( "testapp", "model", [("id", models.AutoField(primary_key=True, validators=[ RegexValidator( re.compile('^[-a-zA-Z0-9_]+\\Z'), "Enter a valid 'slug' consisting of letters, numbers, underscores or hyphens.", 'invalid' ) ]))] ) to_state = ModelState( "testapp", "model", [("id", models.AutoField(primary_key=True, validators=[validate_slug]))] ) before = self.make_project_state([from_state]) after = self.make_project_state([to_state]) autodetector = MigrationAutodetector(before, after) changes = autodetector._detect_changes() # Right number/type of migrations? self.assertNumberMigrations(changes, "testapp", 0) def test_different_regex_does_alter(self): from_state = ModelState( "testapp", "model", [("id", models.AutoField(primary_key=True, validators=[ RegexValidator( re.compile('^[a-z]+\\Z', 32), "Enter a valid 'slug' consisting of letters, numbers, underscores or hyphens.", 'invalid' ) ]))] ) to_state = ModelState( "testapp", "model", [("id", models.AutoField(primary_key=True, validators=[validate_slug]))] ) before = self.make_project_state([from_state]) after = self.make_project_state([to_state]) autodetector = MigrationAutodetector(before, after) changes = autodetector._detect_changes() self.assertNumberMigrations(changes, "testapp", 1) self.assertOperationTypes(changes, "testapp", 0, ["AlterField"]) def test_empty_foo_together(self): """ #23452 - Empty unique/index_together shouldn't generate a migration. Loading Loading
django/db/migrations/autodetector.py +3 −0 Original line number Diff line number Diff line Loading @@ -11,6 +11,7 @@ from django.db.migrations.migration import Migration from django.db.migrations.operations.models import AlterModelOptions from django.db.migrations.optimizer import MigrationOptimizer from django.db.migrations.questioner import MigrationQuestioner from django.db.migrations.utils import COMPILED_REGEX_TYPE, RegexObject from django.utils import six from .topological_sort import stable_topological_sort Loading Loading @@ -62,6 +63,8 @@ class MigrationAutodetector(object): key: self.deep_deconstruct(value) for key, value in obj.items() } elif isinstance(obj, COMPILED_REGEX_TYPE): return RegexObject(obj) elif isinstance(obj, type): # If this is a type that implements 'deconstruct' as an instance method, # avoid treating this as being deconstructible itself - see #22951 Loading
django/db/migrations/utils.py 0 → 100644 +12 −0 Original line number Diff line number Diff line import re COMPILED_REGEX_TYPE = type(re.compile('')) class RegexObject(object): def __init__(self, obj): self.pattern = obj.pattern self.flags = obj.flags def __eq__(self, other): return self.pattern == other.pattern and self.flags == other.flags
django/db/migrations/writer.py +2 −3 Original line number Diff line number Diff line Loading @@ -14,6 +14,7 @@ from django.apps import apps from django.db import migrations, models from django.db.migrations.loader import MigrationLoader from django.db.migrations.operations.base import Operation from django.db.migrations.utils import COMPILED_REGEX_TYPE, RegexObject from django.utils import datetime_safe, six from django.utils._os import upath from django.utils.encoding import force_text Loading @@ -23,8 +24,6 @@ from django.utils.module_loading import module_dir from django.utils.timezone import utc from django.utils.version import get_docs_version COMPILED_REGEX_TYPE = type(re.compile('')) class SettingsReference(str): """ Loading Loading @@ -506,7 +505,7 @@ class MigrationWriter(object): format = "(%s)" if len(strings) != 1 else "(%s,)" return format % (", ".join(strings)), imports # Compiled regex elif isinstance(value, COMPILED_REGEX_TYPE): elif isinstance(value, (COMPILED_REGEX_TYPE, RegexObject)): imports = {"import re"} regex_pattern, pattern_imports = cls.serialize(value.pattern) regex_flags, flag_imports = cls.serialize(value.flags) Loading
tests/migrations/test_autodetector.py +43 −0 Original line number Diff line number Diff line # -*- coding: utf-8 -*- import re from django.conf import settings from django.contrib.auth.models import AbstractBaseUser from django.core.validators import RegexValidator, validate_slug from django.db import connection, models from django.db.migrations.autodetector import MigrationAutodetector from django.db.migrations.graph import MigrationGraph Loading Loading @@ -997,6 +1000,46 @@ class AutodetectorTests(TestCase): self.assertOperationAttributes(changes, "testapp", 0, 0, old_name="Author", new_name="NewAuthor") self.assertOperationAttributes(changes, "testapp", 0, 1, name="newauthor", table="author_three") def test_identical_regex_doesnt_alter(self): from_state = ModelState( "testapp", "model", [("id", models.AutoField(primary_key=True, validators=[ RegexValidator( re.compile('^[-a-zA-Z0-9_]+\\Z'), "Enter a valid 'slug' consisting of letters, numbers, underscores or hyphens.", 'invalid' ) ]))] ) to_state = ModelState( "testapp", "model", [("id", models.AutoField(primary_key=True, validators=[validate_slug]))] ) before = self.make_project_state([from_state]) after = self.make_project_state([to_state]) autodetector = MigrationAutodetector(before, after) changes = autodetector._detect_changes() # Right number/type of migrations? self.assertNumberMigrations(changes, "testapp", 0) def test_different_regex_does_alter(self): from_state = ModelState( "testapp", "model", [("id", models.AutoField(primary_key=True, validators=[ RegexValidator( re.compile('^[a-z]+\\Z', 32), "Enter a valid 'slug' consisting of letters, numbers, underscores or hyphens.", 'invalid' ) ]))] ) to_state = ModelState( "testapp", "model", [("id", models.AutoField(primary_key=True, validators=[validate_slug]))] ) before = self.make_project_state([from_state]) after = self.make_project_state([to_state]) autodetector = MigrationAutodetector(before, after) changes = autodetector._detect_changes() self.assertNumberMigrations(changes, "testapp", 1) self.assertOperationTypes(changes, "testapp", 0, ["AlterField"]) def test_empty_foo_together(self): """ #23452 - Empty unique/index_together shouldn't generate a migration. Loading