Sfoglia il codice sorgente

Fixed #30031 -- Added --no-header option to makemigrations/squashmigrations.

Dakota Hawkins 6 anni fa
parent
commit
8d3147e130

+ 7 - 2
django/core/management/commands/makemigrations.py

@@ -48,6 +48,10 @@ class Command(BaseCommand):
             '-n', '--name',
             help="Use this name for migration file(s).",
         )
+        parser.add_argument(
+            '--no-header', action='store_false', dest='include_header',
+            help='Do not add header comments to new migration file(s).',
+        )
         parser.add_argument(
             '--check', action='store_true', dest='check_changes',
             help='Exit with a non-zero status if model changes are missing migrations.',
@@ -63,6 +67,7 @@ class Command(BaseCommand):
         self.migration_name = options['name']
         if self.migration_name and not self.migration_name.isidentifier():
             raise CommandError('The migration name must be a valid Python identifier.')
+        self.include_header = options['include_header']
         check_changes = options['check_changes']
 
         # Make sure the app they asked for exists
@@ -188,7 +193,7 @@ class Command(BaseCommand):
                 self.stdout.write(self.style.MIGRATE_HEADING("Migrations for '%s':" % app_label) + "\n")
             for migration in app_migrations:
                 # Describe the migration
-                writer = MigrationWriter(migration)
+                writer = MigrationWriter(migration, self.include_header)
                 if self.verbosity >= 1:
                     # Display a relative path if it's below the current working
                     # directory, or an absolute path otherwise.
@@ -288,7 +293,7 @@ class Command(BaseCommand):
                     self.migration_name or ("merge_%s" % get_migration_name_timestamp())
                 )
                 new_migration = subclass(migration_name, app_label)
-                writer = MigrationWriter(new_migration)
+                writer = MigrationWriter(new_migration, self.include_header)
 
                 if not self.dry_run:
                     # Write the merge migrations file to the disk

+ 6 - 1
django/core/management/commands/squashmigrations.py

@@ -37,6 +37,10 @@ class Command(BaseCommand):
             '--squashed-name',
             help='Sets the name of the new squashed migration.',
         )
+        parser.add_argument(
+            '--no-header', action='store_false', dest='include_header',
+            help='Do not add a header comment to the new squashed migration.',
+        )
 
     def handle(self, **options):
 
@@ -47,6 +51,7 @@ class Command(BaseCommand):
         migration_name = options['migration_name']
         no_optimize = options['no_optimize']
         squashed_name = options['squashed_name']
+        include_header = options['include_header']
         # Validate app_label.
         try:
             apps.get_app_config(app_label)
@@ -178,7 +183,7 @@ class Command(BaseCommand):
             new_migration.initial = True
 
         # Write out the new migration file
-        writer = MigrationWriter(new_migration)
+        writer = MigrationWriter(new_migration, include_header)
         with open(writer.path, "w", encoding='utf-8') as fh:
             fh.write(writer.as_string())
 

+ 15 - 7
django/db/migrations/writer.py

@@ -132,8 +132,9 @@ class MigrationWriter:
     of the migration file from it.
     """
 
-    def __init__(self, migration):
+    def __init__(self, migration, include_header=True):
         self.migration = migration
+        self.include_header = include_header
         self.needs_manual_porting = False
 
     def as_string(self):
@@ -195,10 +196,13 @@ class MigrationWriter:
         if self.migration.replaces:
             items['replaces_str'] = "\n    replaces = %s\n" % self.serialize(self.migration.replaces)[0]
         # Hinting that goes into comment
-        items.update(
-            version=get_version(),
-            timestamp=now().strftime("%Y-%m-%d %H:%M"),
-        )
+        if self.include_header:
+            items['migration_header'] = MIGRATION_HEADER_TEMPLATE % {
+                'version': get_version(),
+                'timestamp': now().strftime("%Y-%m-%d %H:%M"),
+            }
+        else:
+            items['migration_header'] = ""
 
         if self.migration.initial:
             items['initial_str'] = "\n    initial = True\n"
@@ -279,10 +283,14 @@ class MigrationWriter:
         return serializer_factory(value).serialize()
 
 
-MIGRATION_TEMPLATE = """\
+MIGRATION_HEADER_TEMPLATE = """\
 # Generated by Django %(version)s on %(timestamp)s
 
-%(imports)s
+"""
+
+
+MIGRATION_TEMPLATE = """\
+%(migration_header)s%(imports)s
 
 class Migration(migrations.Migration):
 %(replaces_str)s%(initial_str)s

+ 12 - 0
docs/ref/django-admin.txt

@@ -776,6 +776,12 @@ Enables fixing of migration conflicts.
 Allows naming the generated migration(s) instead of using a generated name. The
 name must be a valid Python :ref:`identifier <python:identifiers>`.
 
+.. django-admin-option:: --no-header
+
+.. versionadded:: 2.2
+
+Generate migration files without Django version and timestamp header.
+
 .. django-admin-option:: --check
 
 Makes ``makemigrations`` exit with a non-zero status when model changes without
@@ -1156,6 +1162,12 @@ Suppresses all user prompts.
 Sets the name of the squashed migration. When omitted, the name is based on the
 first and last migration, with ``_squashed_`` in between.
 
+.. django-admin-option:: --no-header
+
+.. versionadded:: 2.2
+
+Generate squashed migration file without Django version and timestamp header.
+
 ``startapp``
 ------------
 

+ 4 - 0
docs/releases/2.2.txt

@@ -194,6 +194,10 @@ Management Commands
 * On Oracle, :djadmin:`dbshell` is wrapped with ``rlwrap``, if available.
   ``rlwrap`` provides a command history and editing of keyboard input.
 
+* The new :option:`makemigrations --no-header` option avoids writing header
+  comments in generated migration file(s). This option is also available for
+  :djadmin:`squashmigrations`.
+
 Migrations
 ~~~~~~~~~~
 

+ 15 - 10
tests/migrations/test_writer.py

@@ -613,16 +613,21 @@ class WriterTests(SimpleTestCase):
         })
         dt = datetime.datetime(2015, 7, 31, 4, 40, 0, 0, tzinfo=utc)
         with mock.patch('django.db.migrations.writer.now', lambda: dt):
-            writer = MigrationWriter(migration)
-            output = writer.as_string()
-
-        self.assertTrue(
-            output.startswith(
-                "# Generated by Django %(version)s on 2015-07-31 04:40\n" % {
-                    'version': get_version(),
-                }
-            )
-        )
+            for include_header in (True, False):
+                with self.subTest(include_header=include_header):
+                    writer = MigrationWriter(migration, include_header)
+                    output = writer.as_string()
+
+                    self.assertEqual(
+                        include_header,
+                        output.startswith(
+                            "# Generated by Django %s on 2015-07-31 04:40\n\n" % get_version()
+                        )
+                    )
+                    if not include_header:
+                        # Make sure the output starts with something that's not
+                        # a comment or indentation or blank line
+                        self.assertRegex(output.splitlines(keepends=True)[0], r"^[^#\s]+")
 
     def test_models_import_omitted(self):
         """