Django查询一对多关系

时间:2016-04-19 14:51:30

标签: python mysql django

我有2个表,Order和OrderDetails,在OrderDetails上我有一个字段'product_type'。

从表中我想要获取列表中的所有product_type字段。

Order.objects.filter(pk=1).annotate(type=F('product_type'))

我希望type值返回所有产品类型的列表,而不仅仅是第一个结果,例如'chair'。

例如:type = ['chair', 'pencil']

型号:

class Order(models.Model):
    user = models.ForeignKey(User, related_name="orders")

class OrderDetails(models.Model):
    order = models.ForeignKey(Order, related_name="details")
    quantity = models.SmallIntegerField(null=False, blank=False)
    product_type = models.CharField(null=False, blank=False)

3 个答案:

答案 0 :(得分:3)

这不是您可以或应该尝试使用查询集注释实现的内容。这是因为注释仅适用于CountSum等聚合函数。

如果我正确理解了您的问题,您可以在迭代查询集时获取此信息:

for order in Order.objects.all():
    types = order.details.values_list('product_type', flat=True)

您可以通过为每个订单预取相关的OrderDetail行来提高效率:

for order in Order.objects.prefetch_related('details'):
    types = order.details.values_list('product_type', flat=True)

或者,您可以使用此方法从每个订单中检索一些值:

queryset = Order.objects.values('id', 'user_id', 'details__product_type')

它应该执行单个数据库查询。但是,请参阅此处有关其工作原理的说明:https://docs.djangoproject.com/en/1.9/ref/models/querysets/#values

您的查询集将输出dicts而不是模型实例。你不会得到一个很好的product_type列表...而是你会得到重复的行,如:

[
    {'id': 1, 'user_id': 1, 'product_type': 'chair'},
    {'id': 1, 'user_id': 1, 'product_type': 'table'},
    {'id': 2, 'user_id': 3, 'product_type': 'chair'},
    ...
]

...所以你必须将python中的这些行分组到你想要的数据结构中:

from collections import OrderedDict

grouped = OrderedDict()
for order in Order.objects.values('id', 'user_id', 'details__product_type'):
    if order['id'] not in grouped:
        grouped[order['id']] = {
            'id': order['id'],
            'user_id': order['user_id'],
            'types': set(),
        }
    grouped[order['id']]['types'].add(order['details__product_type'])

答案 1 :(得分:0)

也许您可以尝试类似以下内容(未经测试):

# first get the order whose product details you want
o = Order.objects.get(pk=1)

# now get a list of the different product_types
# for order details associated with that order
product_types = OrderDetails.objects.filter(order=o).values('product_type')

如果我误解你的问题,请告诉我。

答案 2 :(得分:0)

我需要做类似的事情,最后得到两个这样的查询(扩展了@brianpck的想法):

# first get the orders whose product details you want
o = Order.objects.values_list('id', flat=True)

# now get a list of the different product_types
# for order details associated with that order
product_types = OrderDetails.objects.filter(order__in=o).values('product_type').distinct()