django用非模型对象分页

时间:2014-05-19 02:08:43

标签: django django-models pagination django-views

我正在使用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列表进行分页?

1 个答案:

答案 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)。

是否有更好的解决方案可以解决分页问题和两次数据库调用?