I'm creating a data migration using the RunPython
method. However when I try to run a method on the object none are defined. Is it possible to call a method defined on a model using RunPython
?
makemigrations is responsible for packaging up your model changes into individual migration files - analogous to commits - and migrate is responsible for applying those to your database.
To answer your question, with the new migration introduced in Django 1.7, in order to add a new field to a model you can simply add that field to your model and initialize migrations with ./manage.py makemigrations and then run ./manage.py migrate and the new field will be added to your DB.
--fake-initialAllows Django to skip an app's initial migration if all database tables with the names of all models created by all CreateModel operations in that migration already exist. This option is intended for use when first running migrations against a database that preexisted the use of migrations.
Model methods are not available in migrations, including data migrations.
However there is workaround, which should be quite similar to calling model methods. You can define functions inside migrations that mimic those model methods you want to use.
If you had this method:
class Order(models.Model): ''' order model def goes here ''' def get_foo_as_bar(self): new_attr = 'bar: %s' % self.foo return new_attr
You can write function inside migration script like:
def get_foo_as_bar(obj): new_attr = 'bar: %s' % obj.foo return new_attr def save_foo_as_bar(apps, schema_editor): old_model = apps.get_model("order", "Order") for obj in old_model.objects.all(): obj.new_bar_field = get_foo_as_bar(obj) obj.save()
Then use it in migrations:
class Migration(migrations.Migration): dependencies = [ ('order', '0001_initial'), ] operations = [ migrations.RunPython(save_foo_as_bar) ]
This way migrations will work. There will be bit of repetition of code, but it doesn't matter because data migrations are supposed to be one time operation in particular state of an application.
did you call your model like said in the documentation ?
def combine_names(apps, schema_editor): # We can't import the Person model directly as it may be a newer # version than this migration expects. We use the historical version. Person = apps.get_model("yourappname", "Person") for person in Person.objects.all(): person.name = "%s %s" % (person.first_name, person.last_name) person.save()
Data-Migration Because at this point, you can't import your Model directly :
from yourappname.models import Person
Update
The internal Django code is in this file django/db/migrations/state.py django.db.migrations.state.ModelState#construct_fields
def construct_fields(self): "Deep-clone the fields using deconstruction" for name, field in self.fields: _, path, args, kwargs = field.deconstruct() field_class = import_string(path) yield name, field_class(*args, **kwargs)
There is only fields that are clones in a "fake" model instance:
MyModel.__module__ = '__fake__'
Github Django
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With