tablas migraciones datos borrar django django-models django-1.7 django-migrations

datos - ¿Cómo agregar un nuevo campo a un modelo con nuevas migraciones de Django?



django+base de datos (3)

Estoy utilizando el método contribute_to_class clase pero no sé cómo crear el campo en la base de datos con nuevas migraciones.


Para poder hacer eso y tener el archivo de migración ubicado en la aplicación donde realmente agrego el campo en lugar de tener la migración ubicada dentro de la aplicación a la que pertenece el modelo, tuve que escribir mi propia clase base de Migración.

Si utiliza contribute_to_class dentro de la misma aplicación que el modelo original, la respuesta de @nima funciona a la perfección, aunque no veo el punto de utilizar contrib_contro_clase.

Aquí está el código. Es el código original de Django adaptado para migrar un modelo de self.migrated_app lugar de 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

Con esta nueva clase de Migración ubicada en base.utils una migración escrita a mano se vería así. También puede dejar que Django escriba la migración por usted dentro de la aplicación "incorrecta", mueva el archivo y actualícelo para usar la clase de migración personalizada:

# -*- 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, ), ]

Clase de migración personalizada para 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


Para responder a su pregunta, con la nueva migración introducida en Django 1.7 , para agregar un nuevo campo a un modelo, simplemente puede agregar ese campo a su modelo e iniciar migraciones con ./manage.py makemigrations y luego ejecutar ./manage.py migrate y el nuevo campo se agregará a tu base de datos.

Sin embargo, para evitar lidiar con los errores de sus modelos existentes, puede usar --fake :

  1. Inicialice las migraciones para sus modelos existentes:

    ./manage.py makemigrations myapp

  2. Migraciones falsas para modelos existentes:

    ./manage.py migrate --fake myapp

  3. Agregue el nuevo campo a myapp.models:

    from django.db import models class MyModel(models.Model): ... #existing fields newfield = models.CharField(max_length=100) #new field

  4. Ejecute makemigrations de nuevo (esto agregará un nuevo archivo de migración en la carpeta de migraciones que agregará el campo nuevo a db):

    ./manage.py makemigrations myapp

  5. Ejecutar migrar de nuevo:

    ./manage.py migrate myapp


Puedes crear así:

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)

Consulte " Inyección de campo del modelo Django " para obtener más información.