Запросы в наборе запросов группируются в один запрос, используя Django - PullRequest
0 голосов
/ 06 сентября 2018

У меня есть запрос, подобный приведенному ниже.

<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: Я думал о слиянии двух запросов в один, если значение 'user' совпадает в обоих запросах. Для этого нам нужно сделать много проверок, используя условные операторы, которые работают медленно, когда там много пользователей.

Решение 2: Я искал в Google и нашел Group By Django, но он не работает. Я попробовал ниже

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

Пожалуйста, укажите, как два запроса могут быть объединены в один на основе «пользователя», а после «мобильного» должно быть два значения.

Редактировать: я передам этот набор запросов в шаблон через представление, где рисуется таблица. В настоящее время для каждого запроса в таблице содержится одна строка. Так как вышеприведенный набор запросов имеет четыре запроса, у нас будет четыре строки. Но я хочу отобразить информацию только в двух строках, поскольку «id» и «user» одинаковы. Код для шаблона ниже:

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

Обязательный ключ - это словарь, который содержит ключи, которые используются для отображения в таблице. Пример: * +1021 *

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

Элемент get - это функция, которая получает значение при передаче ключа.

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

Значением параметра для функции является весь набор запросов. Но эта функция работает, если в наборе запросов только один пользователь, как указано выше. Но если там это несколько пользователей, это не удается.

Редактировать 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},]>

В приведенном выше наборе запросов пользователи с одинаковыми идентификаторами не находятся один за другим, поэтому функция не смогла получить желаемый результат.

Ответы [ 2 ]

0 голосов
/ 12 сентября 2018

Вы можете использовать функцию, которую вы написали, требуется только изменение, необходимо упорядочить значения на основе идентификатора. Поэтому, прежде чем брать значения из объектов, 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)
0 голосов
/ 07 сентября 2018

Для начала было бы полезно организовать ваши модели лучше. У вас есть информация о пользователе, дублированная в вашей 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)

...