9
votes

Django is creating the same migrations file repeatedly when calling:

./manage.py makemigrations

The same migrations will be created in a new migrations file every time makemigrations is run regardless of if the changes are migrated or not.

The process looks like so:

./manage.py makemigrations app

Migrations for 'app':
project/app/migrations/0007_auto_20171010_1837.py
- Alter field charge_type on charge
- Alter field fee_type on fee
- Alter field event_type on orderevent


./manage.py migrate app

Running migrations:
Applying mws.0007_auto_20171010_1837... OK


./manage.py makemigrations app

Migrations for 'app':
project/app/migrations/0008_auto_20171010_1838.py
- Alter field charge_type on charge
- Alter field fee_type on fee
- Alter field event_type on orderevent


./manage.py makemigrations app

Migrations for 'app':
project/app/migrations/0009_auto_20171010_1839.py
- Alter field charge_type on charge
- Alter field fee_type on fee
- Alter field event_type on orderevent

I am curious why new identical migrations continue to be created with updated migration file names when no changes are being made to the models between makemigrations and migrate commands.

The models look like this:

Current app models:

class OrderEvent(models.Model):
    client = models.ForeignKey('clients.Client')

    SHIPMENT_EVENT = 'she'
    REFUND_EVENT = 'ree'
    CHARGEBACK_EVENT = 'cbe'
    GUARANTEE_CLAIM_EVENT = 'gce'

    EVENT_TYPE_CHOICES = {
        (SHIPMENT_EVENT, 'Shipment Event'),
        (REFUND_EVENT, 'Refund Event'),
        (CHARGEBACK_EVENT, 'Chargeback Event'),
        (GUARANTEE_CLAIM_EVENT, 'Guarantee Claim Event'),
    }

    event_type = models.CharField(max_length=3, choices=EVENT_TYPE_CHOICES)
    amazon_order_id = models.CharField(max_length=19)
    seller_order_id = models.CharField(max_length=19)
    marketplace_name = models.CharField(max_length=14)
    posted_date = models.DateTimeField(blank=True, null=True)


class ShipmentItem(models.Model):
    order_event = models.ForeignKey('OrderEvent')
    seller_sku = models.CharField(max_length=128)
    order_item_id = models.CharField(max_length=19)
    quantity_shipped = models.IntegerField()



class Charge(models.Model):
    shipment_item = models.ForeignKey('ShipmentItem', blank=True, null=True)

    PAYMENT_METHOD_FEE = 'pmf'
    EXPORT_CHARGE = 'exc'
    SAFET_REIMBURSEMENT = 'str'
    OTHER = 'oth'

    CHARGE_TYPE_CHOICES = {
        (PAYMENT_METHOD_FEE, 'Payment Method Fee'),
        (EXPORT_CHARGE, 'Export Charge'),
        (SAFET_REIMBURSEMENT, 'SAFET Reimbursement'),
        (OTHER, 'Other'),
    }
    charge_type = models.CharField(
        max_length=3,
        choices=CHARGE_TYPE_CHOICES,
        blank=True,
        null=True
    )
    charge_currency_code = models.CharField(
        max_length=3,
        blank=True,
        null=True
    )
    charge_amount = models.DecimalField(
        max_digits=10,
        decimal_places=2,
        blank=True,
        null=True
    )


class Fee(models.Model):
    shipment_item = models.ForeignKey('ShipmentItem', blank=True, null=True)
    TAPING_FEE = 'taf'
    TRANSPORTATION_FEE = 'trf'
    OTHER = 'oth'
    FEE_TYPE_CHOICES = {
        (TAPING_FEE, 'Taping Fee'),
        (TRANSPORTATION_FEE, 'Transportation Fee'),
        (OTHER, 'Other'),
    }
    fee_type = models.CharField(
        max_length=3,
        choices=FEE_TYPE_CHOICES,
        blank=True,
        null=True
    )
    fee_currency_code = models.CharField(
        max_length=3,
        blank=True,
        null=True
    )
    fee_amount = models.DecimalField(
        max_digits=10,
        decimal_places=2,
        blank=True,
        null=True
    )

Client app model:

class Client(models.Model):

    name = models.CharField(max_length=128)
    code = models.CharField(
        max_length=16,
        blank=True,
        unique=True,
        help_text="Example: 00042",
    )
    slug = AutoSlugField(max_length=128, unique=True, populate_from='name')

    INVOICE_LEVEL_PARENT = 'pa'
    INVOICE_LEVEL_CHILD = 'ch'

    INVOICE_LEVEL_CHOICES = {
        (INVOICE_LEVEL_PARENT, 'Parent-level Invoice'),
        (INVOICE_LEVEL_CHILD, 'Child-level Invoice'),
    }

    invoice_level = models.CharField(
        max_length=2,
        choices=INVOICE_LEVEL_CHOICES,
        default=INVOICE_LEVEL_PARENT,
    )
    payment_terms = models.CharField(max_length=30, default='Net 15')
    late_fees = models.DecimalField(default='1.50', max_digits=5, decimal_places=2)

    notes = models.TextField(blank=True)

    def __str__(self):
        return self.name
3
Add your model code here. I think you are using a default value as dynamic in fields.Neeraj Kumar
Please show what the alter is actually doing.Krzysztof Szularz
Agreed--this is likely because of something indeterminate in your model definition (choices that are dynamic that can change from minute to minute? a datetime.datetime.now() call somewhere? etc.)ryanmrubin

3 Answers

22
votes

The choice parameter should be a deterministic iterable like a list or tuple.

A set is randomized in Python 3.3+ and it can not be a choice.

Change

EVENT_TYPE_CHOICES = {
    (SHIPMENT_EVENT, 'Shipment Event'), ...
}

to

EVENT_TYPE_CHOICES = (
    (SHIPMENT_EVENT, 'Shipment Event'), ...
)
0
votes

Recently, I have faced this problem and found the solution which was a little weird even I don't know the root cause of the issue.

I had the model as below in same model.py:

class Status(models.Model):
    status=models.CharField(db_column='status',max_length=50, null=False, blank=False)


class Details(models.Model):
    #notes_names=models.CharField(max_length=50,db_column='notes_names')
    #file=models.FileField(upload_to='notes/%Y/%m/%d',max_length=255,null=True,blank=True)
    #user = models.ForeignKey(User,on_delete=models.CASCADE)
    faculty = models.ForeignKey(Registration,db_column='faculty_id',on_delete=models.CASCADE)
    degree=models.ForeignKey(Notes_Degree,on_delete=models.CASCADE)
    seqNo=models.IntegerField(default=1)
    branch=models.ForeignKey(Notes_Branch,on_delete=models.CASCADE)
    semester=models.ForeignKey(Notes_Semester,on_delete=models.CASCADE)
    subject=models.ForeignKey(Notes_Subject,on_delete=models.CASCADE)
    file=models.FileField(validators=[FileExtensionValidator(allowed_extensions=['pdf'])])
    fileType= models.CharField(db_column='file_type',max_length=30, null=True, blank=True)
    size= models.FloatField(default=0)
    url=models.CharField(db_column='url',max_length=1000, null=True, blank=True)
    pages=models.BigIntegerField(null=False, blank=False)
    # Try later ContentTypeRestrictedFileField(upload_to='uploads/', content_types=['video/x-msvideo', 'application/pdf', 'video/mp4', 'audio/mpeg', ],max_upload_size=5242880,blank=True, null=True)
    #filename= models.CharField(db_column='file_name',max_length=80, null=False, blank=False)
    #sample notes columns
    sampleFile=models.FileField(db_column='sample_file',validators=[FileExtensionValidator(allowed_extensions=['pdf'])])
    sampleSize=models.FloatField(default=0)
    sampleFileType= models.CharField(db_column='sample_file_type',max_length=30, null=True, blank=True)
    sampleUrl=models.CharField(db_column='sample_url',max_length=1000, null=True, blank=True)
    updateSeqNo=models.IntegerField(default=0)
    uploadedAt= models.DateTimeField(db_column='uploaded_date',auto_now_add=False,null=False, blank=False)
    updatedAt= models.DateTimeField(db_column='updated_date',auto_now_add=False,null=False, blank=False)
    active=models.BooleanField(default=True)
    status=models.ForeignKey(Status,on_delete=models.CASCADE,default=1)
    description=models.CharField(db_column='description',max_length=100, null=True, blank=True)
    """
    #url=models.TextField(blank=True, null=True),
    userId/notes/degree/Branch/Semester/SubjectId/Seqno/NotesId/updatedTime/Filename
    """

In this case, every time I was doing make migrations, it was creating the auto_migration.py class on-field "status".

To solve the issue, I added Status class into another module's model.py and imported. It worked and resolved smoothly.

I am really not sure why, because, in the same project, the above kind of structure is working perfectly.

-5
votes

You will have to migrate first before making new migration

./mange.py migrate

Otherwise, it will keep comparing to the current db and create new files.