You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Django ORM如何按IP分组查询多用户登录IP及对应用户ID

Django ORM 实现多账号登录IP查询

你当前的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)

需求是筛选出关联至少2个不同用户的IP,同时返回每个IP对应的去重用户ID列表,结构和示例一致。

方案1:数据库原生聚合(推荐,性能更好)

适用于PostgreSQL、MySQL 8.0+、SQLite 3.30+等支持数组聚合的数据库:

from django.db.models import Count, ArrayAgg

result = list(
    SessionLog.objects
    # 过滤掉IP为空的无效日志
    .exclude(ip_address__isnull=True)
    # 按IP地址分组
    .values("ip_address")
    .annotate(
        # 统计每个IP对应的去重用户数
        distinct_user_count=Count("user_id", distinct=True),
        # 聚合所有去重的用户ID为数组
        user_id=ArrayAgg("user_id", distinct=True)
    )
    # 只保留存在多个不同用户登录的IP
    .filter(distinct_user_count__gt=1)
    # 移除多余的统计字段,只保留需要返回的字段
    .values("ip_address", "user_id")
)

方案2:低版本数据库兼容写法

如果使用MySQL 5.x等不支持ArrayAgg的数据库,用两次查询+内存分组实现,数据量未达百万级时性能差距可忽略:

from collections import defaultdict

# 第一步:筛选出所有符合多用户登录条件的IP
target_ips = (
    SessionLog.objects
    .exclude(ip_address__isnull=True)
    .values("ip_address")
    .annotate(user_cnt=Count("user_id", distinct=True))
    .filter(user_cnt__gt=1)
    .values_list("ip_address", flat=True)
)

# 第二步:查询这些IP对应的所有日志记录,内存分组
ip_user_mapping = defaultdict(set)
for ip, user_id in SessionLog.objects.filter(ip_address__in=target_ips).values_list("ip_address", "user_id"):
    ip_user_mapping[ip].add(user_id)

# 组装为要求的返回结构
result = [
    {"ip_address": ip, "user_id": list(user_ids)}
    for ip, user_ids in ip_user_mapping.items()
]

结果说明

两种方案返回的结果完全匹配需求格式,自动处理了用户ID去重,避免同一用户多次登录同一IP产生重复数据:

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

内容的提问来源于stack exchange,提问作者Yery cs

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.03 08:36:26