在外键

时间:2016-09-20 20:29:58

标签: python django sqlite

我尝试过不同的查询数据的方法,但仍会导致数据库大量ping。

我尝试过使用select_related

以下是我的模特:

class Order(models.Model):
    num = models.CharField(max_length=50, unique=True)

class OrderInfo(models.Model):
    info = models.CharField(max_length=100, unique=True)
    datetime = models.DateTimeField(auto_now_add=True, blank=True)
    order_fk = models.ForeignKey(Order)

我想要实现的目标:

OrderInfo包含大量与Order相关的信息。

我想要的是能够从数据库中获取最新的OrderInfo,但我希望它对Order是唯一的。独特的部分是我努力减少查询量的地方。

ois = OrderInfo.objects.order_by('-datetime').select_related('order_fk')

当我尝试过滤时,它会对每个订单进行查询,以检查查询的唯一性。

For instances:
_ = [oi.order_fk for oi in ois] # queries reach to 20k, takes too long.

此外,我只需要限制我得到的响应数量,但我需要先知道有多少唯一Orders才能限制它。

任何人都知道一种最小化这些查询的正确方法,或者我可能需要重构我的模型。

注意:

  • Django 1.7
  • Python 2.7
  • SQLite的

2 个答案:

答案 0 :(得分:1)

每个订单有多少OrderInfo个对象?如果它很小,最简单的方法是使用prefetch_related并在python中进行过滤:

class Order(models.Model):
    num = models.CharField(max_length=50, unique=True)
    @property
    def latest_order_info(self):
        return max(self.orderinfo_set.all(), key=attrgetter('datetime')

然后在您的应用程序代码中,您可以执行以下操作:

orders = Order.objects.filter(...).prefetch_related('orderinfo_set')

这有点浪费,但根据我的经验,除非父模型有很多孩子,否则通常不会成为瓶颈。

答案 1 :(得分:0)

基于this stack overflow answer to a similar question,我认为您只需要将其拆分为两个查询,以期减少与数据库挂钩的数量。

由于您使用的是SQLite,因此您无法访问DISTINCT ON,因此请尝试以下操作:

from django.db.models import Q, Max
import operator

ois = OrderInfo.objects.values('order_id').annotate(max_datetime=Max('datetime'))
filters = reduce(operator.or_, [(Q(order_id=oi['order_id']) &
    Q(datetime=oi['max_datetime'])) for oi in ois])
filtered_ois = OrderInfo.objects.filter(filters)

解释这是做什么的(再次,这是基于链接的堆栈溢出答案):

  • 获取按order_id分组的OrderInfo对象,并在具有该OrderInfo的所有order_id个对象中注释具有最大日期时间的对象。
  • 使用这些值在OrderInfo对象上创建新过滤器。
  • OrderInfo个对象上使用过滤器并将其返回。