Django-对子查询执行子查询,然后获取所有关联的字段

时间:2019-03-08 18:42:29

标签: django

我的数据格式如下:

collection_name | type       | manufacturer | description | image_url
---------------------------------------------------------------------------
beach           | bed        | company a    | nice bed    | 1.jpg
beach           | king bed   | company a    | nice bed    | 1.jpg
beach           | nightstand | company a    | nice ns     | 1.jpg
grass           | chest      | company a    | nice chest  | 2.jpg
apple           | chest      | company a    | nice chest  | 3.jpg
fiver           | chest      | company b    | good chest  | 4.jpg

和类似的模型:

class Product(models.Model):
    collection_name = models.TextField(null='true',blank='true')
    type = models.TextField(null='true',blank='true')
    manufacturer = models.TextField(null='true',blank='true')
    description = models.TextField(null='true',blank='true')
    image_url = models.TextField(null='true',blank='true')

此刻我要在我的应用中做什么?

  • 通过id链接到产品(使用隐藏的pk id字段),
  • 然后为该ID获取集合名称
  • 获取具有该收藏名称的产品列表
  • 从具有特定集合名称*的产品集中获取不同的image_url列表*
  • 对于新集中的每个image_url,获取所有具有相同image_url的记录

我要这样做的原因是,如您在上面的示例数据中所看到的,不同的产品有时会重用同一张图像(某些图像在一幅图像中显示多个产品)。我只希望显示一次每个图像,同时能够显示与给定图像相关联的所有产品(其中可能有多个)。

我一直在基于this答案考虑做类似以下的事情,我认为它遵循上面给出的逻辑,但是我不确定这是正确的方法。

collectionname = product.objects.filter(id=id).values('collection_name').distinct()
images = product.objects.filter(collection_name__in=collectionname).values("image_url").distinct()
results = []
for img in images:
    pbis = product.objects.filter(collection_name__in=collectionname, image_url=img['image_url'])
    obj = {"image": img['image_url'], "items":[{"attr":pbi.attr, ...} for pbi in pbis]}
    results.append(obj)

在这里,我的方法有哪些明显的错误?有没有更好,更清洁的方法?如果相关,则后端为postgres。

我想要在模板中执行的操作如下:

{% for instance in image_url %}
{{ collection_name }} Collection:
<img src="{{ instance }}">
Product type: {{ instance.type }}
Product Description: {{ instance.description }}
{% endfor %}

应该输出以下内容:

对于1.jpg:

Beach Collection
<img src="1.jpg">
Product type: bed
Product Description: nice bed
Product type: king bed
Product Description: nice bed
Product type: nightstand
Product Description: nice ns

对于2.jpg:

Grass Collection
<img src="2.jpg">
Product type: chest
Product Description: nice chest

对于3.jpg:

Apple Collection
<img src="3.jpg">
Product type: chest
Product Description: nice chest

对于4.jpg:

Fiver Collection
<img src="4.jpg">
Product type: chest
Product Description: good chest

1 个答案:

答案 0 :(得分:1)

听起来好像有几个额外的模型可以更轻松地处理您的内容:CollectionImage。对于您的图片模型,我建议您使用Django的ImageField,它的功能比仅仅将URL保存为文本更全面。要使用ImageField,您需要安装Pillow,它是Python图像库(PIL)当前维护的分支。使用命令行上的pip install Pillow执行此操作。 ImageField具有内置属性url,因此您仍然可以轻松访问图像的URL(请参见下面的模板)。然后您的新models.py可以是:

# models.py
class Image(models.Model):
    source = models.ImageField(upload_to='my_media_path')

class Collection(models.Model):
    name = models.CharField(max_length=30)
    products = models.ManyToManyField(Product, blank=True)
    feature_image = models.ForeignKey(Image, related_name='collections', on_delete=models.SET_NULL)

class Product(models.Model):
    ...
    image = models.ForeignKey(Image, related_name='products', on_delete=models.SET_NULL) 
    # or ManyToManyField if a product has several images

然后,您将获得与所选产品具有相同图像的其他产品:

bucket = Product.objects.get(pk=1)
bucket.image.products.all()
<Product: Bucket>
<Product: Spade>

对于您的模板-主要按集合组织内容:

# query
collections = Collection.objects.all()

# template.html
{% for collection in collections %}
    <h1>{{ collection.name }}</h1>
    <img src="{{ collection.feature_image.source.url }}">
    {% for product in collection.products.all %}

        <p>{{ product.name }}</p>
        <p>{{ product.description }}</p>

    {% endfor %}
{% endfor %}

编辑:

没有时间实施上述方法,那么您提到的方法将可以正常工作。您可以在视图代码中更改一行以使其更简单:

...
obj = {"image": img['image_url'], "items": pbis}

然后将results字典传递给模板上下文时:

{% for collection in results %}
    {{ collection.items.0.collection_name }} Collection:
    <img src="{{ collection.image }}">
    {% for item in collection.items %}
        <p>Product type: {{ item.type }}</p>
        <p>Product Description: {{ item.description }}</p>
    {% endfor %}
{% endfor %}