【问题标题】:Join in Django ORM加入 Django ORM
【发布时间】:2014-08-30 01:18:17
【问题描述】:

我想执行 Django Join 操作。我该怎么做?

我的模型是:-

class ShipmentScanMapping(models.Model):
    barcode = models.CharField(max_length = 255)
    shipment_id = models.ForeignKey('Shipment',related_name ='scans')

class ShipmentPPTLMapping(models.Model):
    pptl_id = models.CharField(max_length = 255)
    shipment_id = models.ForeignKey('Shipment', related_name = 'pptls')

class Shipment(models.Model):
    job_id = models.CharField(max_length = 255)
    time = models.DateTimeField( auto_now_add = True, db_index = True)

我在 SQL 中的查询是:-

select * from data_shipmentpptlmapping inner join data_shipmentscanmapping where data_shipmentpptlmapping.shipment_id = data_shipmentscanmapping.shipment_id and data_shipmentscanmapping.barcode = 'xyzabc';

我想获取那些具有barcode = 'xyzabc' 的对象,然后引用 key shipment_id of datashipmentscanmapping = shipping_id of datashipmentpptlmapping。

我现在正在做。

shipment_scan_obj = ShipmentScanMapping.objects.filter(barcode = barcode).values('shipment_id')['shipment_id']
if shipment_scan_obj:
            shipment_pptl_mapping_obj = ShipmentPPTLMapping.objects.filter(shipment_id__in = shipment_id_list)
            if shipment_pptl_mapping_obj:
                    .....do something......

这是我尝试过的。它会抛出一个错误 Cannot resolve keyword 'shipmentscanmapping' into field.:-

shipment_pptl_mapping_obj = ShipmentPPTLMapping.objects.filter(shipmentscanmapping__barcode = barcode,shipment_id = shipmentscanmapping__shipment_id)
        if shipment_pptl_mapping_obj:
              ......dosomething.......

如何在 Django ORM 中执行连接操作?

【问题讨论】:

  • 你能在models.py中显示相关的模型子类吗?至少是相关的字段定义。
  • 哦。我会更新它。
  • 我刚刚更新了它。请看一看。

标签: mysql django django-models django-orm


【解决方案1】:

在 Django 中,您只能跨外键关系(或多对多,或反向外键)加入。在这种情况下,您可以通过 Shipment 类加入到 ShipmentScanMapping。试试这个:

ShipmentPPTLMapping.objects.filter(shipment_id__scans__barcode="xyzabc")

这表示“查找所有引用 Shipments 且具有条形码‘xyzabc’的scansShipmentScanMapping 对象)的 ShipmentPPTLMapping 对象”。

这不是唯一的方法;您可以使用更复杂的子查询系统来跳过访问 Shipment 表的中间步骤。这是子查询方法的一个可能示例(这更复杂也更不寻常,所以我不太确定这段代码是否正确!):

ShipmentPPTLMapping.objects.filter(shipment_id__in=Shipment.filter(scans__barcode="xyzabc"))

这也可以工作,根本不接触 Shipment 表,可能会以依次执行两个相对快速的查询为代价,但警告编码器:

ShipmentPPTLMapping.objects.filter(shipment_id__in=ShipmentScanMapping.objects.filter(barcode="xyzabc").values_list('shipment_id', flat=True))

通过 Shipment 将其作为连接是在 Django 中表达这种愿望的最清晰、最直接的方式。无论您使用哪种方法,我都建议您查看由 ORM 生成的 SQL(通过自省或日志记录),以确保您了解幕后发生的事情。

顺便说一下,我建议不要使用“shipment_id”作为外键的名称,因为 Django 会自动在字段名称的末尾添加一个“_id”来跟踪 ID——无 _id 的名称指外键另一侧的行,而不仅仅是数字 ID。相反,只需将其称为“装运”。

【讨论】:

  • 我想知道它的复杂方法。因为加入 3 个表实际上可能需要很多时间(根据我的代码)。
  • 我很确定多重连接会很快,但我会尝试在答案中添加子查询方法示例。
【解决方案2】:
ShipmentScanMapping.objects.filter(barcode = barcode).values('shipment_id')['shipment_id']

我认为问题来自这里,values 返回一个 ValuesQuerySet,这似乎是一个 dict 数组:Django doc。所以你可以像这样循环它

arr = ShipmentScanMapping.objects.filter(barcode = barcode).values('shipment_id')
for element in arr:
    print element ['shipment_id']

【讨论】:

    猜你喜欢
    • 2014-02-11
    • 1970-01-01
    • 2020-03-11
    • 2019-08-12
    • 2012-03-28
    • 2020-05-26
    • 2014-05-19
    • 2022-01-21
    • 1970-01-01
    相关资源
    最近更新 更多