在Django中比较两个字段而不使用F对象
我刚来这里,正在学习网页应用和搜索引擎优化。StackOverflow对我学习Python和Django帮助很大,非常感谢这个社区。现在我有个问题想问大家!
我有几个Django模型:
class Subscription(models.Model):
hotel = models.ForeignKey("Hotel", related_name="subscriptions")
tier = models.ForeignKey("Tier")
enquiry_count = models.PositiveIntegerField(default=0)
start_date = models.DateField(null=True, blank=True)
end_date = models.DateField(null=True, blank=True)
还有:
class Tier(models.Model):
name = models.CharField(max_length=32)
enquiry_limit = models.PositiveIntegerField(default=0)
我还有一个酒店模型,这里我会用一个非常简单的形式展示:
class Hotel(models.Model):
name = models.CharField("Hotel Name", max_length=128)
address = models.TextField("Address", blank=True)
town = models.CharField(max_length=64)
star = models.PositiveIntegerField(default=0, null=True, blank=True)
每个酒店都需要订阅才能出现在我的搜索结果中。每个订阅都有一个等级和一个查询限制。订阅会在到达结束日期或者查询次数达到上限时结束,也就是说,当它的查询次数达到这个等级的限制时。
我找到了一种简单的方法来实现这个功能,使用了F对象和排除条件,这在我的开发机器上运行得很好:
self.premium_hotels = Hotel.objects.select_related().exclude(
Q(subscriptions__end_date__lte=datetime.date.today()) | Q(subscriptions__enquiry_count__gte=F('subscriptions__tier__enquiry_limit')))
不过,这在网站的正式版本上不行,因为它运行的是Django 1.0。有没有什么建议可以在不使用F对象的情况下实现这个查询呢?
我知道最明显的解决办法是升级,但我们需要立即推出这个功能,而我需要时间来准备和测试,才能升级到Django 1.3。
提前谢谢大家!
2 个回答
0
在查询集中使用 extra
来插入自定义的SQL语句(可以查看条件和表格):
http://docs.djangoproject.com/en/dev/ref/models/querysets/#extra
例如(大致上 - 你需要确保SQL中的表名等匹配):
self.premium_hotels = Hotel.objects.select_related().exclude(
Q(subscriptions__end_date__lte=datetime.date.today())).extra(tables=["myapp_tier"], where=['myapp_subscriptions.enquiry_count
最好的办法是在本地运行你的查询 - 查看它生成了什么SQL,然后用这些信息来确定在调用 extra
时该放什么。
0
如果没有F对象,你就无法一步到位地完成查询。你可以选择不考虑enquiry_limit
,直接运行查询,然后再处理结果,把那些超过限制的酒店剔除掉。
下面的代码应该可以实现这个功能。
hotels = Hotel.objects.select_related().exclude(
Q(subscriptions__end_date__lte=datetime.date.today()))
self.premium_hotels = []
for h in hotels:
for sub in h.subscriptions.filter(start_date__lte=datetime.now(), end_date__gte=datetime.now()):
if sub.enquiry_count < sub.tier.enquiry_limit:
self.premium_hotels.append(h)
break