Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    primarykey
    data
    text
    <p><strong>Check out response below by Paul for some notes on compatibility with newer versions of Django/South.</strong></p> <hr> <p>This seemed like an interesting problem, and I'm becoming a big fan of South, so I decided to look into this a bit. I built a test project on the abstract of what you've described above, and have successfully used South to perform the migration you are asking about. Here's a couple of notes before we get to the code:</p> <ul> <li><p>The South documentation recommends doing schema migrations and data migrations separate. I've followed suit in this.</p></li> <li><p>On the backend, Django represents an inherited table by automatically creating a OneToOne field on the inheriting model</p></li> <li><p>Understanding this, our South migration needs to properly handle the OneToOne field manually, however, in experimenting with this it seems that South (or perhaps Django itself) cannot create a OneToOne filed on multiple inherited tables with the same name. Because of this, I renamed each child-table in the movies/tv app to be respective to it's own app (ie. MovieVideoFile/ShowVideoFile).</p></li> <li><p>In playing with the actual data migration code, it seems South prefers to create the OneToOne field first, and then assign data to it. Assigning data to the OneToOne field during creation cause South to choke. (A fair compromise for all the coolness that is South).</p></li> </ul> <p>So having said all that, I tried to keep a log of the console commands being issued. I'll interject commentary where necessary. The final code is at the bottom.</p> <h2>Command History</h2> <pre><code>django-admin.py startproject southtest manage.py startapp movies manage.py startapp tv manage.py syncdb manage.py startmigration movies --initial manage.py startmigration tv --initial manage.py migrate manage.py shell # added some fake data... manage.py startapp media manage.py startmigration media --initial manage.py migrate # edited code, wrote new models, but left old ones intact manage.py startmigration movies unified-videofile --auto # create a new (blank) migration to hand-write data migration manage.py startmigration movies videofile-to-movievideofile-data manage.py migrate # edited code, wrote new models, but left old ones intact manage.py startmigration tv unified-videofile --auto # create a new (blank) migration to hand-write data migration manage.py startmigration tv videofile-to-movievideofile-data manage.py migrate # removed old VideoFile model from apps manage.py startmigration movies removed-videofile --auto manage.py startmigration tv removed-videofile --auto manage.py migrate </code></pre> <p>For space sake, and since the models invariably look the same in the end, I'm only going to demonstrate with 'movies' app.</p> <h2>movies/models.py</h2> <pre><code>from django.db import models from media.models import VideoFile as BaseVideoFile # This model remains until the last migration, which deletes # it from the schema. Note the name conflict with media.models class VideoFile(models.Model): movie = models.ForeignKey(Movie, blank=True, null=True) name = models.CharField(max_length=1024, blank=True) size = models.IntegerField(blank=True, null=True) ctime = models.DateTimeField(blank=True, null=True) class MovieVideoFile(BaseVideoFile): movie = models.ForeignKey(Movie, blank=True, null=True, related_name='shows') </code></pre> <h2>movies/migrations/0002_unified-videofile.py (schema migration)</h2> <pre><code>from south.db import db from django.db import models from movies.models import * class Migration: def forwards(self, orm): # Adding model 'MovieVideoFile' db.create_table('movies_movievideofile', ( ('videofile_ptr', orm['movies.movievideofile:videofile_ptr']), ('movie', orm['movies.movievideofile:movie']), )) db.send_create_signal('movies', ['MovieVideoFile']) def backwards(self, orm): # Deleting model 'MovieVideoFile' db.delete_table('movies_movievideofile') </code></pre> <h2>movies/migration/0003_videofile-to-movievideofile-data.py (data migration)</h2> <pre><code>from south.db import db from django.db import models from movies.models import * class Migration: def forwards(self, orm): for movie in orm['movies.videofile'].objects.all(): new_movie = orm.MovieVideoFile.objects.create(movie = movie.movie,) new_movie.videofile_ptr = orm['media.VideoFile'].objects.create() # videofile_ptr must be created first before values can be assigned new_movie.videofile_ptr.name = movie.name new_movie.videofile_ptr.size = movie.size new_movie.videofile_ptr.ctime = movie.ctime new_movie.videofile_ptr.save() def backwards(self, orm): print 'No Backwards' </code></pre> <h2>South is awesome!</h2> <p>Ok standard disclaimer: You're dealing with live data. I've given you working code here, but please use the <code>--db-dry-run</code> to test your schema. Always make a backup before trying anything, and generally be careful.</p> <p><strong>COMPATIBILITY NOTICE</strong></p> <p>I'm going to keep my original message intact, but South has since changed the command <code>manage.py startmigration</code> into <code>manage.py schemamigration</code>.</p>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. VO
      singulars
      1. This table or related slice is empty.
    2. VO
      singulars
      1. This table or related slice is empty.
    3. VO
      singulars
      1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload