I've got a model
class Category(models.Model):
title = models.CharField(...)
entry = models.ManyToManyField(Entry,null=True,blank=True,
related_name='category_entries',
)
That I wish to refactor to have additional data with each relationship:
class Category(models.Model):
title = models.CharField(...)
entry = models.ManyToManyField(Entry,null=True,blank=True,
related_name='category_entries',
through='CategoryEntry',
)
But south deletes the existing table. How can I preserve the existing m-t-m relationships?
Create your intermediate model without any extra fields, for now. Give it a unique constraint to match the existing one and specify the table name to match the existing one:
class CategoryEntry(models.Model):
category = models.ForeignKey(Category)
entry = models.ForeignKey(Entry)
class Meta:
db_table='main_category_entries' #change main_ to your application
unique_together = (('category', 'entry'))
Run the South schema migration.
Edit the generated schema migration script and comment-out all the forwards and backwards entries, since you'll be re-using the existing intersection table. Add pass
to complete the methods.
Run the migration.
Update any existing code. As it says in https://docs.djangoproject.com/en/dev/topics/db/models/#many-to-many-relationships, "Unlike normal many-to-many fields, you can't use add, create, or assignment to create relationships" so you'll need to modify any existing application code, e.g.
c.entry.add(e)
could become:
try:
categoryentry = c.categoryentry_set.get(entry = e)
except CategoryEntry.DoesNotExist:
categoryentry = CategoryEntry(category=c, entry=e)
categoryentry.save()
and:
e.category_entries.add(c)
could become:
categoryentry = CategoryEntry(category=c, entry=e) #set extra fields here
categoryentry.save()
and:
c.entry.remove(e)
could become:
categoryentry = c.categoryentry_set.get(entry = e)
categoryentry.delete()
Once this initial pseudo migration has been done, you should then be able to add the extra fields to the CategoryEntry
and create further migrations as normal.