Opened 7 years ago

Closed 7 years ago

Last modified 4 years ago

#27871 closed Bug (needsinfo)

Django keeps making the same migration over and over again

Reported by: Kyle Agronick Owned by: nobody
Component: Migrations Version: 1.10
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 (last modified by Kyle Agronick)

This is what the migration looks like:

class Migration(migrations.Migration):

    dependencies = [
        ('jobs', '0003_auto_20170222_1154'),
    ]

    operations = [
        migrations.AlterField(
            model_name='joblog',
            name='job',
            field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='logs', to='jobs.Job'),
        ),
    ]

Running ./mange.py migrate makes no difference. I recently moved the codebase to Python 3.
Below is the create table syntax for the relevant tables:

CREATE TABLE `jobs_jobparameter` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(100) NOT NULL,
  `value` longtext NOT NULL,
  `job_group_id` int(11) NOT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `jobs_jobparameter_job_group_id_bbb541f6_uniq` (`job_group_id`,`name`),
  KEY `jobs_jobparameter_name_84b3d6ba_uniq` (`name`),
  CONSTRAINT `jobs_jobparameter_job_group_id_7205c657_fk_jobs_jobgroup_id` FOREIGN KEY (`job_group_id`) REFERENCES `jobs_jobgroup` (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=45338 DEFAULT CHARSET=utf8

CREATE TABLE `jobs_joblog` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `command` longtext NOT NULL,
  `command_output` longtext NOT NULL,
  `result` tinyint(1) NOT NULL,
  `job_id` int(11) NOT NULL,
  PRIMARY KEY (`id`),
  KEY `jobs_joblog_job_id_734186c1ec7977e9_fk_jobs_job_id` (`job_id`),
  CONSTRAINT `jobs_joblog_job_id_ae8f8e96_fk_jobs_job_id` FOREIGN KEY (`job_id`) REFERENCES `jobs_job` (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=7749677 DEFAULT CHARSET=latin1

CREATE TABLE `jobs_jobgroup` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `job_type` varchar(100) NOT NULL,
  `created_by_id` int(11) NOT NULL,
  `created_date` datetime NOT NULL,
  `queued_date` datetime DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `jobs_jobgroup_created_by_id_769ccba8b90c80f8_fk_auth_user_id` (`created_by_id`),
  KEY `jobs_jobgroup_job_type_c2db1010_uniq` (`job_type`),
  KEY `jobs_jobgroup_created_date_852898d7_uniq` (`created_date`),
  KEY `jobs_jobgroup_queued_date_c38be898_uniq` (`queued_date`),
  CONSTRAINT `jobs_jobgroup_created_by_id_769ccba8b90c80f8_fk_auth_user_id` FOREIGN KEY (`created_by_id`) REFERENCES `auth_user` (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=15290 DEFAULT CHARSET=latin1

CREATE TABLE `jobs_job` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `state` varchar(1) NOT NULL,
  `start_date` datetime DEFAULT NULL,
  `end_date` datetime DEFAULT NULL,
  `job_group_id` int(11) NOT NULL,
  `store` varchar(40) NOT NULL,
  `payload` longtext NOT NULL,
  PRIMARY KEY (`id`),
  KEY `jobs_job_be96d149` (`job_group_id`),
  KEY `jobs_job_store_6681c0e7_uniq` (`store`),
  KEY `jobs_job_start_date_b8aefdc3_uniq` (`start_date`),
  KEY `jobs_job_state_6ec9b5f7_uniq` (`state`),
  CONSTRAINT `jobs_job_job_group_id_93d2fccf_fk_jobs_jobgroup_id` FOREIGN KEY (`job_group_id`) REFERENCES `jobs_jobgroup` (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=3316872 DEFAULT CHARSET=latin1

The migrations are attached.

Attachments (1)

migrations.tar.gz (4.1 KB ) - added by Kyle Agronick 7 years ago.
Migrations for the affected app

Download all attachments as: .zip

Change History (13)

by Kyle Agronick, 7 years ago

Attachment: migrations.tar.gz added

Migrations for the affected app

comment:1 by Kyle Agronick, 7 years ago

Description: modified (diff)

comment:2 by Kyle Agronick, 7 years ago

Description: modified (diff)
Type: UncategorizedBug

comment:3 by Tim Graham, 7 years ago

Component: Database layer (models, ORM)Migrations

Could you please provide a minimal set of models that reproduces the issue? Did you change the case of any models recently (#27297)?

Last edited 7 years ago by Tim Graham (previous) (diff)

comment:4 by Tim Graham, 7 years ago

Resolution: needsinfo
Status: newclosed

comment:5 by Kyle Agronick, 7 years ago

Description: modified (diff)
Resolution: needsinfo
Status: closednew

comment:6 by Kyle Agronick, 7 years ago

Description: modified (diff)

Here are all the models:

from django.contrib.auth.models import User
from django.db import models

job_state = (('P', 'Pending'), ('A', 'Active'), ('C', 'Completed'), ('F', 'Failed'))
app_type = (('R', 'RX'), ('W', 'WAR'))
server_types = #taken out


class JobGroup(models.Model):
    job_type = models.CharField(max_length=100, db_index=True)
    created_by = models.ForeignKey(User)
    queued_date = models.DateTimeField(null=True, db_index=True)
    created_date = models.DateTimeField(auto_now_add=True, db_index=True)


class JobParameter(models.Model):
    job_group = models.ForeignKey(JobGroup, related_name='job_param', on_delete=models.CASCADE)
    name = models.CharField(max_length=100, db_index=True)
    value = models.TextField()

    def split_values(self):
        if ',' in self.value and isinstance(self.value, str):
            return self.value.split(', ')
        else:
            return [self.value]

    class Meta:
        unique_together = ('job_group', 'name')


class Job(models.Model):
    job_group = models.ForeignKey(JobGroup, related_name='jobs', on_delete=models.CASCADE)
    state = models.CharField(max_length=1, choices=job_state, default='P', db_index=True)
    start_date = models.DateTimeField(null=True, db_index=True)
    end_date = models.DateTimeField(null=True)
    store = models.CharField(max_length=40, db_index=True)
    payload = models.TextField()

    def get_full_state(self):
        return self.get_state_display() if self.state in dict(job_state) else 'Unknown'

    class Meta:
        permissions = (
            ('deployment_job', 'Access Deployment job'),
            ('services_job', 'Access System Services job'),
            ('offline_status_job', 'Access Offline Status job'),
        )


class JobLog(models.Model):
    job = models.ForeignKey(Job, related_name='logs', on_delete=models.CASCADE)
    command = models.TextField()
    command_output = models.TextField()
    result = models.BooleanField(default=False)


class Service(models.Model):
    service_name = models.CharField(max_length=40)
    human_readable_name = models.CharField(max_length=40)
    server_type = models.CharField(choices=server_types, max_length=5)

    def __str__(self):
        return self.human_readable_name

    class Meta:
        ordering = ['human_readable_name']
        unique_together = ['service_name', 'server_type']

comment:7 by Kyle Agronick, 7 years ago

Description: modified (diff)

comment:8 by Tim Graham, 7 years ago

I cannot reproduce a problem. Can you please debug the issue and provide more specific steps to reproduce it?

comment:9 by Kyle Agronick, 7 years ago

You would probably need to run my create table scripts and load in my migrations on a MySQL DB.

Changing job to Job in the name part of CreateModel seems to have fixed it. I don't know why, but at somepoint after squashing the migrations this became an issue.

        migrations.CreateModel(
            name='Job',
            fields=[
                ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
                ('state', models.CharField(choices=[('P', 'Pending'), ('A', 'Active'), ('C', 'Completed'), ('F', 'Failed')], default='P', max_length=1)),
                ('start_date', models.DateTimeField()),
                ('end_date', models.DateTimeField()),
            ],
        ),

comment:10 by Tim Graham, 7 years ago

makemigrations doesn't examine the database state so loading the schema wouldn't matter but some differences in the old migration files is likely the cause (as opposed to what I did in generating an initial migration from the provided models). Part of putting together a useful bug report is to create a minimal sample project that reproduces the issue. For example, I doubt all 6 models are required.

Again I'll point to #27297 and ask if this might be a duplicate of that issue?

comment:11 by Tim Graham, 7 years ago

Resolution: needsinfo
Status: newclosed

comment:12 by Stanislav Zubov, 4 years ago

Greetings from 2020!

Met this issue today with models like this:

class CRITICALITY(models.ChoiceEnum):
    LOW = 'low'
    NORMAL = 'normal'
    HIGH = 'high'

class Detection(models.Model):
    criticality = models.CharField(
        max_length=10, choices=CRITICALITY.choices(), default=CRITICALITY.NORMAL,
    )
    notification = models.ForeignKey(
        'notifications.UserNotification', related_name='+', blank=True, null=True,
        on_delete=models.SET_NULL
    )

makemigrations generates similar migration on every run:

# Generated by Django 2.2.3 on 2020-09-02 08:29

from django.db import migrations, models
import django.db.models.deletion


class Migration(migrations.Migration):

    dependencies = [
        ('detections', '0001_initial'),
    ]

    operations = [
        migrations.AlterField(
            model_name='detection',
            name='notification',
            field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to='notifications.UserNotification'),
        ),
    ]

p.s.

Python 3.6.8
Django                        2.2.3
django-cors-headers           3.0.2
django-db-geventpool          3.1.0
django-debug-toolbar          1.9.1
django-filter                 2.1.0
django-redis                  4.10.0
django-sendfile2              0.4.2
djangorestframework           3.9.4
pytest-django                 3.6.0
Note: See TracTickets for help on using tickets.
Back to Top