[PATCH 1/4] migrations: don't go to the db for 0041_python3 migration

Stephen Finucane stephen at that.guru
Fri Aug 13 02:40:46 AEST 2021


On Sat, 2021-07-17 at 03:19 +1000, Daniel Axtens wrote:
> When we moved to Python 3, makemigrations wanted to change a bunch of
> things, see commit 4ad87ed72aec ("migrations: Add the Python 3 patch").
> 
> The change is, as observed then, just to make django happy; it's not
> supposed to change the database at all.
> 
> So make the migration change the state as seen by Django only.
> This makes the migration ~instant, even for a huge database.
> 
> Signed-off-by: Daniel Axtens <dja at axtens.net>

Oh, this is snazzy. This turns out to actually be a really small change. With
the patch applied:

   $ git diff HEAD~ -w
   diff --git patchwork/migrations/0041_python3.py patchwork/migrations/0041_python3.py
   index 201c6460..25d5de4b 100644
   --- patchwork/migrations/0041_python3.py
   +++ patchwork/migrations/0041_python3.py
   @@ -15,6 +15,8 @@ class Migration(migrations.Migration):
        ]
    
        operations = [
   +        migrations.SeparateDatabaseAndState(
   +            state_operations=[
                    migrations.AlterField(
                        model_name='check',
                        name='context',
   @@ -330,4 +332,6 @@ class Migration(migrations.Migration):
                            help_text='Show click-to-copy patch IDs in the list view',
                        ),
                    ),
   +            ],
   +        ),
        ]

I modified this to include a bug and applied it to master. I'll backport it to
stable/3.0 shortly. Also,

Reviewed-by: Stephen Finucane <stephen at that.guru>

Thanks!
Stephen

> ---
>  patchwork/migrations/0041_python3.py | 632 ++++++++++++++-------------
>  1 file changed, 318 insertions(+), 314 deletions(-)
> 
> diff --git a/patchwork/migrations/0041_python3.py b/patchwork/migrations/0041_python3.py
> index 201c6460fb02..25d5de4b66e3 100644
> --- a/patchwork/migrations/0041_python3.py
> +++ b/patchwork/migrations/0041_python3.py
> @@ -15,319 +15,323 @@ class Migration(migrations.Migration):
>      ]
>  
>      operations = [
> -        migrations.AlterField(
> -            model_name='check',
> -            name='context',
> -            field=models.SlugField(
> -                default='default',
> -                help_text='A label to discern check from checks of other '
> -                'testing systems.',
> -                max_length=255,
> -            ),
> -        ),
> -        migrations.AlterField(
> -            model_name='check',
> -            name='description',
> -            field=models.TextField(
> -                blank=True,
> -                help_text='A brief description of the check.',
> -                null=True,
> -            ),
> -        ),
> -        migrations.AlterField(
> -            model_name='check',
> -            name='state',
> -            field=models.SmallIntegerField(
> -                choices=[
> -                    (0, 'pending'),
> -                    (1, 'success'),
> -                    (2, 'warning'),
> -                    (3, 'fail'),
> -                ],
> -                default=0,
> -                help_text='The state of the check.',
> -            ),
> -        ),
> -        migrations.AlterField(
> -            model_name='check',
> -            name='target_url',
> -            field=models.URLField(
> -                blank=True,
> -                help_text='The target URL to associate with this check. This '
> -                'should be specific to the patch.',
> -                null=True,
> -            ),
> -        ),
> -        migrations.AlterField(
> -            model_name='comment',
> -            name='submission',
> -            field=models.ForeignKey(
> -                on_delete=django.db.models.deletion.CASCADE,
> -                related_name='comments',
> -                related_query_name='comment',
> -                to='patchwork.Submission',
> -            ),
> -        ),
> -        migrations.AlterField(
> -            model_name='delegationrule',
> -            name='path',
> -            field=models.CharField(
> -                help_text='An fnmatch-style pattern to match filenames '
> -                'against.',
> -                max_length=255,
> -            ),
> -        ),
> -        migrations.AlterField(
> -            model_name='delegationrule',
> -            name='priority',
> -            field=models.IntegerField(
> -                default=0,
> -                help_text='The priority of the rule. Rules with a higher '
> -                'priority will override rules with lower priorities',
> -            ),
> -        ),
> -        migrations.AlterField(
> -            model_name='delegationrule',
> -            name='user',
> -            field=models.ForeignKey(
> -                help_text='A user to delegate the patch to.',
> -                on_delete=django.db.models.deletion.CASCADE,
> -                to=settings.AUTH_USER_MODEL,
> -            ),
> -        ),
> -        migrations.AlterField(
> -            model_name='emailconfirmation',
> -            name='type',
> -            field=models.CharField(
> -                choices=[
> -                    ('userperson', 'User-Person association'),
> -                    ('registration', 'Registration'),
> -                    ('optout', 'Email opt-out'),
> -                ],
> -                max_length=20,
> -            ),
> -        ),
> -        migrations.AlterField(
> -            model_name='event',
> -            name='actor',
> -            field=models.ForeignKey(
> -                blank=True,
> -                help_text='The user that caused/created this event.',
> -                null=True,
> -                on_delete=django.db.models.deletion.SET_NULL,
> -                related_name='+',
> -                to=settings.AUTH_USER_MODEL,
> -            ),
> -        ),
> -        migrations.AlterField(
> -            model_name='event',
> -            name='category',
> -            field=models.CharField(
> -                choices=[
> -                    ('cover-created', 'Cover Letter Created'),
> -                    ('patch-created', 'Patch Created'),
> -                    ('patch-completed', 'Patch Completed'),
> -                    ('patch-state-changed', 'Patch State Changed'),
> -                    ('patch-delegated', 'Patch Delegate Changed'),
> -                    ('patch-relation-changed', 'Patch Relation Changed'),
> -                    ('check-created', 'Check Created'),
> -                    ('series-created', 'Series Created'),
> -                    ('series-completed', 'Series Completed'),
> -                ],
> -                db_index=True,
> -                help_text='The category of the event.',
> -                max_length=25,
> -            ),
> -        ),
> -        migrations.AlterField(
> -            model_name='event',
> -            name='cover',
> -            field=models.ForeignKey(
> -                blank=True,
> -                help_text='The cover letter that this event was created for.',
> -                null=True,
> -                on_delete=django.db.models.deletion.CASCADE,
> -                related_name='+',
> -                to='patchwork.CoverLetter',
> -            ),
> -        ),
> -        migrations.AlterField(
> -            model_name='event',
> -            name='date',
> -            field=models.DateTimeField(
> -                default=datetime.datetime.utcnow,
> -                help_text='The time this event was created.',
> -            ),
> -        ),
> -        migrations.AlterField(
> -            model_name='event',
> -            name='patch',
> -            field=models.ForeignKey(
> -                blank=True,
> -                help_text='The patch that this event was created for.',
> -                null=True,
> -                on_delete=django.db.models.deletion.CASCADE,
> -                related_name='+',
> -                to='patchwork.Patch',
> -            ),
> -        ),
> -        migrations.AlterField(
> -            model_name='event',
> -            name='project',
> -            field=models.ForeignKey(
> -                help_text='The project that the events belongs to.',
> -                on_delete=django.db.models.deletion.CASCADE,
> -                related_name='+',
> -                to='patchwork.Project',
> -            ),
> -        ),
> -        migrations.AlterField(
> -            model_name='event',
> -            name='series',
> -            field=models.ForeignKey(
> -                blank=True,
> -                help_text='The series that this event was created for.',
> -                null=True,
> -                on_delete=django.db.models.deletion.CASCADE,
> -                related_name='+',
> -                to='patchwork.Series',
> -            ),
> -        ),
> -        migrations.AlterField(
> -            model_name='patch',
> -            name='number',
> -            field=models.PositiveSmallIntegerField(
> -                default=None,
> -                help_text='The number assigned to this patch in the series',
> -                null=True,
> -            ),
> -        ),
> -        migrations.AlterField(
> -            model_name='project',
> -            name='commit_url_format',
> -            field=models.CharField(
> -                blank=True,
> -                help_text='URL format for a particular commit. {} will be '
> -                'replaced by the commit SHA.',
> -                max_length=2000,
> -            ),
> -        ),
> -        migrations.AlterField(
> -            model_name='project',
> -            name='list_archive_url_format',
> -            field=models.CharField(
> -                blank=True,
> -                help_text="URL format for the list archive's Message-ID "
> -                "redirector. {} will be replaced by the Message-ID.",
> -                max_length=2000,
> -            ),
> -        ),
> -        migrations.AlterField(
> -            model_name='project',
> -            name='subject_match',
> -            field=models.CharField(
> -                blank=True,
> -                default='',
> -                help_text='Regex to match the subject against if only part '
> -                'of emails sent to the list belongs to this project. Will be '
> -                'used with IGNORECASE and MULTILINE flags. If rules for more '
> -                'projects match the first one returned from DB is chosen; '
> -                'empty field serves as a default for every email which has no '
> -                'other match.',
> -                max_length=64,
> -                validators=[patchwork.models.validate_regex_compiles],
> -            ),
> -        ),
> -        migrations.AlterField(
> -            model_name='series',
> -            name='name',
> -            field=models.CharField(
> -                blank=True,
> -                help_text='An optional name to associate with the series, '
> -                'e.g. "John\'s PCI series".',
> -                max_length=255,
> -                null=True,
> -            ),
> -        ),
> -        migrations.AlterField(
> -            model_name='series',
> -            name='total',
> -            field=models.IntegerField(
> -                help_text='Number of patches in series as indicated by the '
> -                'subject prefix(es)'
> -            ),
> -        ),
> -        migrations.AlterField(
> -            model_name='series',
> -            name='version',
> -            field=models.IntegerField(
> -                default=1,
> -                help_text='Version of series as indicated by the subject '
> -                'prefix(es)',
> -            ),
> -        ),
> -        migrations.AlterField(
> -            model_name='seriesreference',
> -            name='series',
> -            field=models.ForeignKey(
> -                on_delete=django.db.models.deletion.CASCADE,
> -                related_name='references',
> -                related_query_name='reference',
> -                to='patchwork.Series',
> -            ),
> -        ),
> -        migrations.AlterField(
> -            model_name='tag',
> -            name='abbrev',
> -            field=models.CharField(
> -                help_text='Short (one-or-two letter) abbreviation for the '
> -                'tag, used in table column headers',
> -                max_length=2,
> -                unique=True,
> -            ),
> -        ),
> -        migrations.AlterField(
> -            model_name='tag',
> -            name='pattern',
> -            field=models.CharField(
> -                help_text='A simple regex to match the tag in the content of '
> -                'a message. Will be used with MULTILINE and IGNORECASE flags. '
> -                'eg. ^Acked-by:',
> -                max_length=50,
> -                validators=[patchwork.models.validate_regex_compiles],
> -            ),
> -        ),
> -        migrations.AlterField(
> -            model_name='tag',
> -            name='show_column',
> -            field=models.BooleanField(
> -                default=True,
> -                help_text="Show a column displaying this tag's count in the "
> -                "patch list view",
> -            ),
> -        ),
> -        migrations.AlterField(
> -            model_name='userprofile',
> -            name='items_per_page',
> -            field=models.PositiveIntegerField(
> -                default=100, help_text='Number of items to display per page'
> -            ),
> -        ),
> -        migrations.AlterField(
> -            model_name='userprofile',
> -            name='send_email',
> -            field=models.BooleanField(
> -                default=False,
> -                help_text='Selecting this option allows patchwork to send '
> -                'email on your behalf',
> -            ),
> -        ),
> -        migrations.AlterField(
> -            model_name='userprofile',
> -            name='show_ids',
> -            field=models.BooleanField(
> -                default=False,
> -                help_text='Show click-to-copy patch IDs in the list view',
> -            ),
> +        migrations.SeparateDatabaseAndState(
> +            state_operations=[
> +                migrations.AlterField(
> +                    model_name='check',
> +                    name='context',
> +                    field=models.SlugField(
> +                        default='default',
> +                        help_text='A label to discern check from checks of other '
> +                                  'testing systems.',
> +                        max_length=255,
> +                    ),
> +                ),
> +                migrations.AlterField(
> +                    model_name='check',
> +                    name='description',
> +                    field=models.TextField(
> +                        blank=True,
> +                        help_text='A brief description of the check.',
> +                        null=True,
> +                    ),
> +                ),
> +                migrations.AlterField(
> +                    model_name='check',
> +                    name='state',
> +                    field=models.SmallIntegerField(
> +                        choices=[
> +                            (0, 'pending'),
> +                            (1, 'success'),
> +                            (2, 'warning'),
> +                            (3, 'fail'),
> +                        ],
> +                        default=0,
> +                        help_text='The state of the check.',
> +                    ),
> +                ),
> +                migrations.AlterField(
> +                    model_name='check',
> +                    name='target_url',
> +                    field=models.URLField(
> +                        blank=True,
> +                        help_text='The target URL to associate with this check. This '
> +                                  'should be specific to the patch.',
> +                        null=True,
> +                    ),
> +                ),
> +                migrations.AlterField(
> +                    model_name='comment',
> +                    name='submission',
> +                    field=models.ForeignKey(
> +                        on_delete=django.db.models.deletion.CASCADE,
> +                        related_name='comments',
> +                        related_query_name='comment',
> +                        to='patchwork.Submission',
> +                    ),
> +                ),
> +                migrations.AlterField(
> +                    model_name='delegationrule',
> +                    name='path',
> +                    field=models.CharField(
> +                        help_text='An fnmatch-style pattern to match filenames '
> +                                  'against.',
> +                        max_length=255,
> +                    ),
> +                ),
> +                migrations.AlterField(
> +                    model_name='delegationrule',
> +                    name='priority',
> +                    field=models.IntegerField(
> +                        default=0,
> +                        help_text='The priority of the rule. Rules with a higher '
> +                                  'priority will override rules with lower priorities',
> +                    ),
> +                ),
> +                migrations.AlterField(
> +                    model_name='delegationrule',
> +                    name='user',
> +                    field=models.ForeignKey(
> +                        help_text='A user to delegate the patch to.',
> +                        on_delete=django.db.models.deletion.CASCADE,
> +                        to=settings.AUTH_USER_MODEL,
> +                    ),
> +                ),
> +                migrations.AlterField(
> +                    model_name='emailconfirmation',
> +                    name='type',
> +                    field=models.CharField(
> +                        choices=[
> +                            ('userperson', 'User-Person association'),
> +                            ('registration', 'Registration'),
> +                            ('optout', 'Email opt-out'),
> +                        ],
> +                        max_length=20,
> +                    ),
> +                ),
> +                migrations.AlterField(
> +                    model_name='event',
> +                    name='actor',
> +                    field=models.ForeignKey(
> +                        blank=True,
> +                        help_text='The user that caused/created this event.',
> +                        null=True,
> +                        on_delete=django.db.models.deletion.SET_NULL,
> +                        related_name='+',
> +                        to=settings.AUTH_USER_MODEL,
> +                    ),
> +                ),
> +                migrations.AlterField(
> +                    model_name='event',
> +                    name='category',
> +                    field=models.CharField(
> +                        choices=[
> +                            ('cover-created', 'Cover Letter Created'),
> +                            ('patch-created', 'Patch Created'),
> +                            ('patch-completed', 'Patch Completed'),
> +                            ('patch-state-changed', 'Patch State Changed'),
> +                            ('patch-delegated', 'Patch Delegate Changed'),
> +                            ('patch-relation-changed', 'Patch Relation Changed'),
> +                            ('check-created', 'Check Created'),
> +                            ('series-created', 'Series Created'),
> +                            ('series-completed', 'Series Completed'),
> +                        ],
> +                        db_index=True,
> +                        help_text='The category of the event.',
> +                        max_length=25,
> +                    ),
> +                ),
> +                migrations.AlterField(
> +                    model_name='event',
> +                    name='cover',
> +                    field=models.ForeignKey(
> +                        blank=True,
> +                        help_text='The cover letter that this event was created for.',
> +                        null=True,
> +                        on_delete=django.db.models.deletion.CASCADE,
> +                        related_name='+',
> +                        to='patchwork.CoverLetter',
> +                    ),
> +                ),
> +                migrations.AlterField(
> +                    model_name='event',
> +                    name='date',
> +                    field=models.DateTimeField(
> +                        default=datetime.datetime.utcnow,
> +                        help_text='The time this event was created.',
> +                    ),
> +                ),
> +                migrations.AlterField(
> +                    model_name='event',
> +                    name='patch',
> +                    field=models.ForeignKey(
> +                        blank=True,
> +                        help_text='The patch that this event was created for.',
> +                        null=True,
> +                        on_delete=django.db.models.deletion.CASCADE,
> +                        related_name='+',
> +                        to='patchwork.Patch',
> +                    ),
> +                ),
> +                migrations.AlterField(
> +                    model_name='event',
> +                    name='project',
> +                    field=models.ForeignKey(
> +                        help_text='The project that the events belongs to.',
> +                        on_delete=django.db.models.deletion.CASCADE,
> +                        related_name='+',
> +                        to='patchwork.Project',
> +                    ),
> +                ),
> +                migrations.AlterField(
> +                    model_name='event',
> +                    name='series',
> +                    field=models.ForeignKey(
> +                        blank=True,
> +                        help_text='The series that this event was created for.',
> +                        null=True,
> +                        on_delete=django.db.models.deletion.CASCADE,
> +                        related_name='+',
> +                        to='patchwork.Series',
> +                    ),
> +                ),
> +                migrations.AlterField(
> +                    model_name='patch',
> +                    name='number',
> +                    field=models.PositiveSmallIntegerField(
> +                        default=None,
> +                        help_text='The number assigned to this patch in the series',
> +                        null=True,
> +                    ),
> +                ),
> +                migrations.AlterField(
> +                    model_name='project',
> +                    name='commit_url_format',
> +                    field=models.CharField(
> +                        blank=True,
> +                        help_text='URL format for a particular commit. {} will be '
> +                                  'replaced by the commit SHA.',
> +                        max_length=2000,
> +                    ),
> +                ),
> +                migrations.AlterField(
> +                    model_name='project',
> +                    name='list_archive_url_format',
> +                    field=models.CharField(
> +                        blank=True,
> +                        help_text="URL format for the list archive's Message-ID "
> +                                  "redirector. {} will be replaced by the Message-ID.",
> +                        max_length=2000,
> +                    ),
> +                ),
> +                migrations.AlterField(
> +                    model_name='project',
> +                    name='subject_match',
> +                    field=models.CharField(
> +                        blank=True,
> +                        default='',
> +                        help_text='Regex to match the subject against if only part '
> +                                  'of emails sent to the list belongs to this project. Will be '
> +                                  'used with IGNORECASE and MULTILINE flags. If rules for more '
> +                                  'projects match the first one returned from DB is chosen; '
> +                                  'empty field serves as a default for every email which has no '
> +                                  'other match.',
> +                        max_length=64,
> +                        validators=[patchwork.models.validate_regex_compiles],
> +                    ),
> +                ),
> +                migrations.AlterField(
> +                    model_name='series',
> +                    name='name',
> +                    field=models.CharField(
> +                        blank=True,
> +                        help_text='An optional name to associate with the series, '
> +                                  'e.g. "John\'s PCI series".',
> +                        max_length=255,
> +                        null=True,
> +                    ),
> +                ),
> +                migrations.AlterField(
> +                    model_name='series',
> +                    name='total',
> +                    field=models.IntegerField(
> +                        help_text='Number of patches in series as indicated by the '
> +                                  'subject prefix(es)'
> +                    ),
> +                ),
> +                migrations.AlterField(
> +                    model_name='series',
> +                    name='version',
> +                    field=models.IntegerField(
> +                        default=1,
> +                        help_text='Version of series as indicated by the subject '
> +                                  'prefix(es)',
> +                    ),
> +                ),
> +                migrations.AlterField(
> +                    model_name='seriesreference',
> +                    name='series',
> +                    field=models.ForeignKey(
> +                        on_delete=django.db.models.deletion.CASCADE,
> +                        related_name='references',
> +                        related_query_name='reference',
> +                        to='patchwork.Series',
> +                    ),
> +                ),
> +                migrations.AlterField(
> +                    model_name='tag',
> +                    name='abbrev',
> +                    field=models.CharField(
> +                        help_text='Short (one-or-two letter) abbreviation for the '
> +                                  'tag, used in table column headers',
> +                        max_length=2,
> +                        unique=True,
> +                    ),
> +                ),
> +                migrations.AlterField(
> +                    model_name='tag',
> +                    name='pattern',
> +                    field=models.CharField(
> +                        help_text='A simple regex to match the tag in the content of '
> +                                  'a message. Will be used with MULTILINE and IGNORECASE flags. '
> +                                  'eg. ^Acked-by:',
> +                        max_length=50,
> +                        validators=[patchwork.models.validate_regex_compiles],
> +                    ),
> +                ),
> +                migrations.AlterField(
> +                    model_name='tag',
> +                    name='show_column',
> +                    field=models.BooleanField(
> +                        default=True,
> +                        help_text="Show a column displaying this tag's count in the "
> +                                  "patch list view",
> +                    ),
> +                ),
> +                migrations.AlterField(
> +                    model_name='userprofile',
> +                    name='items_per_page',
> +                    field=models.PositiveIntegerField(
> +                        default=100, help_text='Number of items to display per page'
> +                    ),
> +                ),
> +                migrations.AlterField(
> +                    model_name='userprofile',
> +                    name='send_email',
> +                    field=models.BooleanField(
> +                        default=False,
> +                        help_text='Selecting this option allows patchwork to send '
> +                                  'email on your behalf',
> +                    ),
> +                ),
> +                migrations.AlterField(
> +                    model_name='userprofile',
> +                    name='show_ids',
> +                    field=models.BooleanField(
> +                        default=False,
> +                        help_text='Show click-to-copy patch IDs in the list view',
> +                    ),
> +                ),
> +            ],
>          ),
>      ]




More information about the Patchwork mailing list