Django Queryset - получить самую новую запись по внешнему ключу - PullRequest
0 голосов
/ 17 января 2020

Я вижу много похожих запросов, но ни один из них, похоже, не работает для того, что я после,

У меня есть таблица как таковая:

class BGPData(models.Model):
    subnet = models.ForeignKey(Subnet, verbose_name="Subnet", on_delete=models.CASCADE, blank=True, null=True)
    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)
    timestamp = models.DateTimeField(auto_now=True, blank=True, null=True)  

Цель: I хотел бы получить самую новую запись по внешнему ключу только на su bnet.

Попытки пока что ниже: -

bgp_data_query = BGPData.objects.filter(subnet__get_bgp=True,subnet__wb_bgp=True) \
                                .annotate(last_updated=Cast(TruncSecond('timestamp', DateTimeField()), CharField()))

d = BGPData.objects.annotate(max_timestamp=Max('timestamp')).filter(timestamp=F('max_timestamp'))

Вот что-то, что я не совсем понимаю, но я не уверены, что это такое ...

Спасибо

, поэтому, если моя таблица содержит:

subnet_id | routes | timestamp
    1     |   10   | 01-01-20 17:30
    1     |   10   | 01-01-20 17:20
    1     |   10   | 01-01-20 17:10
    2     |   20   | 01-01-20 17:30

Я бы вернул

subnet_id | routes | timestamp
    1     |   10   | 01-01-20 17:30
    2     |   20   | 01-01-20 17:30

Ответы [ 3 ]

1 голос
/ 17 января 2020

Один метод, использующий .values() для группировки по Subnet перед аннотированием с максимальной отметкой времени:

from django.db.models import Max

BGPData.objects.values('subnet').annotate(timestamp=Max('timestamp'))

Недостатком использования этого метода является то, что в результате получается список словарей, которые содержат только ключи / значения полей для указанных вами полей. Это не проблема, если эти поля являются единственными полями, которые вы ищете.

Если вам нужен доступ к дополнительным полям в модели BGPData или из связанных моделей, вы можете использовать Window функция . К сожалению, когда я заканчивал это, я понял, что оконные функции не разрешены в фильтре , поэтому это не работает как решение.

from django.db.models import F, Max, Window

data = (
    BGPData.objects
    .annotate(
        max_timestamp=Window(
            expression=Max('timestamp'),
            partition_by=[F('subnet')],
            order_by=F('timestamp').desc(),
        )
    )
    # .filter(timestamp=F('max_timestamp')
)
0 голосов
/ 19 января 2020

То, что вы ищете, эквивалентно этому SQL запросу, выраженному в Django терминах ORM:

SELECT * FROM bgpdata GROUP BY subnet_id HAVING max(timestamp);

Этот запрос элегантен и прост для понимания, но, похоже, что нет Очевидный способ реализовать такой запрос в Django ORM. Вообще говоря, вы можете написать подзапрос для извлечения всех необходимых столбцов, что-то вроде этого:

from django.db.models import Max

BGPData.objects.filter(
    timestamp__in=BGPData.objects.values('subnet').annotate(
        timestamp__max=Max('timestamp')
    ).values('timestamp__max')
)
0 голосов
/ 17 января 2020

Попробуйте это:

BGPData.objects.filter(timestamp = max(timestamp)).distinct(subnet_id)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...