debian-django-reversion/reversion/migrations/0003_auto_20160601_1600.py

109 lines
4.1 KiB
Python

# -*- coding: utf-8 -*-
# Generated by Django 1.9.6 on 2016-06-01 16:00
from __future__ import unicode_literals
from collections import defaultdict
from django.db import DEFAULT_DB_ALIAS, migrations, models, router
from django.apps import apps as live_apps
def de_dupe_version_table(apps, schema_editor):
"""
Removes some duplicate Version models that may have crept into the database and will prevent the
unique index being added by migration 0004.
"""
db_alias = schema_editor.connection.alias
Version = apps.get_model("reversion", "Version")
keep_version_ids = Version.objects.using(db_alias).order_by().values_list(
# Group by the unique constraint we intend to enforce.
"revision_id",
"content_type_id",
"object_id",
).annotate(
# Add in the most recent id for each duplicate row.
max_pk=models.Max("pk"),
).values_list("max_pk", flat=True)
# Do not do anything if we're keeping all ids anyway.
if keep_version_ids.count() == Version.objects.using(db_alias).all().count():
return
# Delete all duplicate versions. Can't do this as a delete with subquery because MySQL doesn't like running a
# subquery on the table being updated/deleted.
delete_version_ids = list(Version.objects.using(db_alias).exclude(
pk__in=keep_version_ids,
).values_list("pk", flat=True))
Version.objects.using(db_alias).filter(
pk__in=delete_version_ids,
).delete()
def set_version_db(apps, schema_editor):
"""
Updates the db field in all Version models to point to the correct write
db for the model.
"""
db_alias = schema_editor.connection.alias
Version = apps.get_model("reversion", "Version")
content_types = Version.objects.using(db_alias).order_by().values_list(
"content_type_id",
"content_type__app_label",
"content_type__model"
).distinct()
model_dbs = defaultdict(list)
for content_type_id, app_label, model_name in content_types:
# We need to be able to access all models in the project, and we can't
# specify them up-front in the migration dependencies. So we have to
# just get the live model. This should be fine, since we don't actually
# manipulate the live model in any way.
try:
model = live_apps.get_model(app_label, model_name)
except LookupError:
# If the model appears not to exist, play it safe and use the default db.
db = "default"
else:
db = router.db_for_write(model)
model_dbs[db].append(content_type_id)
# Update db field.
# speedup for case when there is only default db
if DEFAULT_DB_ALIAS in model_dbs and len(model_dbs) == 1:
Version.objects.using(db_alias).update(db=DEFAULT_DB_ALIAS)
else:
for db, content_type_ids in model_dbs.items():
Version.objects.using(db_alias).filter(
content_type__in=content_type_ids
).update(db=db)
class Migration(migrations.Migration):
dependencies = [
('reversion', '0002_auto_20141216_1509'),
]
operations = [
migrations.RemoveField(
model_name='revision',
name='manager_slug',
),
migrations.RemoveField(
model_name='version',
name='object_id_int',
),
migrations.AlterField(
model_name='version',
name='object_id',
field=models.CharField(help_text='Primary key of the model under version control.', max_length=191),
),
migrations.AlterField(
model_name='revision',
name='date_created',
field=models.DateTimeField(db_index=True, help_text='The date and time this revision was created.', verbose_name='date created'),
),
migrations.AddField(
model_name='version',
name='db',
field=models.CharField(null=True, help_text='The database the model under version control is stored in.', max_length=191),
),
migrations.RunPython(de_dupe_version_table),
migrations.RunPython(set_version_db),
]