Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

django model save - override method not invoked during migrations

I have a save override method in my model class, which generates a new slug each time an object is saved.

def save(self, *args, **kwargs):
    if self.column2:
        self.slug = slugify(self.column1 + " " + self.column2)
    else:
        self.slug = slugify(self.column1)
    print slug
    super(MyModel, self).save(*args, **kwargs)

When I try to create a new object by logging into the python shell, I see the save method is being invoked.

python manage.py shell

>>> MyModel(column1="test",column2="2015").save()
slug is test-2015

However when I am running a migration, this save override method is not being called. Here's part of my migration script..

...
def add_myModel_details(apps, schema_editor):
    x = apps.get_model("myapp","myModel")
    MyModel(column1 = "test", column2="2015" ).save()
.....

The slug is empty, as the save override isn't being called.

like image 301
Rajesh Chamarthi Avatar asked Aug 14 '15 13:08

Rajesh Chamarthi


People also ask

How do you override the Save method of a model?

save() method from its parent class is to be overridden so we use super keyword. slugify is a function that converts any string into a slug.

What is the difference between makemigrations and migrate in Django?

migrate , which is responsible for applying and unapplying migrations. makemigrations , which is responsible for creating new migrations based on the changes you have made to your models.

How to squash Django migrations?

In Django's migrations code, there's a squashmigrations command which: "Squashes the migrations for app_label up to and including migration_name down into fewer migrations, if possible." So, if you want to squash, say, the first 5 migrations, this will help.


2 Answers

Custom model methods are not available during migrations.

Instead, you can run put code in your RunPython function that modifies your model instances the way the custom save() would have.

References:

  • This answer
like image 60
Flimm Avatar answered Sep 18 '22 20:09

Flimm


It happens because migrations don't call your save method.

I think save method is not the best place for generate slug. Will be better to use AutoSlugField or signals.

1. signals:

In your case you may use signal pre_save.

Example:

@receiver(pre_save, sender=MyModel)
def my_handler(sender, **kwargs):
    my_model = kwargs.get('instance')
    if my_model.column2:
        my_model.slug = slugify(my_model.column1 + " " + my_model.column2)
    else:
        my_model.slug = slugify(my_model.column1)
    print my_model.slug

2. AutoSlugField:

It's not a standard field but a lot of libraries implement it. I use AutoSlugField from django-extensions. This field uses signals too.

Example:

slug = AutoSlugField(populate_from=("column1", "column2"))

3. save method and migrations

But if you still want to use a save method to generating slug I'd recommend you create data migration and add slugs manually.

Data Migrations django >= 1.7

Data Migrations south

like image 44
Kirill Ermolov Avatar answered Sep 18 '22 20:09

Kirill Ermolov