blob: 5fa6a6f3ada6e963bf91c5444c48f60d79fe1221 [file] [log] [blame]
Mitja Nikolausfd452f82018-11-07 11:53:59 +01001# -*- coding: utf-8 -*-
2
3"""Migrations to set the unique constraints and drop duplicates."""
4# pylint: disable=invalid-name
5import logging
6
7from django.db import migrations, models, connection
8from django.db.models import Count, Min
9
10from crashreports.models import HeartBeat, Crashreport
11
12LOGGER = logging.getLogger(__name__)
13
14
15def drop_heartbeat_duplicates(apps, schema_editor):
16 """Drop duplicate heartbeat entries."""
17 # pylint: disable=unused-argument
18 find_and_drop_duplicates(HeartBeat)
19
20
21def drop_crashreport_duplicates(apps, schema_editor):
22 """Drop duplicate crashreport entries."""
23 # pylint: disable=unused-argument
24 find_and_drop_duplicates(Crashreport)
25
26
27def find_and_drop_duplicates(object_type):
28 """Drop all duplicates of the given object type."""
29 unique_fields = ("device", "date")
30 duplicates = (
31 object_type.objects.values(*unique_fields)
32 .order_by()
33 .annotate(min_id=Min("id"), num_duplicates=Count("id"))
34 .filter(num_duplicates__gt=1)
35 )
36
37 LOGGER.info(
38 "Found %d %s instances that have duplicates. These will be removed.",
39 duplicates.count(),
40 object_type.__name__,
41 )
42 for duplicate in duplicates:
43 LOGGER.debug("Removing duplicates: %s", duplicate)
44 (
45 object_type.objects.filter(
46 device=duplicate["device"], date=duplicate["date"]
47 )
48 .exclude(id=duplicate["min_id"])
49 .delete()
50 )
51
52 # Manually commit the data migration before schema migrations are applied
53 connection.cursor().execute("COMMIT;")
54
55
56class Migration(migrations.Migration):
57 """Change heartbeat date field, set unique constraints, drop duplicates."""
58
59 dependencies = [("crashreports", "0005_add_fp_staff_group")]
60
61 operations = [
62 migrations.AlterField(
63 model_name="heartbeat",
64 name="date",
65 field=models.DateField(db_index=True),
66 ),
67 migrations.RunPython(
68 drop_heartbeat_duplicates, reverse_code=migrations.RunPython.noop
69 ),
70 migrations.RunPython(
71 drop_crashreport_duplicates, reverse_code=migrations.RunPython.noop
72 ),
73 migrations.AlterUniqueTogether(
74 name="crashreport", unique_together=set([("device", "date")])
75 ),
76 migrations.AlterUniqueTogether(
77 name="heartbeat", unique_together=set([("device", "date")])
78 ),
79 ]