Django & South: custom field methods are not executed when obj.save () is executed when data is migrated

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

Firstly, the model had only the name field, with it the corresponding migrations and that’s it. Then I needed to add the slug field, so, following the conventions of the South, I added the slug field with unique=False , creating a schema migration, then created a data migration, set unique=True and created a new migration for this last change.

Since the slug value is generated when the model is saved, in the data transfer forwards method, I did this to orm['myapp.MyModel'].objects.all() over the query returned by orm['myapp.MyModel'].objects.all() and call the save() method for each instance.

But the value of the slug field is never generated. In an IPython session, I did the same, but referenced the model as from myapp.models import MyModel and worked. Using some debug operators, printing the type model returned by the southern dict form shows the real class; it does not seem to be a fake model built on the fly by the South.

The slug field creates its value with the pre_save method. How to force it to be called during data migration? I need to ensure that the value is unique, so when the index is applied during subsequent migration of the schema, the columns do not contain duplicate values.

Thanks!

BTW: the slug field class defines south_field_triple , so South plays well with it.

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

+6
source share
2 answers

As a rule, you should explicitly copy the code that generates the contents of the field as much as possible during the migration process (a rare example of targeted duplication of code). The code in your approach, even if it worked, will call pre_save, as defined during the migration, which may have changed or even failed with the state of the models during the creation of the migration (this may depend on other fields and not be present in more early time, etc.).

So, the correct approach in your example would be to use slugify () directly, as is done in the pre_save SlugField 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() 
+4
source

I solved this temporarily by getting an instance of the model field and directly calling it pre_save :

 class Migration(DataMigration): def forwards(self, orm): "Write your forwards methods here." # Note: Remember to use orm['appname.ModelName'] rather than "from appname.models..." for myobj in orm['myapp.MyModel'].objects.all(): slug_field = myobj._meta.get_field_by_name('slug')[0] myobj.slug = slug_field.pre_save(myobj, add=False) myobj.save() 

However, for custom fields, it is important that this be taken into account ...

+1
source

Source: https://habr.com/ru/post/920590/


All Articles