Django模型和orm以及外键问题

disho6za  于 2023-03-04  发布在  Go
关注(0)|答案(2)|浏览(186)

我想得到所有相关模型的数据,但我只得到了部分相关数据,为了避免N +1问题,我使用了select_related()和prefetch_related()方法。
起初,我有这些模型:

class OrderList(models.Model):
    order_id=models.CharField(max_length=100)
    order_status=models.CharField(max_length=100)

class ProductInOrder(models.Model):
    order_key=models.ForeignKey(OrderList, on_delete=models.CASCADE, related_name="order_key")
    
    product_id=models.CharField(max_length=100)
    product_price=models.CharField(max_length=100)

class MemosInProduct(models.Model):
    product_key=models.ForeignKey(ProductInOrder, on_delete=models.CASCADE, related_name="product_key")

    memo=models.CharField(max_length=100)
    blahblah some codes...

这些模型的一个简短示例是,一个OrderList具有许多ProductInOrder(一对多),一个ProductInOrder具有许多MemosInProduct(一对多)
然后,我在django shell中运行以下代码:

order_list=OrderList.object.select_related("order_key", "product_key").all()

我排除了所有订单数据以及与之结合的所有相关数据(产品、备忘录):* * 除外**
订单列表[0].订单关键字[0].产品关键字[0].备注订单列表[0].订单关键字[0].产品关键字[1].备注订单列表[0].订单关键字[1].产品关键字[0].备注...
但我得到了:输出
select_related中给定的字段名无效:"订单密钥"、"产品密钥"。选项包括:(无)
我也试过这个:

order_list=MemosInProduct.object.select_related("order_key", "product_key").all()

但是输出不匹配。

p1tboqfb

p1tboqfb1#

Django Documentationselect_related获取相关对象(外键关系),如果外键存在于模型中,这意味着它获取向前相关的对象。
例如:

def OrderList(models.Model):
    order_id=models.CharField(max_length=100)
    order_status=models.CharField(max_length=100))

因为在这个模型中没有正向关系,所以不能使用select_related,所以Django会引发错误。
select_related中给定的字段名无效:"订单密钥"、"产品密钥"。选项包括:(无)
但是,您可以将select_related用于ProductInOrderMemosInProduct,因为ProductInOrderMemosInProduct分别具有order_keyproduct_key的正向关系。
对于向后关系(查询模型中不存在外键),应该使用prefetch_related
因此,在您的情况下,查询应该是

OrderList.objects.prefetch_related("order_key", "order_key__product_key").all()

在这里,您可以看到我还将product_key更改为order_key__product_key,因为product_key不是OrderList的相关对象,而是ProductInOrder的相关对象
这只是理论上的,也许你需要在你的查询中使用Prefetch

OrderList.objects.prefetch_related(Prefetch('order_key', queryset=ProductInOrder.objects.all(), to_attr='order_keys')).all()

不过,请阅读Django文档了解详细信息。

nfg76nw0

nfg76nw02#

我会用相反的方法来解决这个问题,检索MemosInProduct对象及其相关对象,例如,要用order_status = 'overdue'获取与OrderList对象相关的所有内容(我猜):

queryset = MemosInProduct.objects.order_by(
               'product_key__order__key__order_id',
               'product_key__product_id'
            ).select_related(
               'product_key', 'product_key__order_key'
            ).filter(
               product_key__order__key__order_status='overdue'
            )

在检索对象的循环中,如果跟踪循环中的上一项,则可以知道何时已前进到不同的ProductInOrder或OrderList

last_object = None
for memo in queryset:
    product = memo.product_key
    order = product.order_key
    if ( last_object is None or 
         last_object.product_key.order_id != order.id ):
       # do stuff for a changed order compared to last (or the first loop)
    if ( last_object is None or 
         last_object.product_key_id != product.pk) :
       # do stuff for a changed product compared to last

    # do stuff for every memo
    last_object = memo

或者,您可以构造列表的列表的列表,当传递到要呈现的上下文中时,这在模板语言中很容易实现。
记住,Python赋值是名称绑定,而不是对象复制,所以这类事情是高效的,在循环中,乘积和顺序由select_related预取。

相关问题