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将所有具有相同值的记录分组.该复制者(超过id了unique_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/transactions/#django.db.transaction.atomic
| 归档时间: |
|
| 查看次数: |
10823 次 |
| 最近记录: |