【问题标题】:Django: How can I select objects with the same field values?Django:如何选择具有相同字段值的对象?
【发布时间】: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 来完成,而不必遍历对象。我只想获取一个特定字段的重复值的行。

【问题讨论】:

    标签: django django-models


    【解决方案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)
    

    现在DoggyNameDoggyColor不包含重复的名字或颜色,您可以使用它们来选择具有相同名字或颜色的狗。

    【讨论】:

    • 天啊,我不是在问这个。例如,这个模型是一个虚拟模型。真正的问题是找到重复的消息。
    • @DataGreed:为什么更改数据模型不是一个有效的选择?
    • 因为这次我对关于数据库架构的建议不感兴趣。如果你想知道真实情况:我有一个类似论坛的东西,我想在其中找到重复的消息并为版主创建一个关于它们的报告。所以,问题本身是关于使用 Django ORM 进行特定类型的查询(当然,如果可能的话 - 我已经尝试了很多方法,但没有使用 extra() 并且没有得到它的工作)。跨度>
    • @DataGreed:名称和颜色为 CharField 的示例 Doggy 模型将导致冗余数据和非第二范式的数据模型。违反 2NF 会导致存储空间浪费并降低查询性能。如果您的“真正的问题是找到重复的消息”,那么您应该提出真正的问题,而不是投票给提出您实际提出的问题的人。
    • 我对您的答案投了反对票,因为它没有包含对实际问题的答案。您也可以回答诸如“不要这样做,为自己找到另一个爱好”之类的问题,但我并不是在寻求有关寻找其他爱好的建议,而不是编写 django 应用程序。我问的是关于使用 ORM 进行精确查询的确切问题。
    【解决方案5】:

    好吧,显然,没有办法只用 ORM 做这样的事情。

    如果必须这样做,则必须使用 .extra() 来执行所需的 SQL 语句(当然,如果您使用的是 SQL 数据库)

    【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-06-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-06-08
    • 2013-12-01
    相关资源
    最近更新 更多