我的应用程序中有一个搜索功能,它接收“城市”和“持续时间”输入(两个列表)并返回按照“评级”包排序的前30个匹配“包”结果。
如果所有参数都是列,则很容易实现,但“duration”和“rating”是计算属性。这意味着我不能使用标准的Django查询来过滤包。它是seems that Django的“额外”方法是我需要在这里使用的方法,但我的SQL并不好,这看起来像一个非常复杂的查询。
我应该在这里使用额外的方法吗?如果是这样,该陈述会是什么样的?
下面复制的适用代码。
#models.py
class City(models.Model):
...
city = models.CharField(max_length = 100)
class Package(models.Model):
....
city = models.ManyToManyField(City, through = 'PackageCity')
@property
def duration(self):
duration = len(Itinerary.objects.filter(package = self))
return duration
@property
def rating(self):
#do something to get the rating
return unicode(rating)
class PackageCity(models.Model):
package = models.ForeignKey(Package)
city = models.ForeignKey(City)
class Itinerary(models.Model):
# An Itinerary object is a day in a package, so len(Itinerary) works for the duration
...
package = models.ForeignKey(Package)
#functions.py
def get_packages(city, duration):
cities = City.objects.filter(city = city) # works fine
duration_list = range(int(duration_array[0], 10), int(duration_array[1], 10) + 1) # works fine
#What I want to do, but can't because duration & rating are calculated properties
packages = Package.objects.filter(city__in = cities, duration__in = duration_array).order_by('rating')[:30]
答案 0 :(得分:3)
首先,不要在Querysets上使用len(),使用count()。 https://docs.djangoproject.com/en/dev/ref/models/querysets/#when-querysets-are-evaluated
其次,假设您正在使用您的评级属性计算平均评级,您可以使用注释: https://docs.djangoproject.com/en/dev/ref/models/querysets/#annotate
然后您可以执行以下操作:
queryset = Package.objects.annotate({'duration': Count('related-name-for-itinerary', distinct=True), 'rating': Avg('packagereview__rating')})
Where" PackageReview"是一个我刚刚制作的假冒模型,它有一个ForeignKey to Package,并且有一个"等级"字段。
然后您可以按照此处所述过滤带注释的查询集: https://docs.djangoproject.com/en/dev/topics/db/aggregation/#filtering-on-annotations (注意annotate - >过滤器和过滤器 - > annotate之间的子句顺序差异。
属性是在运行时计算的,因此您实际上无法使用它们进行过滤或类似的操作。