我使用contribute_to_class
方法,但我不知道如何使用新的迁移在数据库中创建字段。
答案 0 :(得分:55)
要回答您的问题,使用 Django 1.7 中引入的新迁移,为了向模型添加新字段,您只需将该字段添加到模型中并使用{{1初始化迁移然后运行./manage.py makemigrations
,新字段将添加到您的数据库中。
为避免处理现有模型的错误,您可以使用./manage.py migrate
:
初始化现有模型的迁移:
--fake
现有模型的虚假迁移:
./manage.py makemigrations myapp
将新字段添加到myapp.models:
./manage.py migrate --fake myapp
再次运行makemigrations(这将在迁移文件夹中添加一个新的迁移文件,将新字段添加到db):
from django.db import models
class MyModel(models.Model):
... #existing fields
newfield = models.CharField(max_length=100) #new field
再次运行迁移:
./manage.py makemigrations myapp
答案 1 :(得分:6)
为了能够做到这一点并让迁移文件位于我实际添加字段的应用程序中,而不是让迁移位于模型所属的应用程序内部,我必须编写自己的Migration基类。
如果您在与原始模型相同的应用程序中使用contribute_to_class
,@ nima的答案可以完美运行,但我当时没有看到使用contribute_to_class
的重点。
这是代码。这是Django的原始代码,适用于从self.migrated_app
而不是self.app_label
迁移模型:
from django.db import migrations
class Migration(migrations.Migration):
migrated_app = None
def __init__(self, name, app_label):
super(Migration,self).__init__(name, app_label)
if self.migrated_app is None:
self.migrated_app = self.app_label
def mutate_state(self, project_state):
new_state = project_state.clone()
for operation in self.operations:
operation.state_forwards(self.migrated_app, new_state)
return new_state
def apply(self, project_state, schema_editor, collect_sql=False):
for operation in self.operations:
if collect_sql and not operation.reduces_to_sql:
schema_editor.collected_sql.append("--")
schema_editor.collected_sql.append("-- MIGRATION NOW PERFORMS OPERATION THAT CANNOT BE WRITTEN AS SQL:")
schema_editor.collected_sql.append("-- %s" % operation.describe())
schema_editor.collected_sql.append("--")
continue
new_state = project_state.clone()
operation.state_forwards(self.migrated_app, new_state)
if not schema_editor.connection.features.can_rollback_ddl and operation.atomic:
with atomic(schema_editor.connection.alias):
operation.database_forwards(self.migrated_app, schema_editor, project_state, new_state)
else:
operation.database_forwards(self.migrated_app, schema_editor, project_state, new_state)
project_state = new_state
return project_state
def unapply(self, project_state, schema_editor, collect_sql=False):
to_run = []
for operation in self.operations:
if collect_sql and not operation.reduces_to_sql:
schema_editor.collected_sql.append("--")
schema_editor.collected_sql.append("-- MIGRATION NOW PERFORMS OPERATION THAT CANNOT BE WRITTEN AS SQL:")
schema_editor.collected_sql.append("-- %s" % operation.describe())
schema_editor.collected_sql.append("--")
continue
if not operation.reversible:
raise Migration.IrreversibleError("Operation %s in %s is not reversible" % (operation, self))
new_state = project_state.clone()
operation.state_forwards(self.migrated_app, new_state)
to_run.append((operation, project_state, new_state))
project_state = new_state
to_run.reverse()
for operation, to_state, from_state in to_run:
if not schema_editor.connection.features.can_rollback_ddl and operation.atomic:
with atomic(schema_editor.connection.alias):
operation.database_backwards(self.migrated_app, schema_editor, from_state, to_state)
else:
operation.database_backwards(self.migrated_app, schema_editor, from_state, to_state)
return project_state
使用位于base.utils
的新迁移类,手写迁移将如下所示。你也可以让Django在“错误的”应用程序中为你编写迁移,移动文件并更新它以使用自定义的Migration类:
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import models, migrations
from base.utils import Migration
import dynamicsites.fields
class Migration(Migration):
dependencies = [
('sites', '0001_initial'),
('base', '0001_initial'),
]
migrated_app = 'sites'
operations = [
migrations.AddField(
model_name='site',
name='folder_name',
field=dynamicsites.fields.FolderNameField(default='', help_text=b"Folder name for this site's files. The name may only consist of lowercase characters, numbers (0-9), and/or underscores", max_length=64, blank=True),
preserve_default=False,
),
migrations.AddField(
model_name='site',
name='subdomains',
field=dynamicsites.fields.SubdomainListField(default=(), help_text=b'Comma separated list of subdomains this site supports. Leave blank to support all subdomains', blank=True),
preserve_default=False,
),
]
Django 1.8的自定义迁移类
from django.db import migrations
class Migration(migrations.Migration):
migrated_app = None
def __init__(self, name, app_label):
super(Migration,self).__init__(name, app_label)
if self.migrated_app is None:
self.migrated_app = self.app_label
def __eq__(self, other):
if not isinstance(other, Migration):
if not isinstance(other, migrations.Migration):
return False
return (self.name == other.name) and (self.migrated_app == other.app_label)
return (self.name == other.name) and (self.migrated_app == other.migrated_app)
def __hash__(self):
return hash("%s.%s" % (self.app_label, self.name))
def mutate_state(self, project_state, preserve=True):
new_state = project_state
if preserve:
new_state = project_state.clone()
for operation in self.operations:
operation.state_forwards(self.migrated_app, new_state)
return new_state
def apply(self, project_state, schema_editor, collect_sql=False):
for operation in self.operations:
if collect_sql and not operation.reduces_to_sql:
schema_editor.collected_sql.append("--")
schema_editor.collected_sql.append("-- MIGRATION NOW PERFORMS OPERATION THAT CANNOT BE "
"WRITTEN AS SQL:")
schema_editor.collected_sql.append("-- %s" % operation.describe())
schema_editor.collected_sql.append("--")
continue
old_state = project_state.clone()
operation.state_forwards(self.migrated_app, project_state)
if not schema_editor.connection.features.can_rollback_ddl and operation.atomic:
with atomic(schema_editor.connection.alias):
operation.database_forwards(self.migrated_app, schema_editor, old_state, project_state)
else:
operation.database_forwards(self.migrated_app, schema_editor, old_state, project_state)
return project_state
def unapply(self, project_state, schema_editor, collect_sql=False):
to_run = []
new_state = project_state
for operation in self.operations:
if not operation.reversible:
raise Migration.IrreversibleError("Operation %s in %s is not reversible" % (operation, self))
new_state = new_state.clone()
old_state = new_state.clone()
operation.state_forwards(self.migrated_app, new_state)
to_run.insert(0, (operation, old_state, new_state))
for operation, to_state, from_state in to_run:
if collect_sql:
if not operation.reduces_to_sql:
schema_editor.collected_sql.append("--")
schema_editor.collected_sql.append("-- MIGRATION NOW PERFORMS OPERATION THAT CANNOT BE "
"WRITTEN AS SQL:")
schema_editor.collected_sql.append("-- %s" % operation.describe())
schema_editor.collected_sql.append("--")
continue
if not schema_editor.connection.features.can_rollback_ddl and operation.atomic:
with atomic(schema_editor.connection.alias):
operation.database_backwards(self.migrated_app, schema_editor, from_state, to_state)
else:
operation.database_backwards(self.migrated_app, schema_editor, from_state, to_state)
return project_state
答案 2 :(得分:3)
您可以这样创建:
from django.db.models import CharField
from django.db.models.signals import class_prepared
def add_field(sender, **kwargs):
"""
class_prepared signal handler that checks for the model named
MyModel as the sender, and adds a CharField
to it.
"""
if sender.__name__ == "MyModel":
field = CharField("New field", max_length=100)
field.contribute_to_class(sender, "new_field")
class_prepared.connect(add_field)
有关详细信息,请参阅“Django Model Field Injection”。
答案 3 :(得分:0)
hollo 如果要更改现有模型,您可以将文件添加到模型中,如果数据可用于同一数据库表,请确保文件允许空白
Django==3.2.5
我的模型代码
from django.db import models
# Create your models here.
from django.db import models
class slider_item(models.Model):
title = models.CharField(max_length=100 ,blank=True)
description = models.TextField(blank=True)
image = models.ImageField(blank=True)
我添加了新的 image = models.ImageField(blank=True) 该表上可用的模型表数据所以需要 (blank=True)
page_home 是我的 django 应用名称(你已经给出了你的应用名称)
$ python manage.py migrate
** 迁移完成 **