如何在Django中使用select_related或prefetch_related加入多个相关模型?

时间:2019-12-06 11:22:06

标签: django django-models django-templates

我要在模板中显示5个相关模型。对于每个Collection,我想显示属于相应集合(Product)的所有ProductCollection。我需要为每个产品提供的信息是:名称(ProductAlias)和默认图像(ProductImage)。
原始查询应类似于:

SELECT c.name, pa.name, pi.image
FROM Collection c JOIN ProductCollection pc ON c.collection_id = pc.collection_id
JOIN Product p ON pc.product_id = p.product_id
JOIN ProductAlias pa on p.product_id = pa.product_id
JOIN ProductImage pi on p.product_id = pi.product_id
WHERE pi.default = 'True' and pa.market_id = 1

models.py

class Collection(models.Model):
  name = models.CharField()

class Product(models.Model):
  video = models.URLField()

class ProductCollection(models.Model):
  collection = models.ForeignKey(Collection, on_delete=models.CASCADE)
  product = models.ForeignKey(Product, on_delete=models.CASCADE)

class ProductAlias(models.Model):
  product = models.ForeignKey(Product, on_delete=models.CASCADE)
  market = models.ForeignKey(Market, on_delete=models.CASCADE)
  name = models.CharField()

class ProductImage(models.Model):
  product = models.ForeignKey(Product, on_delete=models.CASCADE)
  image = models.ImageField()
  default = models.BooleanField()

我将产品名称分成另一种型号,因为一种产品根据其销售地区有很多名称。产品也有许多图像。但是我只需要每个market_id = 1使用全局名称(default = True)和默认图像(Product)。

我目前在views.py上使用基于函数的视图的尝试(由于在模板渲染期间我已经出现ValueError,因此尚未应用过滤器):

def collection_view(request):
  # tried to chain the prefetch_related on multiple models but failed.  
  collections = Collection.objects.prefetch_related('productcollection__product__id', 'productalias_set', 'productimage_set').all()
  context = { 'collection_list': collections }
  return render(request, 'product_visualizers/collection.html', context)

我目前对模板collection.html的尝试:

{% for collection in collection_list %}
  <h3>{{ collection.name }}</h3>

  {% for pair in collection.productcollection_set.all %}  # what should I loop here to show the product name and product image?
    <p>{{ pair.product.product_id }}</p>  # tried to display the product_id but failed.
    <p>{{ productalias_name }}</p>  # product name.
    <img src="{{ image.url }}">  # product image.
  {% endfor %}

{% endfor %}

1 个答案:

答案 0 :(得分:1)

您的问题不是由使用预取/选择相关引起的。这些仅用于减少重复查询。您的pair.product.product_id应该是pair.product.id

关于如何设置模型,您对一个产品有许多ProductAliases,而对一个产品有许多ProductImage。您需要遍历它们的两个集合以获取图像和名称字段。

{% for alias in pair.product.productalias_set.all %}
    {{ alias.name }}
{% endfor %}
{% for product_image in pair.product.productimage_set.all %}
    {{ product_image.image }}
{% endfor %}