【问题标题】:Running migrations for a new added field which overrides save为覆盖保存的新添加字段运行迁移
【发布时间】:2019-08-02 00:15:42
【问题描述】:

我一直在运行一个诊所管理软件,到目前为止,我通过输入他的详细信息(包括年龄和月份)来注册患者。这存储在两个 IntegerFields 中。但是我意识到,如果明年同样的病人来访,他的年龄仍然会显示为相同的。因此我需要创建一个大概的出生日期(我不坚持让患者在注册时给出他们的出生日期。)

所以我实现了一个函数,可以根据当前年龄计算大致的出生日期。我重写了 save 方法,如果患者没有输入出生日期,则会在数据库中插入一个计算的日期。

我的问题是为现有客户创建这个。一旦我用新的 DateField 和 save 方法更新了我的模型,在尝试运行 makemigrations 时,系统会提示我输入一个默认值,我不知道如何让 makemigrations 使用我的函数来更新现有的记录耐心。我是否只是将字段设置为空白和 null tr​​ue,然后运行自定义方法来检查字段是否为空白,并更新字段的数据?或者我可以让 makemigrations 本身运行我实现的功能吗?这样做的正确方法是什么?

我的模型和方法:

class customer(models.Model):
    # Need autoincrement, unique and primary
    cstid = models.AutoField(primary_key=True, unique=True)
    name = models.CharField(max_length=35)
    ageyrs=models.IntegerField(blank=True)
    agemnths=models.IntegerField(blank=True)
    dob = models.DateField()
    gender_choices = (
        ('male', 'Male'),
        ('female', 'Female'),
        ('other', 'Something else'),
        ('decline', 'Decline to answer')
        )
    gender = models.CharField(
        choices=gender_choices, max_length=10, default='male')
    maritalstatus_choices = (
        ('unmarried', 'Unmarried'),
        ('married', 'Married')
                            )
    maritalstatus = models.CharField(
        choices=maritalstatus_choices, max_length=10, default='Unmarried')
    mobile = models.CharField(max_length=15, default='')
    alternate = models.CharField(max_length=15, default='', blank=True)
    email = models.CharField(max_length=50, default='', blank=True)
    address = models.CharField(max_length=80, default='', blank=True)
    city = models.CharField(max_length=25, default='', blank=True)
    occupation = models.CharField(max_length=25, default='', blank=True)
    bloodgroup_choices = (('apos', 'A+'),
        ('aneg', 'A-'),
        ('bpos', 'B+'),
        ('bneg', 'B-'),
        ('opos', 'O+'),
        ('oneg', 'O-'),
        ('abpos', 'AB+'),
        ('abneg', 'AB-')
        )
    bloodgroup = models.CharField(choices=bloodgroup_choices, max_length=5, default='-', blank=True)
    linkedclinic = models.ForeignKey(Clinic, on_delete=models.CASCADE)

    class Meta:
        unique_together = ["name", "mobile", "linkedclinic"]


    def __str__(self):
        return self.name

    def save(self, *args, **kwargs):
        if not self.dob:
            current = datetime.datetime.now()
            newdate = current - relativedelta(years=self.ageyrs, months=self.agemnths)
            if not self.ageyrs == 0:
    #           datetime(year, month, day[, hour[, minute[, second[, microsecond[,tzinfo]]]]])
                dob = datetime.datetime(newdate.year, 1, 1)
            else:
                print("Age is less than 1 year")
                dob = newdate
            self.dob = dob
        super().save(*args, **kwargs)  # Call the "real" save() method.

    def age(self):
        if self.ageyrs == 0 and self.agemnths == 0:
            return "0yr"
        if self.ageyrs == 0:
            return str(self.agemnths) + "m"
        if self.agemnths == 0:
            return str(self.ageyrs) +"yr"
        return str(self.ageyrs) +"yr " +  str(self.agemnths) + "m"

关于运行 makemigrations:

joel@hp:~/myappointments$ ./manage.py makemigrations
You are trying to add a non-nullable field 'dob' to customer without a default; we can't do that (the database needs something to populate existing rows).
Please select a fix:
1) Provide a one-off default now (will be set on all existing rows with a null value for this column)
2) Quit, and let me add a default in models.py
Select an option: 

【问题讨论】:

    标签: django python-3.x django-migrations


    【解决方案1】:

    通常,我使用三个迁移来处理此类模型更改:

    1. 使用null=True 添加新字段
    2. 填充空白字段
    3. 将新添加的字段更改为null=False

    第二次迁移可以使用RunSQLRunPython,例如看起来像这样:

    def forward(apps, schema_editor):
        customer = apps.get_model("<app_name>", "customer")
        db_alias = schema_editor.connection.alias
        current = datetime.datetime.now()
        for c in customer.objects.using(db_alias).all():
            newdate = current - relativedelta(years=c.ageyrs, months=c.agemnths)
            if not self.ageyrs == 0:
                dob = datetime.datetime(newdate.year, 1, 1)
            else:
                print("Age is less than 1 year")
            dob = newdate
            c.dob = dob.date()
            c.save()
    
    
    def rollback(apps, schema_editor):
        pass
    
    
    ...
        operations = [migrations.RunPython(forward, rollback)]
    

    您可以使用python manage.py makemigrations &lt;app_name&gt; --empty 生成它,然后使用适当的数据对其进行修改。当您将创建第三次迁移时,在您发布的提示中会有第三个选项,例如“我在以前的迁移中使用手动处理过”。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2020-12-23
      • 1970-01-01
      • 2016-02-05
      • 2016-07-06
      • 2019-05-19
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多