15

日時フィールドを持つモデルがあります。特定の日時 - DT が与えられた場合、日時が DT に最も近いオブジェクトを取得する必要があります。これは可能ですか?

ありがとう、

4

4 に答える 4

19

2 つのクエリといくつかのロジックで取得できます。

アイデアは、ターゲットの日時の直後と直前のオブジェクトを 1 つ見つけて、それらの 1 つを返すことです。

# this method is on the model's manager
def get_closest_to(self, target)
    closest_greater_qs = self.filter(dt__gt=target).order_by('dt')
    closest_less_qs    = self.filter(dt__lt=target).order_by('-dt')

    try:
        try:
            closest_greater = closest_greater_qs[0]
        except IndexError:
            return closest_less_qs[0]

        try:
            closest_less = closest_less_qs[0]
        except IndexError:
            return closest_greater_qs[0]
    except IndexError:
        raise self.model.DoesNotExist("There is no closest object"
                                      " because there are no objects.")

    if closest_greater.dt - target > target - closest_less.dt:
        return closest_less
    else:
        return closest_greater

1 つのクエリでそれを取得するには、ORM から生の SQL にドロップアウトする必要があります。

于 2013-04-06T21:03:41.633 に答える
1

任意のモデルで使用する上記のバージョンの一般的な実装。

def get_closest(
    *,
    qs: models.QuerySet,
    datetime_field: str,
    target_datetime: Union[datetime.datetime, datetime.date],
) -> models.Model:

    greater = qs.filter(**{
        f'{datetime_field}__gte': target_datetime,
    }).order_by(datetime_field).first()

    less = qs.filter(**{
        f'{datetime_field}__lte': target_datetime,
    }).order_by(f'-{datetime_field}').first()

    if greater and less:
        greater_datetime = getattr(greater, datetime_field)
        less_datetime = getattr(less, datetime_field)
        return greater if abs(greater_datetime - target_datetime) < abs(less_datetime - target_datetime) else less
    else:
        return greater or less
于 2020-08-16T12:47:51.363 に答える