unique_fields = ['field_1', …, 'field_n']
duplicates = (MyModel.objects.values(*unique_fields)
.order_by()
.annotate(max_id=models.Max('id'),
count_id=models.Count('id'))
.filter(count_id__gt=1))
for duplicate in duplicates:
(MyModel.objects.filter(**{x: duplicate[x] for x in unique_fields})
.exclude(id=duplicate['max_id'])
.delete())
Sie sollten es nicht oft. Verwenden Sie stattdessen unique_together
Constraints für die Datenbank.
Basiswert SQL-Code
Wenn Anmerkungen versehen django ORM GROUP BY
Anweisung auf allen Modellen Felder verwendet, in der Abfrage verwendet. So die Verwendung von .values()
Methode. GROUP BY
gruppiert alle Datensätze mit diesen Werten identisch. Die duplizierten (mehr als eine id
für unique_fields
) werden später in HAVING
Anweisung ausgedruckt von .filter()
auf annotiert QuerySet
ausgefiltert.
SELECT
field_1,
…
field_n,
MAX(id) as max_id,
COUNT(id) as count_id
FROM
app_mymodel
GROUP BY
field_1,
…
field_n
HAVING
count_id > 1
die duplizierte Datensätze werden in der später for
Schleife mit Ausnahme von den häufigsten einem für jede Gruppe gelöscht.
Leere .order_by()
Nur um sicherzugehen, ist es immer ratsam, einen leeren .order_by()
Anruf hinzufügen, bevor eine QuerySet
aggregieren.
Die Felder für die Bestellung der QuerySet
sind ebenfalls in der GROUP BY
-Anweisung enthalten. Leer .order_by()
überschreibt Spalten, die in Meta
des Modells deklariert wurden, und im Ergebnis sind sie nicht in der SQL-Abfrage enthalten (z. B. kann die Standardsortierung nach Datum die Ergebnisse ruinieren).
Sie müssen es möglicherweise im aktuellen Moment nicht überschreiben, aber jemand könnte die Standardbestellung später hinzufügen und daher Ihren wertvollen Lösch-Duplikat-Code ruinieren, ohne das zu wissen. Ja, ich bin mir sicher, dass Sie 100% Testabdeckung haben ...
Fügen Sie einfach .order_by()
hinzu, um sicher zu sein. ;-)
https://docs.djangoproject.com/en/1.11/topics/db/aggregation/#interaction-with-default-ordering-or-order-by
Transaktion
Natürlich sollte man sie alle in einer einzigen Transaktion in Erwägung ziehen.
https://docs.djangoproject.com/en/1.11/topics/db/transactions/#django.db.transaction.atomic
Vielen Dank! Damit ich jedoch verstehen kann (ich bin immer noch sehr ein Django-Novize), könntest du bitte erklären, was bei jedem Schritt passiert? Ich verstehe, dass 'MyModel.objects.values (* unique_fields)' eine Reihe von Wörterbüchern generiert, wobei jedes Wörterbuch zu einem Objekt gehört. Aber dann bin ich verloren - was macht das Annotat? – Westerley
Ich hoffe, dass mein Update die Dinge ein wenig klären wird. –
Brilliant! Funktioniert perfekt!Ich brauchte ziemlich viel Recherche und Nachdenken, um genau herauszufinden, wie ** es funktioniert (Ihre Erklärung half mir ziemlich und half mir herauszufinden, was ich lesen musste ...), aber es funktioniert! Nochmals vielen Dank (und Entschuldigung für die Verzögerung, um zurück zu diesem) – Westerley