[extensions-web/django/upgrade-1.8] django: update to 1.7.



commit a266e154387b2c314caecac0037dea6122ad9e2e
Author: Yuri Konotopov <ykonotopov gnome org>
Date:   Tue Oct 25 00:23:04 2016 +0300

    django: update to 1.7.
    
    Also bumped django-registration to 2.0 and autoslug to 1.7.2.
    Dropped South as it was superseeded by Django migrations.

 bin/sweettooth-cron-update                         |    3 +
 requirements.txt                                   |    7 +-
 sweettooth/auth/__init__.py                        |    1 +
 sweettooth/auth/apps.py                            |    5 +
 sweettooth/auth/forms.py                           |    6 +-
 sweettooth/errorreports/migrations/0001_initial.py |  125 +++-----------
 .../0002_auto__del_field_errorreport_errors.py     |    0
 .../0003_auto__del_field_errorreport_email.py      |    0
 ...0004_auto__add_field_errorreport_can_contact.py |    0
 ...ort_version__add_field_errorreport_extension.py |    0
 ...0006_auto__del_field_errorreport_can_contact.py |    0
 sweettooth/extensions/migrations/0001_initial.py   |  189 +++++++++-----------
 sweettooth/extensions/models.py                    |   30 ++--
 .../0001_initial.py}                               |   54 +++---
 .../0002_auto__add_shellversion.py                 |    0
 .../0003_auto__add_field_extension_icon.py         |    0
 ...004_auto__chg_field_extensionversion_version.py |    0
 .../0005_auto__add_errorreport.py                  |    0
 .../0006_auto__del_errorreport.py                  |    0
 ...ersion_source__chg_field_extensionversion_ve.py |    0
 .../0008_new_icon_default.py                       |    0
 .../0009_icon_and_screenshot_names.py              |    0
 .../0010_auto__add_field_extension_downloads.py    |    0
 ...enables__add_field_extension_disables__add_f.py |    0
 .../0012_add_extensionpopularityitem.py            |    0
 .../0013_move_to_popularity_items.py               |    0
 ...el_extension_enables_disables_and_popularity.py |    0
 .../0017_auto__add_field_extension_popularity.py   |    0
 .../0018_new_to_unreviewed.py                      |    0
 .../0019_auto__chg_field_extension_screenshot.py   |    0
 .../extensions/testdata/test_upgrade_data.json     |  150 +++++++++++++++-
 sweettooth/extensions/views.py                     |   64 ++++---
 sweettooth/ratings/forms.py                        |    2 +-
 sweettooth/ratings/migrations/0001_initial.py      |  106 ++---------
 .../0001_initial.py}                               |   14 +-
 .../0002_auto__chg_field_ratingcomment_rating.py   |    0
 sweettooth/review/migrations/0001_initial.py       |  129 +++-----------
 .../0001_initial.py}                               |   17 ++-
 .../0002_auto__del_field_codereview_newstatus.py   |    0
 .../0003_auto__add_changestatuslog.py              |    0
 .../0004_auto__add_field_codereview_changelog.py   |    0
 ...uto__add_field_changestatuslog_auto_approved.py |    0
 ...__rename_field_changestatuslog_auto_approved.py |    0
 .../0007_remove_changestatuslog.py                 |    0
 ..._newstatus__add_field_codereview_new_status_.py |    0
 sweettooth/settings.py                             |    2 -
 sweettooth/urls.py                                 |    2 +
 47 files changed, 425 insertions(+), 481 deletions(-)
---
diff --git a/bin/sweettooth-cron-update b/bin/sweettooth-cron-update
index b3e382f..88183cd 100755
--- a/bin/sweettooth-cron-update
+++ b/bin/sweettooth-cron-update
@@ -4,6 +4,7 @@ import datetime
 
 import os
 import sys
+import django
 
 _path = os.path.dirname(__file__)
 
@@ -14,6 +15,8 @@ sys.path.extend([os.path.join(_path, '..'),
 from django.db.models import Sum
 from sweettooth.extensions.models import Extension
 
+django.setup()
+
 for ext in Extension.objects.all():
     data = (ext.popularity_items
             .filter(date__gt=(datetime.datetime.now()-datetime.timedelta(days=7)))
diff --git a/requirements.txt b/requirements.txt
index 8792736..efa6eb7 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -1,8 +1,7 @@
-Django==1.5.12
-django-autoslug==1.5.0
-django-registration==1.0
+Django==1.7.11
+django-autoslug==1.7.2
+django-registration==2.0
 Pygments==1.6
 wsgiref==0.1.2
-South==0.7.6
 sorl-thumbnail
 pillow
diff --git a/sweettooth/auth/__init__.py b/sweettooth/auth/__init__.py
index e69de29..8247c17 100644
--- a/sweettooth/auth/__init__.py
+++ b/sweettooth/auth/__init__.py
@@ -0,0 +1 @@
+default_app_config = 'sweettooth.auth.apps.AuthConfig'
diff --git a/sweettooth/auth/apps.py b/sweettooth/auth/apps.py
new file mode 100644
index 0000000..a2ebcb8
--- /dev/null
+++ b/sweettooth/auth/apps.py
@@ -0,0 +1,5 @@
+from django.apps import AppConfig
+
+class AuthConfig(AppConfig):
+    name = 'sweettooth.auth'
+    label = 'sweettooth_auth'
diff --git a/sweettooth/auth/forms.py b/sweettooth/auth/forms.py
index 162fea0..ea3ff4b 100644
--- a/sweettooth/auth/forms.py
+++ b/sweettooth/auth/forms.py
@@ -1,5 +1,5 @@
 
-from django.db.models import forms
+from django import forms
 from django.contrib.auth import forms as auth_forms
 from django.utils.translation import ugettext_lazy as _
 from registration.forms import RegistrationForm
@@ -16,7 +16,9 @@ class PlainOutputForm(object):
 class AutoFocusForm(object):
     def __init__(self, *a, **kw):
         super(AutoFocusForm, self).__init__(*a, **kw)
-        self.fields.value_for_index(0).widget.attrs['autofocus'] = True
+        for field in self.fields:
+            self.fields[field].widget.attrs['autofocus'] = True
+            break
 
 class InlineForm(object):
     def __init__(self, *a, **kw):
diff --git a/sweettooth/errorreports/migrations/0001_initial.py 
b/sweettooth/errorreports/migrations/0001_initial.py
index 71b7bc5..92b93a7 100644
--- a/sweettooth/errorreports/migrations/0001_initial.py
+++ b/sweettooth/errorreports/migrations/0001_initial.py
@@ -1,107 +1,28 @@
-# encoding: utf-8
-import datetime
-from south.db import db
-from south.v2 import SchemaMigration
-from django.db import models
+# -*- coding: utf-8 -*-
+from __future__ import unicode_literals
 
-class Migration(SchemaMigration):
+from django.db import models, migrations
+from django.conf import settings
 
-    def forwards(self, orm):
-        
-        # Adding model 'ErrorReport'
-        db.create_table('errorreports_errorreport', (
-            ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
-            ('comment', self.gf('django.db.models.fields.TextField')(blank=True)),
-            ('errors', self.gf('django.db.models.fields.TextField')(blank=True)),
-            ('email', self.gf('django.db.models.fields.EmailField')(max_length=75, blank=True)),
-            ('user', self.gf('django.db.models.fields.related.ForeignKey')(related_name='+', blank=True, 
to=orm['auth.User'])),
-            ('version', 
self.gf('django.db.models.fields.related.ForeignKey')(to=orm['extensions.ExtensionVersion'])),
-        ))
-        db.send_create_signal('errorreports', ['ErrorReport'])
 
+class Migration(migrations.Migration):
 
-    def backwards(self, orm):
-        
-        # Deleting model 'ErrorReport'
-        db.delete_table('errorreports_errorreport')
+    dependencies = [
+        ('extensions', '0001_initial'),
+        migrations.swappable_dependency(settings.AUTH_USER_MODEL),
+    ]
 
-
-    models = {
-        'auth.group': {
-            'Meta': {'object_name': 'Group'},
-            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
-            'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}),
-            'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': 
"orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'})
-        },
-        'auth.permission': {
-            'Meta': {'ordering': "('content_type__app_label', 'content_type__model', 'codename')", 
'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'},
-            'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
-            'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': 
"orm['contenttypes.ContentType']"}),
-            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
-            'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
-        },
-        'auth.user': {
-            'Meta': {'object_name': 'User'},
-            'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 
'datetime.datetime.now'}),
-            'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),
-            'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
-            'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 
'symmetrical': 'False', 'blank': 'True'}),
-            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
-            'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
-            'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
-            'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
-            'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 
'datetime.datetime.now'}),
-            'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
-            'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
-            'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': 
"orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}),
-            'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'})
-        },
-        'contenttypes.contenttype': {
-            'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 
'ContentType', 'db_table': "'django_content_type'"},
-            'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
-            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
-            'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
-            'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
-        },
-        'errorreports.errorreport': {
-            'Meta': {'object_name': 'ErrorReport'},
-            'comment': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
-            'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),
-            'errors': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
-            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
-            'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'+'", 'blank': 
'True', 'to': "orm['auth.User']"}),
-            'version': ('django.db.models.fields.related.ForeignKey', [], {'to': 
"orm['extensions.ExtensionVersion']"})
-        },
-        'extensions.extension': {
-            'Meta': {'object_name': 'Extension'},
-            'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 
'True'}),
-            'creator': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"}),
-            'description': ('django.db.models.fields.TextField', [], {}),
-            'icon': ('django.db.models.fields.files.ImageField', [], {'default': "''", 'max_length': '100', 
'blank': 'True'}),
-            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
-            'name': ('django.db.models.fields.CharField', [], {'max_length': '200'}),
-            'screenshot': ('sorl.thumbnail.fields.ImageField', [], {'max_length': '100', 'blank': 'True'}),
-            'slug': ('autoslug.fields.AutoSlugField', [], {'unique_with': '()', 'max_length': '50', 
'populate_from': 'None', 'db_index': 'True'}),
-            'url': ('django.db.models.fields.URLField', [], {'max_length': '200'}),
-            'uuid': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '200', 
'db_index': 'True'})
-        },
-        'extensions.extensionversion': {
-            'Meta': {'unique_together': "(('extension', 'version'),)", 'object_name': 'ExtensionVersion'},
-            'extension': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'versions'", 
'to': "orm['extensions.Extension']"}),
-            'extra_json_fields': ('django.db.models.fields.TextField', [], {}),
-            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
-            'shell_versions': ('django.db.models.fields.related.ManyToManyField', [], {'to': 
"orm['extensions.ShellVersion']", 'symmetrical': 'False'}),
-            'source': ('django.db.models.fields.files.FileField', [], {'max_length': '100'}),
-            'status': ('django.db.models.fields.PositiveIntegerField', [], {}),
-            'version': ('django.db.models.fields.IntegerField', [], {'default': '0', 'max_length': '223'})
-        },
-        'extensions.shellversion': {
-            'Meta': {'object_name': 'ShellVersion'},
-            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
-            'major': ('django.db.models.fields.PositiveIntegerField', [], {}),
-            'minor': ('django.db.models.fields.PositiveIntegerField', [], {}),
-            'point': ('django.db.models.fields.IntegerField', [], {})
-        }
-    }
-
-    complete_apps = ['errorreports']
+    operations = [
+        migrations.CreateModel(
+            name='ErrorReport',
+            fields=[
+                ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, 
primary_key=True)),
+                ('comment', models.TextField(blank=True)),
+                ('extension', models.ForeignKey(to='extensions.Extension', null=True)),
+                ('user', models.ForeignKey(related_name='+', to=settings.AUTH_USER_MODEL)),
+            ],
+            options={
+            },
+            bases=(models.Model,),
+        ),
+    ]
diff --git a/sweettooth/errorreports/migrations/0002_auto__del_field_errorreport_errors.py 
b/sweettooth/errorreports/south_migrations/0002_auto__del_field_errorreport_errors.py
similarity index 100%
rename from sweettooth/errorreports/migrations/0002_auto__del_field_errorreport_errors.py
rename to sweettooth/errorreports/south_migrations/0002_auto__del_field_errorreport_errors.py
diff --git a/sweettooth/errorreports/migrations/0003_auto__del_field_errorreport_email.py 
b/sweettooth/errorreports/south_migrations/0003_auto__del_field_errorreport_email.py
similarity index 100%
rename from sweettooth/errorreports/migrations/0003_auto__del_field_errorreport_email.py
rename to sweettooth/errorreports/south_migrations/0003_auto__del_field_errorreport_email.py
diff --git a/sweettooth/errorreports/migrations/0004_auto__add_field_errorreport_can_contact.py 
b/sweettooth/errorreports/south_migrations/0004_auto__add_field_errorreport_can_contact.py
similarity index 100%
rename from sweettooth/errorreports/migrations/0004_auto__add_field_errorreport_can_contact.py
rename to sweettooth/errorreports/south_migrations/0004_auto__add_field_errorreport_can_contact.py
diff --git 
a/sweettooth/errorreports/migrations/0005_auto__del_field_errorreport_version__add_field_errorreport_extension.py
 
b/sweettooth/errorreports/south_migrations/0005_auto__del_field_errorreport_version__add_field_errorreport_extension.py
similarity index 100%
rename from 
sweettooth/errorreports/migrations/0005_auto__del_field_errorreport_version__add_field_errorreport_extension.py
rename to 
sweettooth/errorreports/south_migrations/0005_auto__del_field_errorreport_version__add_field_errorreport_extension.py
diff --git a/sweettooth/errorreports/migrations/0006_auto__del_field_errorreport_can_contact.py 
b/sweettooth/errorreports/south_migrations/0006_auto__del_field_errorreport_can_contact.py
similarity index 100%
rename from sweettooth/errorreports/migrations/0006_auto__del_field_errorreport_can_contact.py
rename to sweettooth/errorreports/south_migrations/0006_auto__del_field_errorreport_can_contact.py
diff --git a/sweettooth/errorreports/south_migrations/__init__.py 
b/sweettooth/errorreports/south_migrations/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/sweettooth/extensions/migrations/0001_initial.py 
b/sweettooth/extensions/migrations/0001_initial.py
index 74858a3..e5139a8 100644
--- a/sweettooth/extensions/migrations/0001_initial.py
+++ b/sweettooth/extensions/migrations/0001_initial.py
@@ -1,112 +1,87 @@
-# encoding: utf-8
-import datetime
-from south.db import db
-from south.v2 import SchemaMigration
-from django.db import models
+# -*- coding: utf-8 -*-
+from __future__ import unicode_literals
 
-class Migration(SchemaMigration):
+from django.db import models, migrations
+import autoslug.fields
+import sweettooth.extensions.models
+from django.conf import settings
 
-    def forwards(self, orm):
-        
-        # Adding model 'Extension'
-        db.create_table('extensions_extension', (
-            ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
-            ('name', self.gf('django.db.models.fields.CharField')(max_length=200)),
-            ('uuid', self.gf('django.db.models.fields.CharField')(unique=True, max_length=200, 
db_index=True)),
-            ('slug', self.gf('autoslug.fields.AutoSlugField')(unique_with=(), max_length=50, 
populate_from=None, db_index=True)),
-            ('creator', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['auth.User'])),
-            ('description', self.gf('django.db.models.fields.TextField')()),
-            ('url', self.gf('django.db.models.fields.URLField')(max_length=200)),
-            ('created', self.gf('django.db.models.fields.DateTimeField')(auto_now_add=True, blank=True)),
-            ('screenshot', self.gf('sorl.thumbnail.fields.ImageField')(max_length=100, blank=True)),
-        ))
-        db.send_create_signal('extensions', ['Extension'])
 
-        # Adding model 'ExtensionVersion'
-        db.create_table('extensions_extensionversion', (
-            ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
-            ('extension', self.gf('django.db.models.fields.related.ForeignKey')(related_name='versions', 
to=orm['extensions.Extension'])),
-            ('version', self.gf('django.db.models.fields.IntegerField')(default=0)),
-            ('extra_json_fields', self.gf('django.db.models.fields.TextField')()),
-            ('status', self.gf('django.db.models.fields.PositiveIntegerField')()),
-            ('source', self.gf('django.db.models.fields.files.FileField')(max_length=100)),
-        ))
-        db.send_create_signal('extensions', ['ExtensionVersion'])
+class Migration(migrations.Migration):
 
-        # Adding unique constraint on 'ExtensionVersion', fields ['extension', 'version']
-        db.create_unique('extensions_extensionversion', ['extension_id', 'version'])
+    dependencies = [
+        migrations.swappable_dependency(settings.AUTH_USER_MODEL),
+    ]
 
-
-    def backwards(self, orm):
-        
-        # Removing unique constraint on 'ExtensionVersion', fields ['extension', 'version']
-        db.delete_unique('extensions_extensionversion', ['extension_id', 'version'])
-
-        # Deleting model 'Extension'
-        db.delete_table('extensions_extension')
-
-        # Deleting model 'ExtensionVersion'
-        db.delete_table('extensions_extensionversion')
-
-
-    models = {
-        'auth.group': {
-            'Meta': {'object_name': 'Group'},
-            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
-            'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}),
-            'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': 
"orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'})
-        },
-        'auth.permission': {
-            'Meta': {'ordering': "('content_type__app_label', 'content_type__model', 'codename')", 
'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'},
-            'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
-            'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': 
"orm['contenttypes.ContentType']"}),
-            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
-            'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
-        },
-        'auth.user': {
-            'Meta': {'object_name': 'User'},
-            'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 
'datetime.datetime.now'}),
-            'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),
-            'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
-            'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 
'symmetrical': 'False', 'blank': 'True'}),
-            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
-            'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
-            'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
-            'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
-            'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 
'datetime.datetime.now'}),
-            'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
-            'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
-            'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': 
"orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}),
-            'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'})
-        },
-        'contenttypes.contenttype': {
-            'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 
'ContentType', 'db_table': "'django_content_type'"},
-            'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
-            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
-            'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
-            'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
-        },
-        'extensions.extension': {
-            'Meta': {'object_name': 'Extension'},
-            'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 
'True'}),
-            'creator': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"}),
-            'description': ('django.db.models.fields.TextField', [], {}),
-            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
-            'name': ('django.db.models.fields.CharField', [], {'max_length': '200'}),
-            'screenshot': ('sorl.thumbnail.fields.ImageField', [], {'max_length': '100', 'blank': 'True'}),
-            'slug': ('autoslug.fields.AutoSlugField', [], {'unique_with': '()', 'max_length': '50', 
'populate_from': 'None', 'db_index': 'True'}),
-            'url': ('django.db.models.fields.URLField', [], {'max_length': '200'}),
-            'uuid': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '200', 
'db_index': 'True'})
-        },
-        'extensions.extensionversion': {
-            'Meta': {'unique_together': "(('extension', 'version'),)", 'object_name': 'ExtensionVersion'},
-            'extension': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'versions'", 
'to': "orm['extensions.Extension']"}),
-            'extra_json_fields': ('django.db.models.fields.TextField', [], {}),
-            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
-            'source': ('django.db.models.fields.files.FileField', [], {'max_length': '100'}),
-            'status': ('django.db.models.fields.PositiveIntegerField', [], {}),
-            'version': ('django.db.models.fields.IntegerField', [], {'default': '0'})
-        }
-    }
-
-    complete_apps = ['extensions']
+    operations = [
+        migrations.CreateModel(
+            name='Extension',
+            fields=[
+                ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, 
primary_key=True)),
+                ('name', models.CharField(max_length=200)),
+                ('uuid', models.CharField(unique=True, max_length=200, db_index=True)),
+                ('slug', autoslug.fields.AutoSlugField(editable=False)),
+                ('description', models.TextField(blank=True)),
+                ('url', models.URLField(blank=True)),
+                ('created', models.DateTimeField(auto_now_add=True)),
+                ('downloads', models.PositiveIntegerField(default=0)),
+                ('popularity', models.IntegerField(default=0)),
+                ('screenshot', 
models.ImageField(upload_to=sweettooth.extensions.models.make_screenshot_filename, blank=True)),
+                ('icon', models.ImageField(default=b'/static/images/plugin.png', 
upload_to=sweettooth.extensions.models.make_icon_filename, blank=True)),
+                ('creator', models.ForeignKey(to=settings.AUTH_USER_MODEL)),
+            ],
+            options={
+                'permissions': (('can-modify-data', 'Can modify extension data'),),
+            },
+            bases=(models.Model,),
+        ),
+        migrations.CreateModel(
+            name='ExtensionPopularityItem',
+            fields=[
+                ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, 
primary_key=True)),
+                ('offset', models.IntegerField()),
+                ('date', models.DateTimeField(auto_now_add=True)),
+                ('extension', models.ForeignKey(related_name='popularity_items', to='extensions.Extension')),
+            ],
+            options={
+            },
+            bases=(models.Model,),
+        ),
+        migrations.CreateModel(
+            name='ExtensionVersion',
+            fields=[
+                ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, 
primary_key=True)),
+                ('version', models.IntegerField(default=0)),
+                ('extra_json_fields', models.TextField()),
+                ('status', models.PositiveIntegerField(choices=[(0, 'Unreviewed'), (1, 'Rejected'), (2, 
'Inactive'), (3, 'Active'), (4, 'Waiting for author')])),
+                ('source', models.FileField(max_length=223, 
upload_to=sweettooth.extensions.models.make_filename)),
+                ('extension', models.ForeignKey(related_name='versions', to='extensions.Extension')),
+            ],
+            options={
+                'get_latest_by': 'version',
+            },
+            bases=(models.Model,),
+        ),
+        migrations.CreateModel(
+            name='ShellVersion',
+            fields=[
+                ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, 
primary_key=True)),
+                ('major', models.PositiveIntegerField()),
+                ('minor', models.PositiveIntegerField()),
+                ('point', models.IntegerField()),
+            ],
+            options={
+            },
+            bases=(models.Model,),
+        ),
+        migrations.AddField(
+            model_name='extensionversion',
+            name='shell_versions',
+            field=models.ManyToManyField(to='extensions.ShellVersion'),
+            preserve_default=True,
+        ),
+        migrations.AlterUniqueTogether(
+            name='extensionversion',
+            unique_together=set([('extension', 'version')]),
+        ),
+    ]
diff --git a/sweettooth/extensions/models.py b/sweettooth/extensions/models.py
index a3f3900..eb5a38c 100644
--- a/sweettooth/extensions/models.py
+++ b/sweettooth/extensions/models.py
@@ -63,6 +63,15 @@ def build_shell_version_map(versions):
 
     return shell_version_map
 
+
+def make_screenshot_filename(obj, filename=None):
+    return "screenshots/screenshot_%d.png" % (obj.pk,)
+
+
+def make_icon_filename(obj, filename=None):
+    return "icons/icon_%d.png" % (obj.pk,)
+
+
 class Extension(models.Model):
     name = models.CharField(max_length=200)
     uuid = models.CharField(max_length=200, unique=True, db_index=True)
@@ -79,14 +88,7 @@ class Extension(models.Model):
             ("can-modify-data", "Can modify extension data"),
         )
 
-    def make_screenshot_filename(self, filename=None):
-        return "screenshots/screenshot_%d.png" % (self.pk,)
-
     screenshot = models.ImageField(upload_to=make_screenshot_filename, blank=True)
-
-    def make_icon_filename(self, filename=None):
-        return "icons/icon_%d.png" % (self.pk,)
-
     icon = models.ImageField(upload_to=make_icon_filename, blank=True, default="/static/images/plugin.png")
 
     objects = ExtensionManager()
@@ -194,7 +196,11 @@ class ShellVersionManager(models.Manager):
 
     def get_for_version_string(self, version_string):
         major, minor, point = parse_version_string(version_string)
-        obj, created = self.get_or_create(major=major, minor=minor, point=point)
+        try:
+            obj = self.get(major=major, minor=minor, point=point)
+        except self.model.DoesNotExist:
+            obj = self.create(major=major, minor=minor, point=point)
+
         return obj
 
 class ShellVersion(models.Model):
@@ -261,6 +267,11 @@ class ExtensionVersionManager(models.Manager):
     def visible(self):
         return self.filter(status=STATUS_ACTIVE)
 
+
+def make_filename(obj, filename=None):
+    return "%s.v%d.shell-extension.zip" % (obj.extension.uuid, obj.version)
+
+
 class ExtensionVersion(models.Model):
     extension = models.ForeignKey(Extension, related_name="versions")
     version = models.IntegerField(default=0)
@@ -275,9 +286,6 @@ class ExtensionVersion(models.Model):
     def __unicode__(self):
         return "Version %d of %s" % (self.version, self.extension)
 
-    def make_filename(self, filename):
-        return "%s.v%d.shell-extension.zip" % (self.extension.uuid, self.version)
-
     source = models.FileField(upload_to=make_filename,
                               max_length=filename_max_length)
 
diff --git a/sweettooth/extensions/migrations/0002_auto__add_shellversion.py 
b/sweettooth/extensions/south_migrations/0001_initial.py
similarity index 70%
copy from sweettooth/extensions/migrations/0002_auto__add_shellversion.py
copy to sweettooth/extensions/south_migrations/0001_initial.py
index 9f91c62..74858a3 100644
--- a/sweettooth/extensions/migrations/0002_auto__add_shellversion.py
+++ b/sweettooth/extensions/south_migrations/0001_initial.py
@@ -8,31 +8,45 @@ class Migration(SchemaMigration):
 
     def forwards(self, orm):
         
-        # Adding model 'ShellVersion'
-        db.create_table('extensions_shellversion', (
+        # Adding model 'Extension'
+        db.create_table('extensions_extension', (
             ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
-            ('major', self.gf('django.db.models.fields.PositiveIntegerField')()),
-            ('minor', self.gf('django.db.models.fields.PositiveIntegerField')()),
-            ('point', self.gf('django.db.models.fields.IntegerField')()),
+            ('name', self.gf('django.db.models.fields.CharField')(max_length=200)),
+            ('uuid', self.gf('django.db.models.fields.CharField')(unique=True, max_length=200, 
db_index=True)),
+            ('slug', self.gf('autoslug.fields.AutoSlugField')(unique_with=(), max_length=50, 
populate_from=None, db_index=True)),
+            ('creator', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['auth.User'])),
+            ('description', self.gf('django.db.models.fields.TextField')()),
+            ('url', self.gf('django.db.models.fields.URLField')(max_length=200)),
+            ('created', self.gf('django.db.models.fields.DateTimeField')(auto_now_add=True, blank=True)),
+            ('screenshot', self.gf('sorl.thumbnail.fields.ImageField')(max_length=100, blank=True)),
         ))
-        db.send_create_signal('extensions', ['ShellVersion'])
+        db.send_create_signal('extensions', ['Extension'])
 
-        # Adding M2M table for field shell_versions on 'ExtensionVersion'
-        db.create_table('extensions_extensionversion_shell_versions', (
-            ('id', models.AutoField(verbose_name='ID', primary_key=True, auto_created=True)),
-            ('extensionversion', models.ForeignKey(orm['extensions.extensionversion'], null=False)),
-            ('shellversion', models.ForeignKey(orm['extensions.shellversion'], null=False))
+        # Adding model 'ExtensionVersion'
+        db.create_table('extensions_extensionversion', (
+            ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
+            ('extension', self.gf('django.db.models.fields.related.ForeignKey')(related_name='versions', 
to=orm['extensions.Extension'])),
+            ('version', self.gf('django.db.models.fields.IntegerField')(default=0)),
+            ('extra_json_fields', self.gf('django.db.models.fields.TextField')()),
+            ('status', self.gf('django.db.models.fields.PositiveIntegerField')()),
+            ('source', self.gf('django.db.models.fields.files.FileField')(max_length=100)),
         ))
-        db.create_unique('extensions_extensionversion_shell_versions', ['extensionversion_id', 
'shellversion_id'])
+        db.send_create_signal('extensions', ['ExtensionVersion'])
+
+        # Adding unique constraint on 'ExtensionVersion', fields ['extension', 'version']
+        db.create_unique('extensions_extensionversion', ['extension_id', 'version'])
 
 
     def backwards(self, orm):
         
-        # Deleting model 'ShellVersion'
-        db.delete_table('extensions_shellversion')
+        # Removing unique constraint on 'ExtensionVersion', fields ['extension', 'version']
+        db.delete_unique('extensions_extensionversion', ['extension_id', 'version'])
+
+        # Deleting model 'Extension'
+        db.delete_table('extensions_extension')
 
-        # Removing M2M table for field shell_versions on 'ExtensionVersion'
-        db.delete_table('extensions_extensionversion_shell_versions')
+        # Deleting model 'ExtensionVersion'
+        db.delete_table('extensions_extensionversion')
 
 
     models = {
@@ -89,17 +103,9 @@ class Migration(SchemaMigration):
             'extension': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'versions'", 
'to': "orm['extensions.Extension']"}),
             'extra_json_fields': ('django.db.models.fields.TextField', [], {}),
             'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
-            'shell_versions': ('django.db.models.fields.related.ManyToManyField', [], {'to': 
"orm['extensions.ShellVersion']", 'symmetrical': 'False'}),
             'source': ('django.db.models.fields.files.FileField', [], {'max_length': '100'}),
             'status': ('django.db.models.fields.PositiveIntegerField', [], {}),
             'version': ('django.db.models.fields.IntegerField', [], {'default': '0'})
-        },
-        'extensions.shellversion': {
-            'Meta': {'object_name': 'ShellVersion'},
-            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
-            'major': ('django.db.models.fields.PositiveIntegerField', [], {}),
-            'minor': ('django.db.models.fields.PositiveIntegerField', [], {}),
-            'point': ('django.db.models.fields.IntegerField', [], {})
         }
     }
 
diff --git a/sweettooth/extensions/migrations/0002_auto__add_shellversion.py 
b/sweettooth/extensions/south_migrations/0002_auto__add_shellversion.py
similarity index 100%
rename from sweettooth/extensions/migrations/0002_auto__add_shellversion.py
rename to sweettooth/extensions/south_migrations/0002_auto__add_shellversion.py
diff --git a/sweettooth/extensions/migrations/0003_auto__add_field_extension_icon.py 
b/sweettooth/extensions/south_migrations/0003_auto__add_field_extension_icon.py
similarity index 100%
rename from sweettooth/extensions/migrations/0003_auto__add_field_extension_icon.py
rename to sweettooth/extensions/south_migrations/0003_auto__add_field_extension_icon.py
diff --git a/sweettooth/extensions/migrations/0004_auto__chg_field_extensionversion_version.py 
b/sweettooth/extensions/south_migrations/0004_auto__chg_field_extensionversion_version.py
similarity index 100%
rename from sweettooth/extensions/migrations/0004_auto__chg_field_extensionversion_version.py
rename to sweettooth/extensions/south_migrations/0004_auto__chg_field_extensionversion_version.py
diff --git a/sweettooth/extensions/migrations/0005_auto__add_errorreport.py 
b/sweettooth/extensions/south_migrations/0005_auto__add_errorreport.py
similarity index 100%
rename from sweettooth/extensions/migrations/0005_auto__add_errorreport.py
rename to sweettooth/extensions/south_migrations/0005_auto__add_errorreport.py
diff --git a/sweettooth/extensions/migrations/0006_auto__del_errorreport.py 
b/sweettooth/extensions/south_migrations/0006_auto__del_errorreport.py
similarity index 100%
rename from sweettooth/extensions/migrations/0006_auto__del_errorreport.py
rename to sweettooth/extensions/south_migrations/0006_auto__del_errorreport.py
diff --git 
a/sweettooth/extensions/migrations/0007_auto__chg_field_extensionversion_source__chg_field_extensionversion_ve.py
 
b/sweettooth/extensions/south_migrations/0007_auto__chg_field_extensionversion_source__chg_field_extensionversion_ve.py
similarity index 100%
rename from 
sweettooth/extensions/migrations/0007_auto__chg_field_extensionversion_source__chg_field_extensionversion_ve.py
rename to 
sweettooth/extensions/south_migrations/0007_auto__chg_field_extensionversion_source__chg_field_extensionversion_ve.py
diff --git a/sweettooth/extensions/migrations/0008_new_icon_default.py 
b/sweettooth/extensions/south_migrations/0008_new_icon_default.py
similarity index 100%
rename from sweettooth/extensions/migrations/0008_new_icon_default.py
rename to sweettooth/extensions/south_migrations/0008_new_icon_default.py
diff --git a/sweettooth/extensions/migrations/0009_icon_and_screenshot_names.py 
b/sweettooth/extensions/south_migrations/0009_icon_and_screenshot_names.py
similarity index 100%
rename from sweettooth/extensions/migrations/0009_icon_and_screenshot_names.py
rename to sweettooth/extensions/south_migrations/0009_icon_and_screenshot_names.py
diff --git a/sweettooth/extensions/migrations/0010_auto__add_field_extension_downloads.py 
b/sweettooth/extensions/south_migrations/0010_auto__add_field_extension_downloads.py
similarity index 100%
rename from sweettooth/extensions/migrations/0010_auto__add_field_extension_downloads.py
rename to sweettooth/extensions/south_migrations/0010_auto__add_field_extension_downloads.py
diff --git 
a/sweettooth/extensions/migrations/0011_auto__add_field_extension_enables__add_field_extension_disables__add_f.py
 
b/sweettooth/extensions/south_migrations/0011_auto__add_field_extension_enables__add_field_extension_disables__add_f.py
similarity index 100%
rename from 
sweettooth/extensions/migrations/0011_auto__add_field_extension_enables__add_field_extension_disables__add_f.py
rename to 
sweettooth/extensions/south_migrations/0011_auto__add_field_extension_enables__add_field_extension_disables__add_f.py
diff --git a/sweettooth/extensions/migrations/0012_add_extensionpopularityitem.py 
b/sweettooth/extensions/south_migrations/0012_add_extensionpopularityitem.py
similarity index 100%
rename from sweettooth/extensions/migrations/0012_add_extensionpopularityitem.py
rename to sweettooth/extensions/south_migrations/0012_add_extensionpopularityitem.py
diff --git a/sweettooth/extensions/migrations/0013_move_to_popularity_items.py 
b/sweettooth/extensions/south_migrations/0013_move_to_popularity_items.py
similarity index 100%
rename from sweettooth/extensions/migrations/0013_move_to_popularity_items.py
rename to sweettooth/extensions/south_migrations/0013_move_to_popularity_items.py
diff --git a/sweettooth/extensions/migrations/0016_del_extension_enables_disables_and_popularity.py 
b/sweettooth/extensions/south_migrations/0016_del_extension_enables_disables_and_popularity.py
similarity index 100%
rename from sweettooth/extensions/migrations/0016_del_extension_enables_disables_and_popularity.py
rename to sweettooth/extensions/south_migrations/0016_del_extension_enables_disables_and_popularity.py
diff --git a/sweettooth/extensions/migrations/0017_auto__add_field_extension_popularity.py 
b/sweettooth/extensions/south_migrations/0017_auto__add_field_extension_popularity.py
similarity index 100%
rename from sweettooth/extensions/migrations/0017_auto__add_field_extension_popularity.py
rename to sweettooth/extensions/south_migrations/0017_auto__add_field_extension_popularity.py
diff --git a/sweettooth/extensions/migrations/0018_new_to_unreviewed.py 
b/sweettooth/extensions/south_migrations/0018_new_to_unreviewed.py
similarity index 100%
rename from sweettooth/extensions/migrations/0018_new_to_unreviewed.py
rename to sweettooth/extensions/south_migrations/0018_new_to_unreviewed.py
diff --git a/sweettooth/extensions/migrations/0019_auto__chg_field_extension_screenshot.py 
b/sweettooth/extensions/south_migrations/0019_auto__chg_field_extension_screenshot.py
similarity index 100%
rename from sweettooth/extensions/migrations/0019_auto__chg_field_extension_screenshot.py
rename to sweettooth/extensions/south_migrations/0019_auto__chg_field_extension_screenshot.py
diff --git a/sweettooth/extensions/south_migrations/__init__.py 
b/sweettooth/extensions/south_migrations/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/sweettooth/extensions/testdata/test_upgrade_data.json 
b/sweettooth/extensions/testdata/test_upgrade_data.json
index e7099c6..003a798 100644
--- a/sweettooth/extensions/testdata/test_upgrade_data.json
+++ b/sweettooth/extensions/testdata/test_upgrade_data.json
@@ -1 +1,149 @@
-[{"pk": 1, "model": "extensions.extension", "fields": {"description": "Upgrade me, please", "screenshot": 
"", "creator": 1, "url": "http://git.gnome.org/extensions-web";, "created": "2011-11-15 22:33:11", "uuid": 
"upgrade-extension testcases sweettooth mecheye net", "icon": "/static/images/plugin.png", "slug": 
"upgrade-extension", "name": "Upgrade Extension"}}, {"pk": 2, "model": "extensions.extension", "fields": 
{"description": "Downgrade me, please", "screenshot": "", "creator": 1, "url": 
"http://git.gnome.org/extensions-web";, "created": "2011-11-15 22:36:24", "uuid": "downgrade-extension 
testcases sweettooth mecheye net", "icon": "/static/images/plugin.png", "slug": "downgrade-extension", 
"name": "Downgrade Extension"}}, {"pk": 3, "model": "extensions.extension", "fields": {"description": "Reject 
me, please", "screenshot": "", "creator": 1, "url": "http://git.gnome.org/extensions-web";, "created": 
"2011-11-15 22:40:40", "uuid": "reject-extension@testcases.sweettooth.mecheye
 .net", "icon": "/static/images/plugin.png", "slug": "reject-extension", "name": "Rejected Extension"}}, 
{"pk": 1, "model": "extensions.shellversion", "fields": {"major": 3, "minor": 2, "point": 0}}, {"pk": 2, 
"model": "extensions.shellversion", "fields": {"major": 3, "minor": 2, "point": -1}}, {"pk": 6, "model": 
"extensions.extensionversion", "fields": {"status": 2, "extra_json_fields": "{\"shell-version\": [\"3.2.0\", 
\"3.2\"], \"_generated\": \"Generated by SweetTooth, do not edit\"}", "extension": 3, "source": 
"reject-extension testcases sweettooth mecheye net v1 shell-extension zip", "version": 1, "shell_versions": 
[1, 2]}}, {"pk": 1, "model": "extensions.extensionversion", "fields": {"status": 4, "extra_json_fields": 
"{\"shell-version\": [\"3.2.0\", \"3.2\"], \"_generated\": \"Generated by SweetTooth, do not edit\"}", 
"extension": 1, "source": "upgrade-extension testcases sweettooth mecheye net v1 shell-extension zip", 
"version": 1, "shell_versions": [1, 2]}}, {"pk": 2,
  "model": "extensions.extensionversion", "fields": {"status": 4, "extra_json_fields": "{\"uuid\": 
\"upgrade-extension testcases sweettooth mecheye net\", \"shell-version\": [\"3.2.0\", \"3.2\"], \"name\": 
\"Upgrade Extension\", \"url\": \"http://git.gnome.org/extensions-web\";, \"_generated\": \"Generated by 
SweetTooth, do not edit\", \"description\": \"Upgrade me, please\"}", "extension": 1, "source": 
"upgrade-extension testcases sweettooth mecheye net v2 shell-extension zip", "version": 2, "shell_versions": 
[1, 2]}}, {"pk": 4, "model": "extensions.extensionversion", "fields": {"status": 4, "extra_json_fields": 
"{\"shell-version\": [\"3.2.0\", \"3.2\"], \"_generated\": \"Generated by SweetTooth, do not edit\"}", 
"extension": 2, "source": "downgrade-extension testcases sweettooth mecheye net v1 shell-extension zip", 
"version": 1, "shell_versions": [1, 2]}}, {"pk": 5, "model": "extensions.extensionversion", "fields": 
{"status": 2, "extra_json_fields": "{\"uuid\": \"downgrade-e
 xtension testcases sweettooth mecheye net\", \"shell-version\": [\"3.2.0\", \"3.2\"], \"name\": \"Downgrade 
Extension\", \"url\": \"http://git.gnome.org/extensions-web\";, \"_generated\": \"Generated by SweetTooth, do 
not edit\", \"description\": \"Downgrade me, please\"}", "extension": 2, "source": "downgrade-extension 
testcases sweettooth mecheye net v2 shell-extension zip", "version": 2, "shell_versions": [1, 2]}}]
\ No newline at end of file
+[
+  {
+    "pk": 1,
+    "model": "extensions.extension",
+    "fields": {
+      "description": "Upgrade me, please",
+      "screenshot": "",
+      "creator": 1,
+      "url": "http://git.gnome.org/extensions-web";,
+      "created": "2011-11-15 22:33:11",
+      "uuid": "upgrade-extension testcases sweettooth mecheye net",
+      "icon": "/static/images/plugin.png",
+      "slug": "upgrade-extension",
+      "name": "Upgrade Extension"
+    }
+  },
+  {
+    "pk": 2,
+    "model": "extensions.extension",
+    "fields": {
+      "description": "Downgrade me, please",
+      "screenshot": "",
+      "creator": 1,
+      "url": "http://git.gnome.org/extensions-web";,
+      "created": "2011-11-15 22:36:24",
+      "uuid": "downgrade-extension testcases sweettooth mecheye net",
+      "icon": "/static/images/plugin.png",
+      "slug": "downgrade-extension",
+      "name": "Downgrade Extension"
+    }
+  },
+  {
+    "pk": 3,
+    "model": "extensions.extension",
+    "fields": {
+      "description": "Reject me, please",
+      "screenshot": "",
+      "creator": 1,
+      "url": "http://git.gnome.org/extensions-web";,
+      "created": "2011-11-15 22:40:40",
+      "uuid": "reject-extension testcases sweettooth mecheye net",
+      "icon": "/static/images/plugin.png",
+      "slug": "reject-extension",
+      "name": "Rejected Extension"
+    }
+  },
+  {
+    "pk": 1,
+    "model": "extensions.shellversion",
+    "fields": {
+      "major": 3,
+      "minor": 2,
+      "point": 0
+    }
+  },
+  {
+    "pk": 2,
+    "model": "extensions.shellversion",
+    "fields": {
+      "major": 3,
+      "minor": 2,
+      "point": -1
+    }
+  },
+  {
+    "pk": 6,
+    "model": "extensions.extensionversion",
+    "fields": {
+      "status": 2,
+      "extra_json_fields": "{\"shell-version\": [\"3.2.0\", \"3.2\"], \"_generated\": \"Generated by 
SweetTooth, do not edit\"}",
+      "extension": 3,
+      "source": "reject-extension testcases sweettooth mecheye net v1 shell-extension zip",
+      "version": 1,
+      "shell_versions": [
+        1,
+        2
+      ]
+    }
+  },
+  {
+    "pk": 1,
+    "model": "extensions.extensionversion",
+    "fields": {
+      "status": 4,
+      "extra_json_fields": "{\"shell-version\": [\"3.2.0\", \"3.2\"], \"_generated\": \"Generated by 
SweetTooth, do not edit\"}",
+      "extension": 1,
+      "source": "upgrade-extension testcases sweettooth mecheye net v1 shell-extension zip",
+      "version": 1,
+      "shell_versions": [
+        1,
+        2
+      ]
+    }
+  },
+  {
+    "pk": 2,
+    "model": "extensions.extensionversion",
+    "fields": {
+      "status": 4,
+      "extra_json_fields": "{\"uuid\": \"upgrade-extension testcases sweettooth mecheye net\", 
\"shell-version\": [\"3.2.0\", \"3.2\"], \"name\": \"Upgrade Extension\", \"url\": 
\"http://git.gnome.org/extensions-web\";, \"_generated\": \"Generated by SweetTooth, do not edit\", 
\"description\": \"Upgrade me, please\"}",
+      "extension": 1,
+      "source": "upgrade-extension testcases sweettooth mecheye net v2 shell-extension zip",
+      "version": 2,
+      "shell_versions": [
+        1,
+        2
+      ]
+    }
+  },
+  {
+    "pk": 4,
+    "model": "extensions.extensionversion",
+    "fields": {
+      "status": 4,
+      "extra_json_fields": "{\"shell-version\": [\"3.2.0\", \"3.2\"], \"_generated\": \"Generated by 
SweetTooth, do not edit\"}",
+      "extension": 2,
+      "source": "downgrade-extension testcases sweettooth mecheye net v1 shell-extension zip",
+      "version": 1,
+      "shell_versions": [
+        1,
+        2
+      ]
+    }
+  },
+  {
+    "pk": 5,
+    "model": "extensions.extensionversion",
+    "fields": {
+      "status": 2,
+      "extra_json_fields": "{\"uuid\": \"downgrade-extension testcases sweettooth mecheye net\", 
\"shell-version\": [\"3.2.0\", \"3.2\"], \"name\": \"Downgrade Extension\", \"url\": 
\"http://git.gnome.org/extensions-web\";, \"_generated\": \"Generated by SweetTooth, do not edit\", 
\"description\": \"Downgrade me, please\"}",
+      "extension": 2,
+      "source": "downgrade-extension testcases sweettooth mecheye net v2 shell-extension zip",
+      "version": 2,
+      "shell_versions": [
+        1,
+        2
+      ]
+    }
+  },
+  {
+    "pk": 1,
+    "model": "auth.User",
+    "fields": {
+      "username": "Test",
+      "email": "test@localhost.local",
+      "password": "test@localhost.local"
+    }
+  }
+]
diff --git a/sweettooth/extensions/views.py b/sweettooth/extensions/views.py
index 4f023d4..cac83f2 100644
--- a/sweettooth/extensions/views.py
+++ b/sweettooth/extensions/views.py
@@ -366,43 +366,47 @@ def ajax_set_status_view(request, newstatus):
     return dict(svm=json.dumps(extension.visible_shell_version_map),
                 mvs=render_to_string('extensions/multiversion_status.html', context))
 
-@transaction.commit_manually
 def create_version(request, file_source):
+    transaction.set_autocommit(False)
     try:
-        metadata = models.parse_zipfile_metadata(file_source)
-        uuid = metadata['uuid']
-    except (models.InvalidExtensionData, KeyError), e:
-        messages.error(request, "Invalid extension data: %s" % (e.message,))
-        transaction.rollback()
-        return None, []
-
-    try:
-        extension = models.Extension.objects.get(uuid=uuid)
-    except models.Extension.DoesNotExist:
-        extension = models.Extension(creator=request.user)
-    else:
-        if request.user != extension.creator and not request.user.is_superuser:
-            messages.error(request, "An extension with that UUID has already been added.")
+        try:
+            metadata = models.parse_zipfile_metadata(file_source)
+            uuid = metadata['uuid']
+        except (models.InvalidExtensionData, KeyError), e:
+            messages.error(request, "Invalid extension data: %s" % (e.message,))
             transaction.rollback()
             return None, []
 
-    extension.parse_metadata_json(metadata)
-    extension.save()
+        try:
+            extension = models.Extension.objects.get(uuid=uuid)
+        except models.Extension.DoesNotExist:
+            extension = models.Extension(creator=request.user)
+        else:
+            if request.user != extension.creator and not request.user.is_superuser:
+                messages.error(request, "An extension with that UUID has already been added.")
+                transaction.rollback()
+                return None, []
 
-    try:
-        extension.full_clean()
-    except ValidationError, e:
-        transaction.rollback()
-        return None, e.messages
-
-    version = models.ExtensionVersion.objects.create(extension=extension,
-                                                     source=file_source,
-                                                     status=models.STATUS_UNREVIEWED)
-    version.parse_metadata_json(metadata)
-    version.replace_metadata_json()
-    version.save()
+        extension.parse_metadata_json(metadata)
+        extension.save()
+
+        try:
+            extension.full_clean()
+        except ValidationError, e:
+            transaction.rollback()
+            return None, e.messages
+
+        version = models.ExtensionVersion.objects.create(extension=extension,
+                                                         source=file_source,
+                                                         status=models.STATUS_UNREVIEWED)
+        version.parse_metadata_json(metadata)
+        version.replace_metadata_json()
+        version.save()
+
+        transaction.commit()
+    finally:
+        transaction.set_autocommit(True)
 
-    transaction.commit()
     return version, []
 
 @login_required
diff --git a/sweettooth/ratings/forms.py b/sweettooth/ratings/forms.py
index 725de96..99c13eb 100644
--- a/sweettooth/ratings/forms.py
+++ b/sweettooth/ratings/forms.py
@@ -5,7 +5,7 @@ from django.forms import fields, widgets
 from django.conf import settings
 from django.contrib.contenttypes.models import ContentType
 from django.contrib.comments.forms import CommentForm
-from django.utils.encoding import StrAndUnicode, force_unicode
+from django.utils.encoding import force_unicode
 from django.utils.safestring import mark_safe
 
 from sweettooth.ratings.models import RatingComment
diff --git a/sweettooth/ratings/migrations/0001_initial.py b/sweettooth/ratings/migrations/0001_initial.py
index 6c0a17e..357c2d1 100644
--- a/sweettooth/ratings/migrations/0001_initial.py
+++ b/sweettooth/ratings/migrations/0001_initial.py
@@ -1,91 +1,25 @@
-# encoding: utf-8
-import datetime
-from south.db import db
-from south.v2 import SchemaMigration
-from django.db import models
+# -*- coding: utf-8 -*-
+from __future__ import unicode_literals
 
-class Migration(SchemaMigration):
+from django.db import models, migrations
 
-    def forwards(self, orm):
-        
-        # Adding model 'RatingComment'
-        db.create_table('ratings_ratingcomment', (
-            ('comment_ptr', 
self.gf('django.db.models.fields.related.OneToOneField')(to=orm['comments.Comment'], unique=True, 
primary_key=True)),
-            ('rating', self.gf('django.db.models.fields.PositiveIntegerField')()),
-        ))
-        db.send_create_signal('ratings', ['RatingComment'])
 
+class Migration(migrations.Migration):
 
-    def backwards(self, orm):
-        
-        # Deleting model 'RatingComment'
-        db.delete_table('ratings_ratingcomment')
+    dependencies = [
+        ('comments', '__first__'),
+    ]
 
-
-    models = {
-        'auth.group': {
-            'Meta': {'object_name': 'Group'},
-            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
-            'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}),
-            'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': 
"orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'})
-        },
-        'auth.permission': {
-            'Meta': {'ordering': "('content_type__app_label', 'content_type__model', 'codename')", 
'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'},
-            'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
-            'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': 
"orm['contenttypes.ContentType']"}),
-            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
-            'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
-        },
-        'auth.user': {
-            'Meta': {'object_name': 'User'},
-            'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 
'datetime.datetime.now'}),
-            'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),
-            'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
-            'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 
'symmetrical': 'False', 'blank': 'True'}),
-            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
-            'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
-            'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
-            'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
-            'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 
'datetime.datetime.now'}),
-            'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
-            'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
-            'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': 
"orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}),
-            'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'})
-        },
-        'comments.comment': {
-            'Meta': {'ordering': "('submit_date',)", 'object_name': 'Comment', 'db_table': 
"'django_comments'"},
-            'comment': ('django.db.models.fields.TextField', [], {'max_length': '3000'}),
-            'content_type': ('django.db.models.fields.related.ForeignKey', [], {'related_name': 
"'content_type_set_for_comment'", 'to': "orm['contenttypes.ContentType']"}),
-            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
-            'ip_address': ('django.db.models.fields.IPAddressField', [], {'max_length': '15', 'null': 
'True', 'blank': 'True'}),
-            'is_public': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
-            'is_removed': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
-            'object_pk': ('django.db.models.fields.TextField', [], {}),
-            'site': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['sites.Site']"}),
-            'submit_date': ('django.db.models.fields.DateTimeField', [], {'default': 'None'}),
-            'user': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': 
"'comment_comments'", 'null': 'True', 'to': "orm['auth.User']"}),
-            'user_email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),
-            'user_name': ('django.db.models.fields.CharField', [], {'max_length': '50', 'blank': 'True'}),
-            'user_url': ('django.db.models.fields.URLField', [], {'max_length': '200', 'blank': 'True'})
-        },
-        'contenttypes.contenttype': {
-            'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 
'ContentType', 'db_table': "'django_content_type'"},
-            'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
-            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
-            'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
-            'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
-        },
-        'ratings.ratingcomment': {
-            'Meta': {'ordering': "('submit_date',)", 'object_name': 'RatingComment', '_ormbases': 
['comments.Comment']},
-            'comment_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': 
"orm['comments.Comment']", 'unique': 'True', 'primary_key': 'True'}),
-            'rating': ('django.db.models.fields.PositiveIntegerField', [], {})
-        },
-        'sites.site': {
-            'Meta': {'ordering': "('domain',)", 'object_name': 'Site', 'db_table': "'django_site'"},
-            'domain': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
-            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
-            'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
-        }
-    }
-
-    complete_apps = ['ratings']
+    operations = [
+        migrations.CreateModel(
+            name='RatingComment',
+            fields=[
+                ('comment_ptr', models.OneToOneField(parent_link=True, auto_created=True, primary_key=True, 
serialize=False, to='comments.Comment')),
+                ('rating', models.IntegerField(default=-1, blank=True)),
+            ],
+            options={
+                'abstract': False,
+            },
+            bases=('comments.comment',),
+        ),
+    ]
diff --git a/sweettooth/ratings/migrations/0002_auto__chg_field_ratingcomment_rating.py 
b/sweettooth/ratings/south_migrations/0001_initial.py
similarity index 91%
copy from sweettooth/ratings/migrations/0002_auto__chg_field_ratingcomment_rating.py
copy to sweettooth/ratings/south_migrations/0001_initial.py
index abee6e6..6c0a17e 100644
--- a/sweettooth/ratings/migrations/0002_auto__chg_field_ratingcomment_rating.py
+++ b/sweettooth/ratings/south_migrations/0001_initial.py
@@ -8,14 +8,18 @@ class Migration(SchemaMigration):
 
     def forwards(self, orm):
         
-        # Changing field 'RatingComment.rating'
-        db.alter_column('ratings_ratingcomment', 'rating', self.gf('django.db.models.fields.IntegerField')())
+        # Adding model 'RatingComment'
+        db.create_table('ratings_ratingcomment', (
+            ('comment_ptr', 
self.gf('django.db.models.fields.related.OneToOneField')(to=orm['comments.Comment'], unique=True, 
primary_key=True)),
+            ('rating', self.gf('django.db.models.fields.PositiveIntegerField')()),
+        ))
+        db.send_create_signal('ratings', ['RatingComment'])
 
 
     def backwards(self, orm):
         
-        # Changing field 'RatingComment.rating'
-        db.alter_column('ratings_ratingcomment', 'rating', 
self.gf('django.db.models.fields.PositiveIntegerField')())
+        # Deleting model 'RatingComment'
+        db.delete_table('ratings_ratingcomment')
 
 
     models = {
@@ -74,7 +78,7 @@ class Migration(SchemaMigration):
         'ratings.ratingcomment': {
             'Meta': {'ordering': "('submit_date',)", 'object_name': 'RatingComment', '_ormbases': 
['comments.Comment']},
             'comment_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': 
"orm['comments.Comment']", 'unique': 'True', 'primary_key': 'True'}),
-            'rating': ('django.db.models.fields.IntegerField', [], {'default': '-1', 'blank': 'True'})
+            'rating': ('django.db.models.fields.PositiveIntegerField', [], {})
         },
         'sites.site': {
             'Meta': {'ordering': "('domain',)", 'object_name': 'Site', 'db_table': "'django_site'"},
diff --git a/sweettooth/ratings/migrations/0002_auto__chg_field_ratingcomment_rating.py 
b/sweettooth/ratings/south_migrations/0002_auto__chg_field_ratingcomment_rating.py
similarity index 100%
rename from sweettooth/ratings/migrations/0002_auto__chg_field_ratingcomment_rating.py
rename to sweettooth/ratings/south_migrations/0002_auto__chg_field_ratingcomment_rating.py
diff --git a/sweettooth/ratings/south_migrations/__init__.py b/sweettooth/ratings/south_migrations/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/sweettooth/review/migrations/0001_initial.py b/sweettooth/review/migrations/0001_initial.py
index 60c2445..269d220 100644
--- a/sweettooth/review/migrations/0001_initial.py
+++ b/sweettooth/review/migrations/0001_initial.py
@@ -1,107 +1,32 @@
-# encoding: utf-8
-import datetime
-from south.db import db
-from south.v2 import SchemaMigration
-from django.db import models
+# -*- coding: utf-8 -*-
+from __future__ import unicode_literals
 
-class Migration(SchemaMigration):
+from django.db import models, migrations
+from django.conf import settings
 
-    def forwards(self, orm):
-        
-        # Adding model 'CodeReview'
-        db.create_table('review_codereview', (
-            ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
-            ('reviewer', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['auth.User'])),
-            ('date', self.gf('django.db.models.fields.DateTimeField')(auto_now_add=True, blank=True)),
-            ('comments', self.gf('django.db.models.fields.TextField')()),
-            ('version', self.gf('django.db.models.fields.related.ForeignKey')(related_name='reviews', 
to=orm['extensions.ExtensionVersion'])),
-            ('newstatus', self.gf('django.db.models.fields.PositiveIntegerField')()),
-        ))
-        db.send_create_signal('review', ['CodeReview'])
 
+class Migration(migrations.Migration):
 
-    def backwards(self, orm):
-        
-        # Deleting model 'CodeReview'
-        db.delete_table('review_codereview')
+    dependencies = [
+        ('extensions', '0001_initial'),
+        migrations.swappable_dependency(settings.AUTH_USER_MODEL),
+    ]
 
-
-    models = {
-        'auth.group': {
-            'Meta': {'object_name': 'Group'},
-            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
-            'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}),
-            'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': 
"orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'})
-        },
-        'auth.permission': {
-            'Meta': {'ordering': "('content_type__app_label', 'content_type__model', 'codename')", 
'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'},
-            'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
-            'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': 
"orm['contenttypes.ContentType']"}),
-            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
-            'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
-        },
-        'auth.user': {
-            'Meta': {'object_name': 'User'},
-            'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 
'datetime.datetime.now'}),
-            'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),
-            'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
-            'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 
'symmetrical': 'False', 'blank': 'True'}),
-            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
-            'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
-            'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
-            'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
-            'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 
'datetime.datetime.now'}),
-            'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
-            'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
-            'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': 
"orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}),
-            'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'})
-        },
-        'contenttypes.contenttype': {
-            'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 
'ContentType', 'db_table': "'django_content_type'"},
-            'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
-            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
-            'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
-            'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
-        },
-        'extensions.extension': {
-            'Meta': {'object_name': 'Extension'},
-            'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 
'True'}),
-            'creator': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"}),
-            'description': ('django.db.models.fields.TextField', [], {}),
-            'icon': ('django.db.models.fields.files.ImageField', [], {'default': "''", 'max_length': '100', 
'blank': 'True'}),
-            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
-            'name': ('django.db.models.fields.CharField', [], {'max_length': '200'}),
-            'screenshot': ('sorl.thumbnail.fields.ImageField', [], {'max_length': '100', 'blank': 'True'}),
-            'slug': ('autoslug.fields.AutoSlugField', [], {'unique_with': '()', 'max_length': '50', 
'populate_from': 'None', 'db_index': 'True'}),
-            'url': ('django.db.models.fields.URLField', [], {'max_length': '200'}),
-            'uuid': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '200', 
'db_index': 'True'})
-        },
-        'extensions.extensionversion': {
-            'Meta': {'unique_together': "(('extension', 'version'),)", 'object_name': 'ExtensionVersion'},
-            'extension': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'versions'", 
'to': "orm['extensions.Extension']"}),
-            'extra_json_fields': ('django.db.models.fields.TextField', [], {}),
-            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
-            'shell_versions': ('django.db.models.fields.related.ManyToManyField', [], {'to': 
"orm['extensions.ShellVersion']", 'symmetrical': 'False'}),
-            'source': ('django.db.models.fields.files.FileField', [], {'max_length': '100'}),
-            'status': ('django.db.models.fields.PositiveIntegerField', [], {}),
-            'version': ('django.db.models.fields.IntegerField', [], {'default': '0', 'max_length': '223'})
-        },
-        'extensions.shellversion': {
-            'Meta': {'object_name': 'ShellVersion'},
-            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
-            'major': ('django.db.models.fields.PositiveIntegerField', [], {}),
-            'minor': ('django.db.models.fields.PositiveIntegerField', [], {}),
-            'point': ('django.db.models.fields.IntegerField', [], {})
-        },
-        'review.codereview': {
-            'Meta': {'object_name': 'CodeReview'},
-            'comments': ('django.db.models.fields.TextField', [], {}),
-            'date': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
-            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
-            'newstatus': ('django.db.models.fields.PositiveIntegerField', [], {}),
-            'reviewer': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"}),
-            'version': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'reviews'", 
'to': "orm['extensions.ExtensionVersion']"})
-        }
-    }
-
-    complete_apps = ['review']
+    operations = [
+        migrations.CreateModel(
+            name='CodeReview',
+            fields=[
+                ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, 
primary_key=True)),
+                ('date', models.DateTimeField(auto_now_add=True)),
+                ('comments', models.TextField(blank=True)),
+                ('new_status', models.PositiveIntegerField(null=True, choices=[(0, 'Unreviewed'), (1, 
'Rejected'), (2, 'Inactive'), (3, 'Active'), (4, 'Waiting for author')])),
+                ('auto', models.BooleanField(default=False)),
+                ('reviewer', models.ForeignKey(to=settings.AUTH_USER_MODEL)),
+                ('version', models.ForeignKey(related_name='reviews', to='extensions.ExtensionVersion')),
+            ],
+            options={
+                'permissions': (('can-review-extensions', 'Can review extensions'), ('trusted', 'Trusted 
author')),
+            },
+            bases=(models.Model,),
+        ),
+    ]
diff --git a/sweettooth/review/migrations/0002_auto__del_field_codereview_newstatus.py 
b/sweettooth/review/south_migrations/0001_initial.py
similarity index 87%
copy from sweettooth/review/migrations/0002_auto__del_field_codereview_newstatus.py
copy to sweettooth/review/south_migrations/0001_initial.py
index fdba87a..60c2445 100644
--- a/sweettooth/review/migrations/0002_auto__del_field_codereview_newstatus.py
+++ b/sweettooth/review/south_migrations/0001_initial.py
@@ -8,14 +8,22 @@ class Migration(SchemaMigration):
 
     def forwards(self, orm):
         
-        # Deleting field 'CodeReview.newstatus'
-        db.delete_column('review_codereview', 'newstatus')
+        # Adding model 'CodeReview'
+        db.create_table('review_codereview', (
+            ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
+            ('reviewer', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['auth.User'])),
+            ('date', self.gf('django.db.models.fields.DateTimeField')(auto_now_add=True, blank=True)),
+            ('comments', self.gf('django.db.models.fields.TextField')()),
+            ('version', self.gf('django.db.models.fields.related.ForeignKey')(related_name='reviews', 
to=orm['extensions.ExtensionVersion'])),
+            ('newstatus', self.gf('django.db.models.fields.PositiveIntegerField')()),
+        ))
+        db.send_create_signal('review', ['CodeReview'])
 
 
     def backwards(self, orm):
         
-        # User chose to not deal with backwards NULL issues for 'CodeReview.newstatus'
-        raise RuntimeError("Cannot reverse this migration. 'CodeReview.newstatus' and its values cannot be 
restored.")
+        # Deleting model 'CodeReview'
+        db.delete_table('review_codereview')
 
 
     models = {
@@ -90,6 +98,7 @@ class Migration(SchemaMigration):
             'comments': ('django.db.models.fields.TextField', [], {}),
             'date': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
             'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'newstatus': ('django.db.models.fields.PositiveIntegerField', [], {}),
             'reviewer': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"}),
             'version': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'reviews'", 
'to': "orm['extensions.ExtensionVersion']"})
         }
diff --git a/sweettooth/review/migrations/0002_auto__del_field_codereview_newstatus.py 
b/sweettooth/review/south_migrations/0002_auto__del_field_codereview_newstatus.py
similarity index 100%
rename from sweettooth/review/migrations/0002_auto__del_field_codereview_newstatus.py
rename to sweettooth/review/south_migrations/0002_auto__del_field_codereview_newstatus.py
diff --git a/sweettooth/review/migrations/0003_auto__add_changestatuslog.py 
b/sweettooth/review/south_migrations/0003_auto__add_changestatuslog.py
similarity index 100%
rename from sweettooth/review/migrations/0003_auto__add_changestatuslog.py
rename to sweettooth/review/south_migrations/0003_auto__add_changestatuslog.py
diff --git a/sweettooth/review/migrations/0004_auto__add_field_codereview_changelog.py 
b/sweettooth/review/south_migrations/0004_auto__add_field_codereview_changelog.py
similarity index 100%
rename from sweettooth/review/migrations/0004_auto__add_field_codereview_changelog.py
rename to sweettooth/review/south_migrations/0004_auto__add_field_codereview_changelog.py
diff --git a/sweettooth/review/migrations/0005_auto__add_field_changestatuslog_auto_approved.py 
b/sweettooth/review/south_migrations/0005_auto__add_field_changestatuslog_auto_approved.py
similarity index 100%
rename from sweettooth/review/migrations/0005_auto__add_field_changestatuslog_auto_approved.py
rename to sweettooth/review/south_migrations/0005_auto__add_field_changestatuslog_auto_approved.py
diff --git a/sweettooth/review/migrations/0006_auto__rename_field_changestatuslog_auto_approved.py 
b/sweettooth/review/south_migrations/0006_auto__rename_field_changestatuslog_auto_approved.py
similarity index 100%
rename from sweettooth/review/migrations/0006_auto__rename_field_changestatuslog_auto_approved.py
rename to sweettooth/review/south_migrations/0006_auto__rename_field_changestatuslog_auto_approved.py
diff --git a/sweettooth/review/migrations/0007_remove_changestatuslog.py 
b/sweettooth/review/south_migrations/0007_remove_changestatuslog.py
similarity index 100%
rename from sweettooth/review/migrations/0007_remove_changestatuslog.py
rename to sweettooth/review/south_migrations/0007_remove_changestatuslog.py
diff --git 
a/sweettooth/review/migrations/0008_auto__del_field_codereview_newstatus__add_field_codereview_new_status_.py 
b/sweettooth/review/south_migrations/0008_auto__del_field_codereview_newstatus__add_field_codereview_new_status_.py
similarity index 100%
rename from 
sweettooth/review/migrations/0008_auto__del_field_codereview_newstatus__add_field_codereview_new_status_.py
rename to 
sweettooth/review/south_migrations/0008_auto__del_field_codereview_newstatus__add_field_codereview_new_status_.py
diff --git a/sweettooth/review/south_migrations/__init__.py b/sweettooth/review/south_migrations/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/sweettooth/settings.py b/sweettooth/settings.py
index 5213094..e592616 100644
--- a/sweettooth/settings.py
+++ b/sweettooth/settings.py
@@ -133,8 +133,6 @@ INSTALLED_APPS = (
     'django.contrib.admin',
     # Uncomment the next line to enable admin documentation:
     # 'django.contrib.admindocs'
-
-    'south',
 )
 
 COMMENTS_APP = 'sweettooth.ratings'
diff --git a/sweettooth/urls.py b/sweettooth/urls.py
index 47df68f..cf27236 100644
--- a/sweettooth/urls.py
+++ b/sweettooth/urls.py
@@ -7,6 +7,7 @@ from django.http import HttpResponse
 
 from django.contrib import admin
 from django.views import static
+from django.contrib.staticfiles import urls as static_urls
 admin.autodiscover()
 
 urlpatterns = patterns('',
@@ -27,6 +28,7 @@ if settings.DEBUG:
     # Use static.serve for development...
     urlpatterns.append(url(r'^static/extension-data/(?P<path>.*)', static.serve,
                            dict(document_root=settings.MEDIA_ROOT), name='extension-data'))
+    urlpatterns += static_urls.staticfiles_urlpatterns()
 else:
     # and a dummy to reverse on for production.
     urlpatterns.append(url(r'^static/extension-data/(?P<path>.*)', lambda *a, **kw: HttpResponse(),


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]