Django - Выполнение подзапроса в подзапросе с последующим получением всех связанных полей - PullRequest
0 голосов
/ 08 марта 2019

У меня есть данные в следующей форме:

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')

Что я пытаюсь сделать в своем приложении в данный момент:

  • Ссылка на товар по идентификатору (используя скрытое поле идентификатора pk),
  • Затем для этого идентификатора получите имя коллекции
  • Получите список продуктов с таким названием коллекции
  • Получить список отдельных image_url из набора продуктов с определенным названием коллекции *
  • для каждого image_url в новом наборе, получить все записи с одинаковым image_url

Причина, по которой я хочу это сделать, заключается в том, что, как вы можете видеть на приведенных выше примерах данных, разные продукты иногда используют одно и то же изображение (некоторые изображения показывают несколько продуктов на одном изображении).Я хочу показать каждое изображение только один раз, при этом я могу показать все продукты, связанные с данным изображением (которых может быть несколько).

Я думал сделать что-то вроде следующего, основываясь на этот ответ, который, я думаю, следует логике, приведенной выше, но я не уверен, что это правильный подход.

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)

Каковы очевидные ошибки в моем подходе здесь, иЕсть ли лучший, более чистый способ сделать это?В случае, если это уместно, backend является 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 Ответ

1 голос
/ 09 марта 2019

Похоже, что пара дополнительных моделей облегчит работу с вашим контентом: Collection и Image. Для вашей модели изображения я бы порекомендовал использовать 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 %}

EDIT:

Без времени для реализации вышеуказанного подхода, упомянутый вами подход будет работать нормально. Вы можете изменить одну строку в коде представления, чтобы упростить ее:

...
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 %}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...