在使用South迁移父类时,我对_ptr使用什么值? [英] What value do I use for _ptr when migrating reparented classes with South?

查看:71
本文介绍了在使用South迁移父类时,我对_ptr使用什么值?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有两个类,其中一个是另一类的后代,我想使它们两个同级都从同一基类继承。

I have two classes, one of which is descended from the other, and I would like to make them both sibling classes descended from the same base class.

之前:

from django.db import models

class A(models.Model):
    name = models.CharField(max_length=10)

class B(models.Model):
    title = models.CharField(max_length=10)

之后:

from django.db import models

class Base(models.Model):
    name = models.CharField(max_length=10)

class A(Base):
    pass

class B(Base):
    title = models.CharField(max_length=10)

当我生成模式迁移时,这是输出,包括我对问题的回答:

When I generate a schema migration, this is the output, including my answers to the questions:

+ Added model basetest.Base
? The field 'B.a_ptr' does not have a default specified, yet is NOT NULL.
? Since you are removing this field, you MUST specify a default
? value to use for existing rows. Would you like to:
?  1. Quit now, and add a default to the field in models.py
?  2. Specify a one-off value to use for existing columns now
?  3. Disable the backwards migration by raising an exception.
? Please select a choice: 3
- Deleted field a_ptr on basetest.B
? The field 'B.base_ptr' does not have a default specified, yet is NOT NULL.
? Since you are adding this field, you MUST specify a default
? value to use for existing rows. Would you like to:
?  1. Quit now, and add a default to the field in models.py
?  2. Specify a one-off value to use for existing columns now
? Please select a choice: 2
? Please enter Python code for your one-off default value.
? The datetime module is available, so you can do e.g. datetime.date.today()
>>> 37
+ Added field base_ptr on basetest.B
? The field 'A.id' does not have a default specified, yet is NOT NULL.
? Since you are removing this field, you MUST specify a default
? value to use for existing rows. Would you like to:
?  1. Quit now, and add a default to the field in models.py
?  2. Specify a one-off value to use for existing columns now
?  3. Disable the backwards migration by raising an exception.
? Please select a choice: 3
- Deleted field id on basetest.A
? The field 'A.name' does not have a default specified, yet is NOT NULL.
? Since you are removing this field, you MUST specify a default
? value to use for existing rows. Would you like to:
?  1. Quit now, and add a default to the field in models.py
?  2. Specify a one-off value to use for existing columns now
?  3. Disable the backwards migration by raising an exception.
? Please select a choice: 3
- Deleted field name on basetest.A
? The field 'A.base_ptr' does not have a default specified, yet is NOT NULL.
? Since you are adding this field, you MUST specify a default
? value to use for existing rows. Would you like to:
?  1. Quit now, and add a default to the field in models.py
?  2. Specify a one-off value to use for existing columns now
? Please select a choice: 2
? Please enter Python code for your one-off default value.
? The datetime module is available, so you can do e.g. datetime.date.today()
>>> 73
+ Added field base_ptr on basetest.A
Created 0002_auto__add_base__del_field_b_a_ptr__add_field_b_base_ptr__del_field_a_i.py. You can now apply this migration with: ./manage.py migrate basetest

我不知道如何回答有关B.base_ptr和A.base_ptr的默认值的问题。我给出的任何常量都会导致迁移在运行时失败,并显示以下输出:

I do not know how to answer the questions about default values for B.base_ptr and A.base_ptr. Any constant I give causes the migration to fail when it is run, with this output:

FATAL ERROR - The following SQL query failed: CREATE TABLE "_south_new_basetest_a" ()
The error was: near ")": syntax error
RuntimeError: Cannot reverse this migration. 'B.a_ptr' and its values cannot be restored.

顺便说一下,这是我使用sqlite3时的结果。使用Postgres会给出以下信息:

This is the result when I use sqlite3, by the way. Using Postgres gives something like this:

FATAL ERROR - The following SQL query failed: ALTER TABLE "basetest_a" ADD COLUMN "base_ptr_id" integer NOT NULL PRIMARY KEY DEFAULT 73;
The error was: could not create unique index "basetest_a_pkey"
DETAIL:  Key (base_ptr_id)=(73) is duplicated.

Error in migration: basetest:0002_auto__add_base__del_field_b_a_ptr__add_field_b_base_ptr__del_field_a_i
IntegrityError: could not create unique index "basetest_a_pkey"
DETAIL:  Key (base_ptr_id)=(73) is duplicated.

base_ptr应该使用什么值来使此迁移有效?谢谢!

What values should I use for base_ptr to make this migration work? Thanks!

推荐答案

您可以在单独的阶段中进行此操作。

You do this in separate phases.

阶段1:在代码中创建基础模型。在A和B模型上,将 base_ptr 作为可为空的FK添加到Base(名称 base_ptr 是通过小写class-name Base ,相应地修改您的名字)。在新列上指定 db_column ='base_ptr',这样就不会添加 _id 后缀。暂时不要更改父母身份:将 B 保留为 A A 和以前一样( Base 尚无子类)。添加迁移以更改相应的数据库,然后运行它。

Phase 1: Create your "Base" model in the code. On the A and B models, add base_ptr as a nullable FK to Base (the name base_ptr is made by lowercasing the class-name Base, adapt your names accordingly). Specify db_column='base_ptr' on the new column, so you don't get an _id suffix added. Don't change parenthood yet: Keep B as a child of A and A as it was before (Base has no child classes yet). Add a migration to make the respective database changes, and run it.

阶段2:创建数据迁移,在其周围复制相关数据。您可能应该将所有 A 数据复制到 Base ,删除多余的 A 记录(为 B 实例提供服务的记录),以及其余的记录( A 和<$ c $的记录) c> B )将ID复制到 base_ptr 中。请注意,子类 B 使用两个表-其 id 字段来自 A 的表,并在其自己的表上有一个字段 a_ptr ,它是 A -因此,如果将值从 a_ptr 复制到 base_ptr ,更新操作将更加高效。确保复制到base_ptr中是在复制到 Base 表之后进行的,这样您就不会违反FK约束。

Phase 2: Create a data migration, copying relevant data around. You should probably copy all A data into Base, remove redundant A records (those that served B instances), and in remaining records (of both A and B) copy the id into base_ptr. Note that the child class B uses two tables -- its id field comes from A's table, and on its own table there is a field a_ptr which is a FK to A -- so your update operation will be more efficient if you copy values from a_ptr to base_ptr. Make sure the copying into base_ptr occurs after the copying into the Base table, so you don't violate the FK constraints.

阶段3:现在再次更改模型-删除显式的 base_ptr FK并将父级更改为您喜欢的方式,然后创建第三个迁移(自动模式迁移) 。请注意,将父级设置为 Base 隐式定义了一个不可为空的 base_ptr 字段,因此对于 base_ptr 字段,您只是将可为空的字段更改为不可为空的字段,并且不需要默认值。

Phase 3: Now change the models again -- remove the explicit base_ptr FK and change parents to the way you like, and create a third migration (automatic schema migration). Note that setting the parent to Base implicitly defines a non-nullable base_ptr field, so with respect to the base_ptr fields, you are only changing a nullable field into non-nullable, and no default is needed.

您仍然应该要求提供 a_ptr 的默认值-从 B A的隐式FK A 更改为 Base 时删除的code>;向后迁移时需要使用默认值。您可以执行某些将使向后迁移失败的操作,或者,如果确实要支持它,则可以向 B 添加一个显式可空的 a_ptr 。 code>,就像您之前使用的 base_ptr 列一样。然后可以在第四次迁移中删除此可为空的列。

You should still be asked for a default value for a_ptr -- the implicit FK from B to A that is removed when the parent is changed from A to Base; the default is needed for the migration in the backward direction. You can either do something that will fail the backward migration, or, if you do want to support it, add an explicit nullable a_ptr to B, like the base_ptr columns you used before. This nullable column can then be removed in a fourth migration.

这篇关于在使用South迁移父类时,我对_ptr使用什么值?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆