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
相关产品推荐
相关产品推荐

