views:

290

answers:

2

I'd like to refactor a number of django apps in a way which involves moving Models from one app into another where they can be more readily reused.

A number of these models have either ForeignKey relationships or M2M relationships to other models (such as User). For example:

class Department(models.Model):
    name = models.CharField(max_length=255)
    reviewers = models.ManyToManyField(User)

In most cases, the models do not change, so I've currently just redefined them in the new app. This of course causes problems with related_name, since I have the same model defined in two separate apps, and manage.py syncdb gives the following error:

new_app.department: Accessor for m2m field 'reviewers' clashes with related m2m field 'User.department_set'. Add a related_name argument to the definition for 'reviewers'.
old_app.department: Accessor for m2m field 'reviewers' clashes with related m2m field 'User.department_set'. Add a related_name argument to the definition for 'reviewers'.

When doing this, I also need to migrate the data keeping any automatically generated database ids. I'd planned on using the ORM to do the migration, thinking something like the following would work:

from newapp.models import Department
import oldapp.models as old

for obj in old.Department.objects.all():
    new_obj = Department(id=obj.id, name=obj.name)
    new_obj.save()
    for r in obj.reviewers.all():
        new_obj.reviewers.add(r)
    new_obj.save()

Of course, the related_name problem prevents me from doing this.

How have others made this sort of code refactor and migration possible? Thanks!

+4  A: 

Have you looked at using a migration tool such as South or django-evolution?

Vinay Sajip
I know of south, but thought that it just modified table schemas (but not data). Does it transfer data as well?
Brad Montgomery
Yes, South has a very nice system for doing data migrations, including "freezing" old versions of models so that data migrations will continue to work even much later after the actual models look different.
Carl Meyer
After having read the South tutorial (and more), I think this is definitely the way to go. Thanks.
Brad Montgomery
A: 

You can very easily solve the immediate problem by just providing a related_name argument to the ForeignKey in either the new or old model, exactly as the error message tells you to. Not confident that will solve all your problems with this migration, but it will take you one step forward.

Carl Meyer
I actually have several (probably around 10) models from 3 different apps that I want to pull all into 1 shared app... I suppose I could set temporary related_names for the old models, do the migration, and then remove the old models. I'm assuming this would allow me to leave all other code intact.
Brad Montgomery
Yup, shouldn't need to change any code if you add related_name to the old model's ForeignKey. Other things will temporarily break because there won't be any data in the new tables, but you'll fix that pretty quick.
Carl Meyer