从 Django 中的 QuerySet 中排除对象实例的最佳方法是什么(在这种情况下,filter() 不是一个选项)?

What is the best way to exclude object instances from a QuerySet in Django (filter() not an option in this case)?

目前我能想到的最佳解决方案是在特定实例上单独使用 queryset.exclude(pk=instance.pk)。

场景是我需要为几个字段过滤模型查询集,然后还要检查日期字段是否与给定值匹配。通常我只会过滤 date=mydate 但在我的情况下我需要首先使用不同模型中存储的时区计算日期(这就是为什么我不能简单地使用过滤器)

现在我的代码(有效但似乎是一种 hack-y 过滤方式)看起来像这样:

user_tracks = HabitTrack.objects.filter(user=user)
filtered_user_tracks = user_tracks
for t in user_tracks:
    if not HabitEvent.objects.filter(user=user, track=t, date_expected=t.get_timezone_corrected_datetime_now().date(), post__isnull=True).exists():
        print("Excluding ", t.track_name, " with track specific time of ", t.get_timezone_corrected_datetime_now(), "from the list of options")
        filtered_user_tracks = filtered_user_tracks.exclude(pk=t.pk)
    else:
        print("Including ", t.track_name, " with track specific time of ", t.get_timezone_corrected_datetime_now(), "in the list of options")

对于上下文,这是我的 ModelForm 中的一个片段,因此我可以将表单选择限制为仅对用户“今天”可用的选项,其中“今天”是根据用户的时区计算的。

(这也是我第一次在SO上提问,所以如果需要澄清我会尽力清理我的问题,谢谢!)

在 HabitTrack 模型中:

def get_timezone_corrected_datetime_now(self):
    return datetime.now(self.timezone)

这可能很难。 django.db.models.functions.TruncDatefunctions.Now 可能有效,但我不知道是否可以使用 F 实例更改时区。如果您知道用户的足迹都在同一个时区,这会让事情变得更容易。否则,对于短期而言,您可能必须非规范化 HabitEvent.date_expected 以便您拥有完整的日期时间和本地化日期。

编辑:

更好的答案

您还可以使用数据库的函数创建自己的 Func 实例。如果您使用的是 postgres,timezone(zone, timestamp) (docs 9.9.3) 可能会满足您的需求。

您的函数可能如下所示:

class LocalizedNow(Func):
    function = 'timezone'
    template = '%(function)s(%(expressions)s, NOW())'

然后您可以在查询中使用它:

HabitEvent.objects.filter(expected_date=LocalizedNow('track__timezone'))