删除Django ORM中的重复项 - 多行

Wes*_*ley 26 django django-models

我有一个有四个字段的模型.如何从数据库中删除重复的对象?

丹尼尔罗斯曼对这个问题的回答似乎是恰当的,但我不确定如何将其扩展到每个对象有四个字段进行比较的情况.

谢谢,

W.

Krz*_*arz 68

def remove_duplicated_records(model, fields):
    """
    Removes records from `model` duplicated on `fields`
    while leaving the most recent one (biggest `id`).
    """
    duplicates = model.objects.values(*fields)

    # override any model specific ordering (for `.annotate()`)
    duplicates = duplicates.order_by()

    # group by same values of `fields`; count how many rows are the same
    duplicates = duplicates.annotate(
        max_id=models.Max("id"), count_id=models.Count("id")
    )

    # leave out only the ones which are actually duplicated
    duplicates = duplicates.filter(count_id__gt=1)

    for duplicate in duplicates:
        to_delete = model.objects.filter(**{x: duplicate[x] for x in fields})

        # leave out the latest duplicated record
        # you can use `Min` if you wish to leave out the first record
        to_delete = to_delete.exclude(id=duplicate["max_id"])

        to_delete.delete()
Run Code Online (Sandbox Code Playgroud)

你不应该经常这样做.unique_together而是使用数据库约束.

这使记录id中的DB 最大.如果要保留原始记录(第一个),请稍微修改一下代码models.Min.您还可以使用完全不同的字段,例如创建日期或其他内容.

基础SQL代码

注释django ORM时,GROUP BY会对查询中使用的所有模型字段使用statement.因此使用.values()方法.GROUP BY将所有具有相同值的记录分组.该复制者(超过idunique_fields)在稍后滤除HAVING由生成的语句.filter()上批注QuerySet.

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
Run Code Online (Sandbox Code Playgroud)

稍后将在for循环中删除重复的记录,但每个组的最常见记录除外.

空.order_by()

可以肯定的是,.order_by()在汇总a之前添加空呼叫总是明智的QuerySet.

用于订购的字段QuerySet也包含在GROUP BY声明中.Empty .order_by()覆盖在模型中声明的列Meta,结果它们不包含在SQL查询中(例如,按日期默认排序会破坏结果).

您可能不需要在当前时刻覆盖它,但有人可能会在以后添加默认排序,因此会破坏您珍贵的删除重复代码甚至不知道.是的,我相信你有100%的测试覆盖率......

只需添加空.order_by()即可.;-)

https://docs.djangoproject.com/en/1.11/topics/db/aggregation/#interaction-with-default-ordering-or-order-by

交易

当然,您应该考虑在一次交易中完成所有操作.

https://docs.djangoproject.com/en/1.11/topics/db/transactions/#django.db.transaction.atomic

  • @AndreMiras取决于用例。有时最后一个具有最新信息。 (2认同)