Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Django & South: Custom field methods are not executed when doing obj.save() in a data migration

In my Django model I have two fields, name (a regular CharField) and slug, a custom field that generates the slug based on a field name passed in the field definition, in this case I use name for this.

First, the model only had the name field, with it's corresponding migrations and all. Then I needed to add the slug field, so following South conventions, I added the slug field with unique=False, create the schema migration, then created a data migration, set the unique=True and create another migration for this last change.

Since the value of the slug is generated on model save, in the forwards method of the data migration what I did was to iterate over the queryset returned by orm['myapp.MyModel'].objects.all() and calling the save() method on each instance.

But the value of the slug field is never generated. Under an IPython session I did the same thing, but referencing the model as from myapp.models import MyModel, and worked. Using some debug statements, printing the type of the model returned by South's orm dict shows the real class, it doesn't appear to be an fake model constructed on the fly by South.

The slug field creates it's value when the pre_save method. How to force it to be called during a data migration? I need to ensure the uniqueness of the value so when the index is applied in a later schema migration, the columns doesn't contains duplicate values.

Thanks!

BTW: The slug field class does define the south_field_triple so South plays nice with it.

EDIT: Please see my answer. But more like an answer, it feels more like a hack. Is there a better/right way to do this?

like image 516
Armando Pérez Marqués Avatar asked Jul 16 '12 13:07

Armando Pérez Marqués


People also ask

What is Django used for?

What is Django? Django is a high-level Python web framework that enables rapid development of secure and maintainable websites. Built by experienced developers, Django takes care of much of the hassle of web development, so you can focus on writing your app without needing to reinvent the wheel.

Was Django a true story?

The wildly popular Django Unchained is the most talked about film of the last month, and aside from the controversy, it's popular because of how badass Django is. However, nobody knew about the real Django–a man named Bass Reeves–whom became a Deputy U.S. Marshal in 1875 at the age of 38.

Is Python and Django same?

Python has a set of language and object-oriented approach that helps programmers create clear and logical code. Django is a web development python framework that makes it easy to build powerful web applications. The platform comes with useful built-in features found at the Django Admin Interface.

Is Django front end or backend?

“The technically correct answer,” Willison told me when I asked him about this, “is that a backend framework like Django works with any frontend framework, because of separation of concerns: if a web framework can respond to HTTP requests with JSON and HTML, it can be used with anything.”


1 Answers

Generally you should explicitly replicate the code that generates the field's contents as closely as possible in the migration (A rare example of purposeful code duplication). The code in your approach, even if it worked, would call pre_save as defined at the time of executing the migration, which may have changed or even fail with the models state at the time the migration was created (It may depend on other fields not being present at an earlier time etc.).

So the correct approach in you example would be to use slugify() directly, as it is done in the SlugField's pre_save method:

from django.template.defaultfilters import slugify

class Migration(DataMigration):

    def forwards(self, orm):
        "Write your forwards methods here."

        for myobj in orm['myapp.MyModel'].objects.all():
            myobj.slug = slugify(myobj.otherfield)
            myobj.save()
like image 119
Florian Ledermann Avatar answered Sep 19 '22 23:09

Florian Ledermann