Sam*_*ham 112 python mysql database django schema-migration
所以大约一年前,我开始了一个项目,像所有新开发人员一样,我并没有真正关注结构,但是现在我与Django一起开始显示我的项目布局主要是我的模型结构很糟糕.
我的模型主要存放在一个应用程序中,并且这些模型中的大多数应该在他们自己的个人应用程序中,我确实尝试解决这个并将它们移动到南方然而我发现它很棘手并且由于外键等而非常困难.
但是由于Django 1.7和内置的迁移支持,现在有更好的方法吗?
oza*_*zan 316
这可以很容易地使用migrations.SeparateDatabaseAndState.基本上,我们使用数据库操作来同时使用两个状态操作重命名表,以从一个应用程序的历史记录中删除模型,并在另一个应用程序的历史记录中创建它.
python manage.py makemigrations old_app --empty
Run Code Online (Sandbox Code Playgroud)
在迁移中:
class Migration(migrations.Migration):
dependencies = []
database_operations = [
migrations.AlterModelTable('TheModel', 'newapp_themodel')
]
state_operations = [
migrations.DeleteModel('TheModel')
]
operations = [
migrations.SeparateDatabaseAndState(
database_operations=database_operations,
state_operations=state_operations)
]
Run Code Online (Sandbox Code Playgroud)
首先,将模型复制到新应用程序的model.py,然后:
python manage.py makemigrations new_app
Run Code Online (Sandbox Code Playgroud)
这将生成一个以天真CreateModel操作为唯一操作的迁移.在SeparateDatabaseAndState操作中包装,以便我们不会尝试重新创建表.还包括先前的迁移作为依赖项:
class Migration(migrations.Migration):
dependencies = [
('old_app', 'above_migration')
]
state_operations = [
migrations.CreateModel(
name='TheModel',
fields=[
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
],
options={
'db_table': 'newapp_themodel',
},
bases=(models.Model,),
)
]
operations = [
migrations.SeparateDatabaseAndState(state_operations=state_operations)
]
Run Code Online (Sandbox Code Playgroud)
小智 25
我遇到了同样的问题. Ozan的回答帮了我很多,但不幸的是还不够.事实上,我有几个ForeignKey链接到我想要移动的模型.经过一番头痛我找到了解决方案,所以决定发布它以解决人们的时间问题.
您还需要2个步骤:
ForeignKey链接更改TheModel为Integerfield.然后跑python manage.py makemigrationsForeignKey(TheModel)而不是IntegerField().然后再次进行迁移(python manage.py makemigrations).然后你可以迁移它应该工作(python manage.py migrate)希望能帮助到你.当然在尝试生产之前在当地测试它以避免糟糕的惊喜:)
Mic*_*ter 14
我是怎么做到的(在Django上测试== 1.8,有postgres,所以可能也是1.7)
情况
app1.YourModel
但你想要它去: app2.YourModel
将此添加到app2.YourModel:
Class Meta:
db_table = 'app1_yourmodel'
Run Code Online (Sandbox Code Playgroud)$ python manage.py makemigrations app2
在app2中使用migrations.CreateModel()语句进行新的迁移(例如0009_auto_something.py),将此语句移动到app2的初始迁移(例如0001_initial.py)(它就像它一直存在的那样).现在删除创建的migration = 0009_auto_something.py
就像你的行为一样,app2.YourModel总是在那里,现在从你的迁移中移除app1.YourModel的存在.含义:注释掉CreateModel语句,以及之后使用的每个调整或数据迁移.
当然,每个对app1.YourModel的引用都必须通过您的项目更改为app2.YourModel.另外,不要忘记迁移中app1.YourModel的所有可能外键都必须更改为app2.YourModel
现在,如果你进行$ python manage.py migrate,没有任何改变,当你执行$ python manage.py makemigrations时,没有检测到任何新内容.
现在最后一步:从app2.YourModel中删除Class Meta并执行$ python manage.py makemigrations app2 && python manage.py migrate app2(如果你看看这个迁移,你会看到这样的东西:)
migrations.AlterModelTable(
name='yourmodel',
table=None,
),
Run Code Online (Sandbox Code Playgroud)table = None,表示它将采用默认的表名,在本例中为app2_yourmodel.
PS在迁移过程中会看到content_type app1.yourmodel已被删除并可以删除.您可以对此说"是",但前提是您不使用它.如果您严重依赖它来使FK与该内容类型保持完整,请不要回答是或否,而是手动进入数据库,并删除内容类型app2.yourmodel,并重命名contenttype app1. yourmodel到app2.yourmodel,然后继续回答否.
Chi*_*and 13
我删除旧答案可能会导致数据丢失.正如ozan所说,我们可以在每个应用程序中创建一个迁移.
首次迁移从第一个应用程序中删除模型.
$ python manage.py makemigrations old_app --empty
Run Code Online (Sandbox Code Playgroud)
编辑迁移文件以包含这些操作.
class Migration(migrations.Migration):
database_operations = [migrations.AlterModelTable('TheModel', 'newapp_themodel')]
state_operations = [migrations.DeleteModel('TheModel')]
operations = [
migrations.SeparateDatabaseAndState(
database_operations=database_operations,
state_operations=state_operations)
]
Run Code Online (Sandbox Code Playgroud)
第二次迁移取决于第一次迁移并在第二个应用程序中创建新表.将模型代码移动到第二个应用程序后
$ python manage.py makemigrations new_app
Run Code Online (Sandbox Code Playgroud)
并将迁移文件编辑为类似的内容.
class Migration(migrations.Migration):
dependencies = [
('old_app', 'above_migration')
]
state_operations = [
migrations.CreateModel(
name='TheModel',
fields=[
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
],
options={
'db_table': 'newapp_themodel',
},
bases=(models.Model,),
)
]
operations = [
migrations.SeparateDatabaseAndState(state_operations=state_operations)
]
Run Code Online (Sandbox Code Playgroud)
cla*_*ond 10
我感到紧张的手动编码迁移(按照Ozan的回答所要求的),因此以下结合Ozan和Michael的策略来最小化所需的手动编码量:
makemigrations.app1到app2根据@Michael的建议,我们使用db_table"new"模型上的Meta选项将新模型指向旧数据库表:
class Meta:
db_table = 'app1_yourmodel'
Run Code Online (Sandbox Code Playgroud)跑makemigrations.这将产生CreateModelin app2和DeleteModelin app1.从技术上讲,这些迁移引用完全相同的表,并将删除(包括所有数据)并重新创建表.
实际上,我们不希望(或需要)对表做任何事情.我们只需要让Django相信已经做出了改变.按照@ Ozan的回答,state_operations旗帜就是SeparateDatabaseAndState这样做的.因此,我们将所有migrations条目包装在两个MIGRATIONS FILES中SeparateDatabaseAndState(state_operations=[...]).例如,
operations = [
...
migrations.DeleteModel(
name='YourModel',
),
...
]
Run Code Online (Sandbox Code Playgroud)
变
operations = [
migrations.SeparateDatabaseAndState(state_operations=[
...
migrations.DeleteModel(
name='YourModel',
),
...
])
]
Run Code Online (Sandbox Code Playgroud)编辑:您还需要确保新的"虚拟" CreateModel迁移依赖于实际创建或更改原始表的任何迁移.例如,如果您的新迁移是app2.migrations.0004_auto_<date>(for Create)和app1.migrations.0007_auto_<date>(for Delete),最简单的事情是:
app1.migrations.0007_auto_<date>并复制其app1依赖关系(例如 ('app1', '0006...'),).这是"紧接在先"的迁移,app1并且应该包括对所有实际模型构建逻辑的依赖性.app2.migrations.0004_auto_<date>并添加刚刚复制到其dependencies列表中的依赖项.编辑:如果您ForeignKey与正在移动的模型有关系,则上述操作可能无效.这是因为:
ForeignKey更改创建依赖关系ForeignKey更改,state_operations因此我们需要确保它们与表操作分开."最小"操作集取决于具体情况,但以下过程应适用于大多数/所有ForeignKey迁移:
app1to 复制app2,设置db_table,但不要更改任何FK参考.makemigrations并包装所有app2迁移state_operations(参见上文)
app2 CreateTable在最新的app1迁移中添加依赖项models.py(不要删除它),这样它就不会与导入的类竞争.运行makemigrations但不要包装任何东西state_operations(FK更改应该实际发生).在所有ForeignKey迁移中添加依赖项(即AlterField)到CreateTable迁移中app2(下一步需要此列表,以便跟踪它们).例如:
CreateModeleg 的迁移app2.migrations.0002_auto_<date>并复制该迁移的名称.查找具有该模型的ForeignKey的所有迁移(例如,通过搜索app2.YourModel以查找迁移,例如:
class Migration(migrations.Migration):
dependencies = [
('otherapp', '0001_initial'),
]
operations = [
migrations.AlterField(
model_name='relatedmodel',
name='fieldname',
field=models.ForeignKey(... to='app2.YourModel'),
),
]
Run Code Online (Sandbox Code Playgroud)将CreateModel迁移添加为依赖项:
class Migration(migrations.Migration):
dependencies = [
('otherapp', '0001_initial'),
('app2', '0002_auto_<date>'),
]
Run Code Online (Sandbox Code Playgroud)从中删除模型 app1
makemigrations并包装app1迁移state_operations.
ForeignKey迁移(即AlterField)添加依赖项(可能包括迁移app1和app2).DeleteTable已经依赖于AlterField迁移,因此我不需要手动强制执行(即Alter之前Delete).在这一点上,Django很高兴.新模型指向旧表,Django的迁移使其确信所有内容都已正确重新定位.最重要的警告(来自@ Michael的回答)是ContentType为新模型创建了一个新的.如果您链接(例如,通过ForeignKey)内容类型,则需要创建迁移以更新ContentType表.
我想在自己之后进行清理(元选项和表名),所以我使用了以下程序(来自@Michael):
db_tableMeta条目makemigrations再次运行以生成数据库重命名DeleteTable迁移.它似乎不应该是必要的,因为它Delete应该是纯逻辑的,但app1_yourmodel如果我不这样做,我会遇到错误(例如,不存在).