我一直在运行一个诊所管理软件,到目前为止,我已经注册了一名患者,通过输入他的详细信息,包括年龄和几个月的年龄。这存储在两个Integerfields中。但是,我意识到明年,如果同一患者来访,他的年龄仍将显示为相同。因此,我需要创建大约出生日期(我不坚持注册时给予出生日期。)
因此,我实施了一个功能,该功能可以计算出当前年龄的大约出生日期。我覆盖了保存方法,以便如果患者未进入出生日期,则将插入数据库中的日期。
我的问题是为现有客户创建这个问题。一旦我使用新的datefield和保存方法更新了模型,并在尝试运行makemigrations时,我被提示输入默认值,我不知道如何使makemigrations使用我的功能来更新现有的记录患者。我是否只是将字段设置为空白并为null True,然后运行自定义方法以检查字段是否为空白并更新字段的数据?还是可以使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:
通常,我使用三个迁移处理这样的模型更改:
- 用
null=True
添加新字段 - 填充空字段
- ALTER新添加的字段到
null=False
第二个迁移可以使用RunSQL
或RunPython
和E.G.看起来像这样:
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 <app_name> --empty
生成它,然后使用适当的数据对其进行修改。当您将创建第三个迁移时,在提示您发布的提示中,将有第三个选项,例如"我在以前的迁移中手动使用此操作"。