删除模型继承并将 id 保留在新创建的自动字段中
Remove model inheritance and keep id in newly created autofield
我有一个继承自非抽象超级模型的模型:
class Person(models.Model):
pass
class User(Person):
pass
由于概念错误,我们想删除 Person 模型并将所有 person 数据复制给用户。主要问题涉及 "id" AutoField。
用户模型没有任何由 django 自动创建的 id 字段。由于继承,用户的主键是 "person_ptr_id".
我正在尝试进行数据库迁移。 Django 迁移想要将 "id" 字段添加为 AutoField 但要求提供默认值。我想为每个用户记录从 person_ptr_id 复制初始值。
我还希望 postgres 序列与值同步。
您是否已经执行过此类迁移?
我终于成功完成了这些迁移:
1) 通过注释person_ptr的列删除和'id'的列创建来更改django的自动迁移。然后添加一个 'id' 列作为整数:
migrations.AddField(
model_name='user',
name='id',
field=models.IntegerField(null=True)
),
2) 创建一个新的空迁移,用于将数据从个人迁移到用户,删除 person_ptr 字段并将 'id' 类型更改为 AutoField
def copy_persons_data(apps, schema_editor):
User = apps.get_model("accounts", "User")
Person = apps.get_model("persons", "Person")
for user in User.objects.all():
person = Person.objects.get(id=user.person_ptr_id)
user.new_field1 = person.new_field1
user.new_field2 = person.new_field2
user.id = person.id
user.save()
class Migration(migrations.Migration):
dependencies = [
('accounts', '0026_auto_20170606_1524'),
]
operations = [
migrations.RunPython(copy_persons_data, reverse_code=migrations.RunPython.noop),
migrations.RemoveField(
model_name='user',
name='person_ptr',
),
migrations.AlterField(
model_name='user',
name='id',
field=models.AutoField(auto_created=True, null=False, primary_key=True, serialize=False, verbose_name='ID'),
preserve_default=False,
),
]
这样做,django 会自动为 'id' 字段创建与最大 ID 同步的序列。
备注:
在数据迁移函数中使用user.person_ptr 将使django 拒绝保存用户,因为未保存的人员实例。所以我做了一个获取查询来获取用户的个人实例。
perserve_default=false 对于避免 django 需要新的迁移来删除自动字段的默认值很重要
根据我的经验,最有效的是:
- 重命名 旧模型并为其创建迁移。
- 重新创建具有正确层次结构的新模型,然后再次为其创建迁移。
- 创建数据迁移并用旧值填充新模型。
- 删除旧的 模型并再次迁移。
到目前为止,这是一条不那么曲折的道路。希望对遇到同样问题的人有所帮助。
我有一个继承自非抽象超级模型的模型:
class Person(models.Model):
pass
class User(Person):
pass
由于概念错误,我们想删除 Person 模型并将所有 person 数据复制给用户。主要问题涉及 "id" AutoField。
用户模型没有任何由 django 自动创建的 id 字段。由于继承,用户的主键是 "person_ptr_id".
我正在尝试进行数据库迁移。 Django 迁移想要将 "id" 字段添加为 AutoField 但要求提供默认值。我想为每个用户记录从 person_ptr_id 复制初始值。 我还希望 postgres 序列与值同步。
您是否已经执行过此类迁移?
我终于成功完成了这些迁移:
1) 通过注释person_ptr的列删除和'id'的列创建来更改django的自动迁移。然后添加一个 'id' 列作为整数:
migrations.AddField(
model_name='user',
name='id',
field=models.IntegerField(null=True)
),
2) 创建一个新的空迁移,用于将数据从个人迁移到用户,删除 person_ptr 字段并将 'id' 类型更改为 AutoField
def copy_persons_data(apps, schema_editor):
User = apps.get_model("accounts", "User")
Person = apps.get_model("persons", "Person")
for user in User.objects.all():
person = Person.objects.get(id=user.person_ptr_id)
user.new_field1 = person.new_field1
user.new_field2 = person.new_field2
user.id = person.id
user.save()
class Migration(migrations.Migration):
dependencies = [
('accounts', '0026_auto_20170606_1524'),
]
operations = [
migrations.RunPython(copy_persons_data, reverse_code=migrations.RunPython.noop),
migrations.RemoveField(
model_name='user',
name='person_ptr',
),
migrations.AlterField(
model_name='user',
name='id',
field=models.AutoField(auto_created=True, null=False, primary_key=True, serialize=False, verbose_name='ID'),
preserve_default=False,
),
]
这样做,django 会自动为 'id' 字段创建与最大 ID 同步的序列。
备注:
在数据迁移函数中使用user.person_ptr 将使django 拒绝保存用户,因为未保存的人员实例。所以我做了一个获取查询来获取用户的个人实例。
perserve_default=false 对于避免 django 需要新的迁移来删除自动字段的默认值很重要
根据我的经验,最有效的是:
- 重命名 旧模型并为其创建迁移。
- 重新创建具有正确层次结构的新模型,然后再次为其创建迁移。
- 创建数据迁移并用旧值填充新模型。
- 删除旧的 模型并再次迁移。
到目前为止,这是一条不那么曲折的道路。希望对遇到同样问题的人有所帮助。