【问题标题】:Django - Get a single timestamp per foreign key ID (MySQL)Django - 为每个外键 ID 获取一个时间戳(MySQL)
【发布时间】:2020-03-14 02:35:12
【问题描述】:

在下面的模型中,我无法为每个外键 ID 获取一条记录,我已经尝试过这个查询,但它目前似乎没有做任何事情

我使用了一个有效的 RAW 查询,但我不能对其使用过滤器。我还创建了一个列表并从 QuerySet 中删除了重复项,但我再次无法过滤它,因为它是一个列表

查询:

queryset = BGPData.objects.annotate(max_timestamp=Max('timestamp')).filter(timestamp=F('max_timestamp')).select_related(
    'device_circuit_subnet__subnet',
    'device_circuit_subnet__device',
    'device_circuit_subnet__circuit',
    'device_circuit_subnet__device__site',
    )

型号:

class BGPData(models.Model):
    device_circuit_subnet = models.ForeignKey(DeviceCircuitSubnets, verbose_name="Device", on_delete=models.CASCADE)
    bgp_peer_as = models.CharField(max_length=20, verbose_name='BGP Peer AS', blank=True, null=True)
    bgp_session = models.CharField(max_length=10, verbose_name='BGP Session', blank=True, null=True)
    bgp_routes = models.CharField(max_length=10, verbose_name='BGP Routes Received', blank=True, null=True)
    service_status = models.CharField(max_length=10, verbose_name='Service Status', blank=True, null=True)  
    timestamp = models.DateTimeField(auto_now=True, blank=True, null=True)  

即时测试的样本数据(打印为字典),“device_circuit_subnet_id”应该只有一条记录:“10”,最新的一条。

我想要每个 device_circuit_subnet_id 的最新记录,因此查询应该返回 3 个结果而不是 4 个,因为有 2 个项目具有相同的 device_circuit_subnet_id。

我读到 distinct 用于此,但运行的是 MySQL,还有其他方法吗?

谢谢

[{
        "id": 4,
        "device_circuit_subnet_id" : "10",
        "hostname": "EDGE",
        "circuit_name": "MPLS",
        "subnet": "172.1.1.1",
        "subnet_mask": "/30",
        "bgp_session": "1w2d",
        "bgp_routes": "377",
        "bgp_peer_as": "1",
        "service_status": "Up",
        "timestamp": "2019-11-18 16:16:17"
    },
    {
        "id": 5,
        "device_circuit_subnet_id" : "11",
        "hostname": "INT-GW",
        "subnet": "1.1.1.1",
        "subnet_mask": "/24",
        "bgp_session": null,
        "bgp_routes": null,
        "bgp_peer_as": null,
        "service_status": "unknown",
        "timestamp": "2019-08-07 14:46:00"
    },
    {
        "id": 8,
        "hostname": "EDGE",
        "device_circuit_subnet_id" : "20",
        "circuit_name": "MPLS 02",
        "subnet": "172.2.1.1",
        "subnet_mask": "/30",
        "bgp_session": null,
        "bgp_routes": null,
        "bgp_peer_as": null,
        "service_status": "unknown",
        "timestamp": "2019-11-15 16:18:30"
    },
    {
        "id": 9,
        "hostname": "EDGE",
        "device_circuit_subnet_id" : "10",
        "circuit_name": "MPLS",
        "subnet": "172.1.1.1",
        "subnet_mask": "/30",
        "bgp_session": "1w3d",
        "bgp_routes": "385",
        "bgp_peer_as": "1",
        "service_status": "Up",
        "timestamp": "2019-11-18 16:16:44"
    }
]

谢谢

【问题讨论】:

  • 不是一个完美的解决方案,但您可以迁移到 PostgreSQL,然后使用 .order_by('-timestamp').distinct('device_circuit_subnet')

标签: django django-rest-framework django-queryset


【解决方案1】:

Django 查询集以惰性方式进行评估。因此,此查询只会从数据库中获取一条记录。由于-前缀,时间戳的排序是降序的,所以最新的时间戳值将是第一条记录。

queryset = BGPData.objects.all().order_by(
    #prefix field name to order by with `-` to use Descending order
    '-timestamp'
).select_related(
    'device_circuit_subnet__subnet',
    'device_circuit_subnet__device',
    'device_circuit_subnet__circuit',
    'device_circuit_subnet__device__site',
)[0]

【讨论】:

  • 对不起,也许我解释错了,这只会给我一条记录,我想要每个 device_circuit_subnet_id 的最新记录,所以查询应该返回 3 个结果而不是 4 个,因为有 2 个项目带有相同的 device_circuit_subnet_id
【解决方案2】:

你试过了吗?


from django.db.models import Max, F

max_timestamp = Max('device_circuit_subnet__bgpdata__timestamp')
result = BGPData.objects.annotate(ts=max_timestamp).filter(timestamp=F('ts')).select_related(...)

我不确定这个查询的性能,但它会起作用:) :)

【讨论】:

  • 这不会只得到一条记录吗?我希望每个 device_circuit_subnet_id 获得一条记录,因此在上面的数据中有 3 个唯一的 device_circuit_subnet_id。我想获取每个唯一 ID 的最新记录
  • result 将是一个具有 N 记录的查询集,其中 N 是总数device_circuit_subnet唯一值的数量
  • 您是否在您的环境中运行了 sn-p?有什么问题吗?
  • 我必须更改我的环境,我将再次更改它以便我可以尽快测试,谢谢
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2022-09-23
  • 1970-01-01
  • 2022-09-24
  • 2018-05-04
  • 1970-01-01
  • 1970-01-01
  • 2020-07-15
相关资源
最近更新 更多