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

标签 django django-models

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

丹尼尔罗斯曼对 this question 的回答似乎很合适,但我不确定如何将其扩展到每个对象有四个字段要比较的情况。

谢谢,

W.

最佳答案

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()

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

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

底层 SQL

注释django ORM时使用GROUP BY查询中使用的所有模型字段的语句。因此使用 .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

重复的记录随后在 for 中被删除循环,每个组中出现频率最高的异常(exception)。

空 .order_by()

可以肯定的是,添加一个空的 .order_by() 总是明智的在聚合之前调用 QuerySet .

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

您目前可能不需要覆盖它,但稍后可能有人会添加默认顺序,因此毁了您宝贵的删除重复代码,甚至都不知道。是的,我确定您有 100% 的测试覆盖率……

只需添加空.order_by()为了安全。 ;-)

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

交易

当然,您应该考虑在单个事务中完成所有操作。

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

关于django - 删除 Django ORM 中的重复项——多行,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13700200/

相关文章:

django - 如何测试邮件确认?

Django List 在rest-framework中反序列化

python - 将 Django 调度程序应用程序与您自己的模型一起使用

django - 使用两个可选但一个必需的外键创建模型

django - 查询集 Django 中的 min 函数可在模型中查找较早的日期?

python - 在 Django 中将静态文件中的图像添加到多部分电子邮件中

Django Forms clean() 方法 - 需要客户端的 IP 地址

django - djoser 通过链接激活帐户

Django 名称错误 : name 'bPath' is not defined

python - Django 使用对象自己的数据对多个更新进行建模?