我正在使用python和Django开展一个侧面项目。它是一个跟踪某个网站某些产品价格的网站,然后显示所有产品的历史价格。
所以,我在Django中有这个类:
class Product(models.Model):
price = models.FloatField()
date = models.DateTimeField(auto_now = True)
name = models.CharField()
然后,在我的views.py中,因为我想在表格中显示产品,如下所示:
+----------+--------+--------+--------+--------+....
| Name | Date 1 | Date 2 | Date 3 |... |....
+----------+--------+--------+--------+--------+....
| Product1 | 100.0 | 120.0 | 70.0 | ... |....
+----------+--------+--------+--------+--------+....
...
我使用以下类进行渲染:
class ProductView(objects):
name = ""
price_history = {}
因此,在我的模板中,我可以轻松地将每个product_view对象转换为一个表行。我还要通过上下文传递所有可用日期的排序列表,以构建表格的头部,并在该日期获得每个产品的价格。
然后我在视图中有逻辑,将一个或多个产品转换为此ProductView对象。逻辑看起来像这样:
def conversion():
result_dict = {}
all_products = Product.objects.all()
for product in all_products:
if product.name in result_dict:
result_dict[product.name].append(product)
else:
result_dict[product.name] = [product]
# So result_dict will be like
# {"Product1":[product, product], "Product2":[product],...}
product_views = []
for products in result_dict.values():
# Logic that converts list of Product into ProductView, which is simple.
# Then I'm returning the product_views, sorted based on the price on the
# latest date, None if not available.
return sorted(product_views,
key = lambda x: get_latest_price(latest_date, x),
reverse = True)
根据Daniel Roseman和zymud,添加get_latest_price:
def get_latest_price(date, product_view):
if date in product_view.price_history:
return product_view.price_history[date]
else:
return None
我省略了转换中获取最新日期的逻辑。我有一个单独的表,只记录我运行我的价格收集脚本的每个日期,该脚本向表中添加新数据。因此,获取最新日期的逻辑基本上是在具有最高ID的OpenDate表中获取日期。
所以,问题是,当产品增长到很大的数量时,我如何对product_views列表进行分页?例如如果我想在我的Web应用程序中看到10个产品,如何告诉Django只从DB中获取这些行?
我不能(或者不知道如何)使用django.core.paginator.Paginator,因为要创建我想要的10行,Django需要选择与这10个产品名称相关的所有行。但要弄清楚要选择哪10个名字,首先需要获取所有对象,然后找出哪些对象在最近的日期具有最高价格。
在我看来,唯一的解决方案是在Django和DB之间添加一些东西,比如缓存,来存储ProductView对象。但除此之外,有没有办法直接对produvt_views列表进行分页?
答案 0 :(得分:0)
我想知道这是否有意义:
基本的想法是,因为我需要按照"最新"的价格对所有product_views进行排序。日期,我首先在数据库中执行该操作,并且只获取产品名称列表以使其成为"可分页的"。然后,我将进行第二次数据库查询,以获取具有这些产品名称的所有产品,然后构建那么多product_views。它有意义吗?
为了清除它,代码如下:
所以而不是
#def conversion():
all_products = Product.objects.all()
我这样做:
#def conversion():
# This would get me the latest available date
latest_date = OpenDate.objects.order_by('-id')[:1]
top_ten_priced_product_names = Product.objects
.filter(date__in = latest_date)
.order_by('-price')
.values_list('name', flat = True)[:10]
all_products_that_i_need = Product.objects
.filter(name__in = top_ten_priced_product_names)
# then I can construct that list of product_views using
# all_products_that_i_need
然后对于第一个之后的页面,我可以修改[:10]来说[10:10]或[20:10]。
这使得代码分页更容易,并且通过将适当的代码拉入单独的函数,它也可以执行Ajax和所有那些花哨的东西。
但是,出现了一个问题:这个解决方案需要为每个查询进行三次DB调用。现在我在同一个盒子上运行所有东西,但我仍然想把这个开销减少到两个(One或Opendate,另一个用于Product)。
是否有更好的解决方案可以解决分页问题和两次数据库调用?