Django:如何选择具有相同字段值的对象?
Posted
技术标签:
【中文标题】Django:如何选择具有相同字段值的对象?【英文标题】:Django: How can I select objects with the same field values? 【发布时间】:2011-06-11 02:30:34 【问题描述】:例如,我有一个这样的模型:
Class Doggy(models.Model):
name = models.CharField(u'Name', max_length = 40)
color = models.CharField(u'Color', max_length = 20)
如何选择颜色相同的狗狗?或者同名:)
UPD。当然,我不知道名字和颜色。我想……按他们的价值观分组。
UPD2。我正在尝试做类似的事情,但使用 Django:
SELECT *
FROM table
WHERE tablefield IN (
SELECT tablefield
FROM table
GROUP BY tablefield
HAVING (COUNT(tablefield ) > 1)
)
UPD3。我想通过 Django ORM 来完成,而不必遍历对象。我只想获取一个特定字段的重复值的行。
【问题讨论】:
【参考方案1】:我迟到了,但你去吧:
Doggy.objects.values('color', 'name').annotate(Count('pk'))
这将为您提供按颜色和名称分组的每个 Doggy 的数量的结果。
【讨论】:
:) 是的,应该这样做,虽然 2011 年没有注释 ;)【参考方案2】:如果您正在寻找某种颜色的 Doggy,您可以这样做。
Doggy.objects.filter(color='blue')
如果要根据当前 Doggy 的颜色来查找 Doggys
def GetSimilarColoredDoggys(self):
return Doggy.objects.filter(color=self.color)
名字也是如此:-
def GetDoggysWithSameName(self):
return Doggy.objects.filter(color=self.name)
【讨论】:
天啊,我的问题真的这么不清楚吗?抱歉,我会更新它以显示颜色/名称未知。 顺便说一句,您的命名不遵循 python neaming 约定。看来,你喜欢 C :) @DataGreed:您对 Mez 的评论是正确的,即使用 CamelCase 代替带下划线的小写字母并不是首选方式。但是话又说回来,关键字参数中的“=”符号之间的空格(正如您在问题中使用的那样)也不符合 PEP8。 python.org/dev/peps/pep-0008 很公平,但我是寻求建议的人。请记住,它是一个知识库,如果新手愿意接受这个建议,它可能会导致他陷入代码格式化破坏的黑暗方式。顺便说一句,使用带有小写首字母的 camelCase 不会那么混乱。但是,同样,这不是重点。【参考方案3】:您可以为此使用itertools.groupby():
import operator
import itertools
from django.db import models
def group_model_by_attr(model_class, attr_name):
assert issubclass(model_class, models.Model), \
"%s is not a Django model." % (model_class,)
assert attr_name in [field.name for field in Event._meta.fields], \
"The %s field doesn't exist on model %s" % (attr_name, model_class)
all_instances = model_class.objects.all().order_by(attr_name)
keyfunc = operator.attrgetter(attr_name)
return [k: list(g) for k, g in itertools.groupby(all_instances, keyfunc)]
grouped_by_color = group_model_by_attr(Doggy, 'color')
grouped_by_name = group_model_by_attr(Doggy, 'name')
grouped_by_color
(例如)将是像 ['purple': [doggy1, doggy2], 'pink': [doggy3,]]
这样的字典列表,其中 doggy1、2 等是 Doggy
实例。
更新:
从您的更新看来,您只需要每个事件类型的 id 列表。我在我的 ubuntu 笔记本电脑上使用 250k 条记录在 postgresql 中测试了这个,带有核心 2 duo 和 3gb 内存,生成字典需要 0.35 秒(itertools.group_by 需要 0.72 秒)。你提到你有 900K 记录,所以这应该足够快。如果不是,它应该很容易随着记录的变化而缓存/更新。
from collections import defaultdict
doggies = Doggy.objects.values_list('color', 'id').order_by('color').iterator()
grouped_doggies_by_color = defaultdict(list)
for color, id in doggies:
grouped_doggies_by_color[color].append(id)
【讨论】:
感谢您的帮助。实际上,我想使用 ORM 来做到这一点。当然,我可以遍历所有对象,但如果你有超过 900k 个对象,那就不是很好了...... 没问题。我肯定会在您的问题中提到数据大小。我已经更新了我认为对你有用的答案。 感谢您的回复,我已经投了赞成票 :) 但我会留下这个问题 - 我真的很想知道是否可以通过 ORM $ 进行上述查询) 第二个基本上是通过 ORM 完成的,有点消息传递数据。仅供参考:我刚刚尝试了 w/750k 记录,groupby 花了 48 秒,而 values_list 花了 22 秒。 是的,我明白了,谢谢,但我仍然有兴趣像上面的 SQL 查询那样构造查询。【参考方案4】:我会更改您的数据模型,以便颜色和名称与 Doggy 是一对多的关系,如下所示:
class Doggy(models.Model):
name = models.ForeignKey('DoggyName')
color = models.ForeignKey('DoggyColor')
class DoggyName(models.Model):
name = models.CharField(max_length=40, unique=True)
class DoggyColor(models.Model):
color = models.CharField(max_length=20, unique=True)
现在DoggyName
和DoggyColor
不包含重复的名字或颜色,您可以使用它们来选择具有相同名字或颜色的狗。
【讨论】:
天啊,我不是在问这个。例如,这个模型是一个虚拟模型。真正的问题是找到重复的消息。 @DataGreed:为什么更改数据模型不是一个有效的选择? 因为这次我对关于数据库架构的建议不感兴趣。如果你想知道真实情况:我有一个类似论坛的东西,我想在其中找到重复的消息并为版主创建一个关于它们的报告。所以,问题本身是关于使用 Django ORM 进行特定类型的查询(当然,如果可能的话 - 我已经尝试了很多方法,但没有使用 extra() 并且没有得到它的工作)。跨度> @DataGreed:名称和颜色为 CharField 的示例 Doggy 模型将导致冗余数据和非第二范式的数据模型。违反 2NF 会导致存储空间浪费并降低查询性能。如果您的“真正的问题是找到重复的消息”,那么您应该提出真正的问题,而不是投票给提出您实际提出的问题的人。 我对您的答案投了反对票,因为它没有包含对实际问题的答案。您也可以回答诸如“不要这样做,为自己找到另一个爱好”之类的问题,但我并不是在寻求有关寻找其他爱好的建议,而不是编写 django 应用程序。我问的是关于使用 ORM 进行精确查询的确切问题。【参考方案5】:好吧,显然,没有办法只用 ORM 做这样的事情。
如果必须这样做,则必须使用 .extra() 来执行所需的 SQL 语句(当然,如果您使用的是 SQL 数据库)
【讨论】:
我会使用 .raw() 而不是 .extra() ——它更简单,你可以使用任何你想要的 SQL 并取回 Django 模型对象。 docs.djangoproject.com/en/dev/topics/db/sql/…以上是关于Django:如何选择具有相同字段值的对象?的主要内容,如果未能解决你的问题,请参考以下文章
如何防止在 Django Admin 中对 FK / MTM 字段进行自我(递归)选择