Как создать словарь с двумя наборами запросов из разных моделей, используя общее поле DateTimeField в качестве ключей словаря?

Я хочу создать словарь из двух моделей, имеющих общее поле dt. Это поле должно быть ключами словаря, а поля value и last - значениями ключей. Каков наиболее эффективный способ сделать это?

class Balance(models.Model):
    value = models.FloatField(default=0)
    dt = models.DateTimeField()

class Price(models.Model):
    last = models.FloatField(default=0)
    dt = models.DateTimeField()

Желаемый результат будет примерно таким :

{
    "2022-10-11T00:00:00Z": {
        "value": 151.05,
        "last": 1,
    },
    "2022-10-10T00:00:00Z": {
        "value": 151.1,
        "last": 1.1,
    },
    "2022-10-09T00:00:00Z": {
        "value": 152,
        "last": 1.1,
    },
    "2022-10-08T00:00:00Z": {
        "value": 154,
        "last": 1.23,
    }
}

Я мог бы перебирать все словари кверисетов с помощью вложенного цикла и искать элементы с общим dt затем заполнять ключ:значение в новом словаре, но это не элегантно и я не верю, что это эффективно.

Это подойдет, но не уверен в эффективности.

import datetime
balance = Balance.objects.annotate(date_only=Cast('dt',DateField())).values("date_only", "value")
price = Price.objects.annotate(date_only=Cast('dt',DateField())).values("date_only", "last")


data = {}
for (a, b) in zip(balance, price):
    str_date = a['date_only'].strftime("%Y/%m/%d")
    if a['date_only'] == b['date_only']:
        data[str_date] = {}
        data[str_date]['last'] = b['last']
        data[str_date]['value'] = a['value']


print(data)

Эта версия должна справиться с дополнительными несбалансированными строками Price, описанными OP в комментариях:

balances = (
    Balance
    .objects
    .annotate(date_only=Cast('dt', DateField()))
    .order_by("dt")
    .values("date_only", "value")
)
balance_dates = {balance.dt for balance in balances}
prices = (
    Price
    .objects
    .annotate(date_only=Cast('dt', DateField()))
    .filter(dt__in=balance_dates)
    .order_by("dt")
    .values("date_only", "last")
)

data = {
    balance['date_only'].strftime("%Y/%m/%d"): {
        "last": price["last"],
        "value": balance["value"],
    }
    for (balance, price) in zip(balances, prices)
}

Эффективность на стороне Python примерно такая же, как в ответе Хемала Пателя (на котором основан этот ответ)

Но запрос в db выиграет от индекса на dt столбце и может быть медленным, если таблицы очень большие.

В этом случае вам, вероятно, лучше использовать необработанный SQL для вывода набора данных, который вы хотите.

Вернуться на верх