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