pythondjangodjango-modelsmigrationdjango-migrations

Django Migrations: Same migrations being created with makemigrations


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

Solution

  • 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'), ...
    )