Django ORM Группировка по полю по другому полю

У меня есть модель SessionLog

class SessionLog(models.Model):
    user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
    ip_address = models.CharField(max_length=20, null=True)

Я хочу получить список ip-адресов только для дублирующихся пользователей. То есть, если разные пользователи вошли в систему с одним и тем же IP-адресом, я хочу получить список таких IP-адресов.

Также я хочу получить список пользователей, которые вошли в систему с того же ip.

Так что ожидаемый результат будет

[
  {
    "ip_address": "170.221.23.56",
    "user_id": [21, 23, 45]
  },
  {
    "ip_address": "170.221.23.58",
    "user_id": [25, 23, 45]
  },
]

Как я могу реализовать с помощью django ORM?

Если вы используете PostgreSQL, вы можете сделать следующее:

from django.db import models
from django.contrib.postgres.fields import ArrayField


class Array(models.Subquery):
    template = 'ARRAY(%(subquery)s)'
    output_field = ArrayField(base_field=models.TextField())

user_ids = SessionLog.objects.filter(
    ip_address=models.OuterRef("ip_address")
).values_list("user_id", flat=True)

sessions = SessionLog.objects.distict("ip_address").order_by("ip_address").annotate(
    user_ids=Array(user_ids)
)

for session in sessions:
    print(session.ip_address, session.user_ids)

Вы можете сначала преобразовать наборы запросов в списки:

ip_list = list(SessionLog.objects.values_list('ip_address'))
user_list = list(SessionLog.objects.values_list('user'))

затем создайте другой список для идентификации уникальных ip-адресов:

unique_addresses = list(set(ip_list))

наконец, используйте enumerate для получения индекса ip-адресов, а затем используйте эти индексы для получения соответствующих значений пользователей следующим образом:

Dict = {} 
users = [] 
for n in unique_addresses: 
    indices = [i for i, x in enumerate(ip_list) if x == n] 
        for p in indices: 
            users.append(user_list[p]) 
    Dict[n] = status 
    status = [] 
print(Dict)

Формат вывода немного неопрятный, но вы можете получить доступ к пользователям определенного ip-адреса, используя Dict['ip_address']

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

Вернуться на верх