【问题标题】:Queries in query set group in to one query using Django使用 Django 将查询集中的查询组合成一个查询
【发布时间】:2019-02-11 19:56:17
【问题描述】:

我有一个如下查询集。

<QuerySet[{'user':'xyz','id':12,'home':'qwe','mobile':1234}, 
          {'user':'xyz','id':12,'home':'qwe','mobile':4321}, 
          {'user':'abc','id':13,'home':'def','mobile':1233}, 
          {'user':'abc','id':13,'home':'def','mobile':1555},]>

这个 QuerySet 由 django 使用

返回
users.objects.all()

对于查询集中的每个查询,我在前端绘制了一个用户表,其中显示了用户的详细信息。如果同一个“用户”注册了两个“手机”号码,则在表格中显示为两行而不是一行。我的目标是在同一行中显示两个数字,而不是创建两行。

我想到了以下两种可能的解决方案:

解决方案 1:如果两个查询中的“用户”值匹配,我曾考虑将两个查询合并为一个。为此,我们需要使用条件语句进行大量检查,当有很多用户时,条件语句运行缓慢。

解决方案 2:我在 Google 上搜索并提出了 Group By Django,但它不起作用。我在下面尝试过

query = users.objects.all().query
query.group_by = ['mobile']
results = QuerySet(query=query, model=users)  

请提供一种方法,以便可以基于“用户”将两个查询合并为一个,并且在合并后“移动”应包含两个值。

编辑:我将通过正在绘制表格的视图将此查询集传递给模板。目前,对于每个查询,一行是 in 表。由于上述查询集有四个查询,我们将有四行。但我只想在两行中显示信息,因为“id”和“user”是相同的。模板代码如下:

{% if users %}
    {% for user in users %}
        {% for k,v in required_keys.items %}
            <td>{{ user | get_item:k }}
        {% endfor %}
    {% endfor %}
{% endif %}    

必需键是一个字典,其中包含用于在表中显示的键。示例:

Required_keys = {
    'User Name':user,
    'Contact':mobile,
    'Address':home,
} 

get item 是一个函数,它在传递key时获取值。

def get_item(dictionery,key):
    return dictionery.get(key)

编辑 2:我尝试了一个解决方案,它不是一个完整的解决方案,但它部分解决了问题。该解决方案完美适用于一位用户。但是,如果有很多用户,则该解决方案不起作用。见下例:

# input query set to the function which partially solves the problem 
<QuerySet[{'user':'xyz','id':12,'home':'qwe','mobile':1234}, 
      {'user':'xyz','id':12,'home':'qwe','mobile':4321},]> 

# Now our team has written a function which gives the following output
<QuerySet[{'user':'xyz','id':12,'home':'qwe','mobile':1234,4321},]>

但如果有多个用户,则输出与输入相同,它不会包含查询。请看下面的函数:

def merge_values(cls,values):
    import itertools
    grouped_results = itertools.groupby(values,key=lambda x:x['id'])
    merged_values = []
    for k,g in grouped_results:
        groups=list(g)
        merged_value = {}
        for group in groups:
            for key, val in group.iteritems():
                if not merged_value.get(key):
                    merged_value[key] = val
                elif val != merged_value[key]:
                    if isinstance(merged_value[key], list):
                        if val not in merged_value[key]:
                            merged_value[key].append(val)
                        else:
                            old_val = merged_value[key]
                            merged_value[key] = [old_value, val]
        merged_values.append(merged_value)
    return merged_values

函数的 values 参数是整个查询集。但是这个功能 如果上面提到的查询集中只有一个用户,则可以使用。但如果有 是多个用户,它失败了。

编辑3:我找到了为什么上述功能不适用于多个用户(不知道这是否正确)。为函数设置的输入查询(对于一个用户)是

<QuerySet[{'user':'xyz','id':12,'home':'qwe','mobile':1234}, 
      {'user':'xyz','id':12,'home':'qwe','mobile':4321},]>

由于两个用户查询是一个接一个,因此它们是合并的。但是如果有多个用户,传递给函数的查询集是

<QuerySet[{'user':'xyz','id':12,'home':'qwe','mobile':1234}, 
      {'user':'xyz','id':13,'home':'qwe','mobile':4321}, 
      {'user':'abc','id':12,'home':'def','mobile':1233}, 
      {'user':'abc','id':13,'home':'def','mobile':1555},]>

在上面的查询集中,相同id的用户不是一个接一个,所以函数没有得到想要的输出。

【问题讨论】:

  • 使用group_by会得到什么结果?
  • &lt;QuerySet[]&gt; 是结果。在shell中,当我调试时,它是Type Error : None type
  • 添加预期的输出和输入

标签: mysql django python-3.x orm django-queryset


【解决方案1】:

首先,更好地组织模型会有所帮助。您的user 模型中有重复的用户信息。如果您知道某个用户有多个手机号码,最好为此创建一个单独的模型:

class Mobile(models.Model)
    number = models.IntegerField()
    user = models.ForeignKey(User)

然后,当您进行查询并且想要获取所有手机号码时,您将首先在您的视图中获取所有使用users = User.objects.all() 的用户,然后在您的模板中:

{% for user in users %}
    {% for mobile in user.mobile_set.all %}
        <td>{{ user }}</td>
        <td>{{ mobile.number }}</td>
    {% endfor %}
{% endfor %}

作为旁注,我认为最好将模型命名为单数(User 而不是 Users

【讨论】:

  • 谢谢丹尼尔。这会起作用,但我无法实现它。我正在努力在一个巨大的产品中添加一个功能。如果我从users 模型中取出mobile 并为mobile 编写单独的模型,它将破坏依赖于users 模型的其他功能。我非常感谢您的解决方案,我知道它有效,但问题是我无法使用它。谢谢。
  • 我明白了。对于未来的问题,提及您遇到的任何限制都会有所帮助。甚至提及您知道但不适用于您当前情况的可能解决方案。但在我提供更新的答案之前,您可以使用 pandas 库吗?
  • @Daniel.H 感谢您的回复。我已经编辑了我提到的一个部分工作的解决方案的问题。我们的产品中不允许使用 Pandas。我们不想引入一个完整的库来解决这个问题。
  • 由于您的模型的结构方式(无法更改),可能值得考虑使用 pandas 之类的东西来在这个和未来的用例中处理您的数据。这可能是证明其使用合理性的一种方式。
  • 谢谢。我知道当有更多用户时,函数merge_values 有点耗时。但这里我以用户为例。在我们的产品中,users 的类比是不同的,它不会太大且耗时。我们也为多个用户提供了解决方案。查看解决方案。
【解决方案2】:

您可以使用您编写的函数,只需要更改是需要根据 id 对值进行排序。 因此,在从对象中获取值之前,order_by('id'),然后获取您需要的值并将其传递给您的函数以合并值。

例如。

query_set = Mymodel.objects.filter(name='Required').order_by('id')
values = query_set.values('id', 'field1', 'field2')
merged_values = merge_values(values)

【讨论】:

    猜你喜欢
    • 2020-12-24
    • 2016-05-09
    • 1970-01-01
    • 1970-01-01
    • 2018-08-07
    • 1970-01-01
    • 1970-01-01
    • 2022-01-12
    • 2013-09-06
    相关资源
    最近更新 更多