我有一个具有日期时间字段的模型。现在给定一个特定的日期时间 - DT,我需要获取日期时间最接近 DT 的对象。这可能吗?
谢谢,
您可以通过两个查询和一些逻辑来获得它:
这个想法是在目标日期时间之后找到一个对象,在目标日期时间之前找到一个对象,然后返回其中一个:
# 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
要通过一个查询获得它,您必须从 ORM 中退出到原始 SQL。
我想完成 Pavel 的回答,如:
dt__gte
dt__lte
应改为使用。
提供确切日期时的过滤将无法正常工作。
只需将 Pavlel 的答案更改为:
def get_closest_to_dt(qs, dt):
greater = qs.filter(dt__gte=dt).order_by("dt").first()
less = qs.filter(dt__lte=dt).order_by("-dt").first()
if greater and less:
return greater if abs(greater.dt - dt) < abs(less.dt - dt) else less
else:
return greater or less
上述版本的通用实现,可与任意模型一起使用。
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