Django Migrations:使用 makemigrations 创建相同的迁移

Posted

技术标签:

【中文标题】Django Migrations:使用 makemigrations 创建相同的迁移【英文标题】:Django Migrations: Same migrations being created with makemigrations 【发布时间】:2018-03-22 06:51:21 【问题描述】:

Django 在调用时重复创建相同的迁移文件:

./manage.py makemigrations

每次运行 makemigrations 时,无论是否迁移更改,都会在新的迁移文件中创建相同的迁移。

流程如下:

./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

我很好奇为什么在 makemigrations 和 migrate 命令之间没有对模型进行任何更改时,使用更新的迁移文件名继续创建新的相同迁移。

模型如下所示:

当前应用模型:

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
    )

客户端应用模型:

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

【问题讨论】:

在此处添加您的型号代码。我认为您在字段中使用默认值作为动态。 请展示alter实际在做什么。 同意——这很可能是因为您的模型定义中存在不确定性(动态的选择会随着时间的推移而变化?在某处调用 datetime.datetime.now() 吗?等等) 【参考方案1】:

choice 参数应该是确定性可迭代,如列表或元组

set 在 Python 3.3+ 中是随机的,它不能选择

改变

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

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

【讨论】:

【参考方案2】:

最近,我遇到了这个问题,并找到了一个有点奇怪的解决方案,即使我不知道问题的根本原因。

我在同一个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
    """

在这种情况下,每次我进行迁移时,都会在字段“状态”中创建 auto_migration.py 类。

为了解决这个问题,我将 Status 类添加到另一个模块的 model.py 中并导入。它工作并顺利解决。

我真的不知道为什么,因为在同一个项目中,上述结构运行良好。

【讨论】:

【参考方案3】:

在进行新迁移之前,您必须先迁移

./mange.py 迁移

否则,它将继续与当前数据库进行比较并创建新文件。

【讨论】:

不,不会。 Django 将模型中的定义与迁移文件进行比较,而不是数据库中的状态。

以上是关于Django Migrations:使用 makemigrations 创建相同的迁移的主要内容,如果未能解决你的问题,请参考以下文章

重新创建已删除的 django_migrations 表

Django Migrations:使用 makemigrations 创建相同的迁移

Django 删除 migrations

如何使用 Django Migrations 重新创建已删除的表?

django migrations 采坑

django migrations 采坑