我有一个历史模型,如下所示
class History(models.Model):
class Meta:
app_label = 'subscription'
ordering = ['-start_datetime']
subscription = models.ForeignKey(Subscription, related_name='history')
FREE = 'free'
Premium = 'premium'
SUBSCRIPTION_TYPE_CHOICES = ((FREE, 'Free'), (Premium, 'Premium'),)
name = models.CharField(max_length=32, choices=SUBSCRIPTION_TYPE_CHOICES, default=FREE)
start_datetime = models.DateTimeField(db_index=True)
end_datetime = models.DateTimeField(db_index=True, blank=True, null=True)
cancelled_datetime = models.DateTimeField(blank=True, null=True)
现在我有一个像下面这样的查询集过滤
users = get_user_model().objects.all()
queryset = users.exclude(subscription__history__end_datetime__lt=timezone.now())
问题在于,在上面的排除中,它检查特定历史记录对象的所有行的end_datetime。但我只想将它与第一行历史对象进行比较。
以下是特定历史对象的外观。所以我想编写一个查询集过滤器,它只能在第一行进行日期时间比较。
答案 0 :(得分:0)
您可以使用Model Manager method。文档并非完全具有描述性,但您可以按照以下方式执行操作:
class SubscriptionManager(models.Manager):
def my_filter(self):
# You'd want to make this a smaller query most likely
subscriptions = Subscription.objects.all()
results = []
for subscription in subscriptions:
sub_history = subscription.history_set.first()
if sub_history.end_datetime > timezone.now:
results.append(subscription)
return results
class History(models.Model):
subscription = models.ForeignKey(Subscription)
end_datetime = models.DateTimeField(db_index=True, blank=True, null=True)
objects = SubscriptionManager()
然后:queryset = Subscription.objects().my_filter()
不是可复制的答案,但显示了管理员的使用。鉴于您所寻找的内容的特殊性,我认为没有办法通过简单的filter()
和exclude()
来获取它。
在不知道你的最终目标是什么的情况下,很难说这是否可行,但你是否考虑在订阅模型中添加一个属性来表明你想要的是什么?例如,如果您尝试让订阅结束的每个人都结束:
class Subscription(models.Model):
@property
def ending(self):
if self.end_datetime > timezone.now:
return True
else:
return False
然后在您的代码中:queryset = users.filter(subscription_ending=True)
答案 1 :(得分:0)
我已经尝试过django的所有表达王(aggregate,query,conditional),但无法解决问题所以我选择RawSQL它解决了这个问题。
我使用下面的SQL选择第一行,然后比较end_datetime
SELECT (end_datetime > %s OR end_datetime IS NULL) AS result
FROM subscription_history
ORDER BY start_datetime DESC
LIMIT 1;
如果在接下来的两天内未找到带有queryset过滤器链接的解决方案,我会选择接受的答案。