Возможно ли в Django захватить поле с первого внешнего ключа? - PullRequest
0 голосов
/ 03 ноября 2019

Я пытаюсь оптимизировать мой запрос Django. Прямо сейчас я собираю все продукты, затем перебираю их и делаю отдельный запрос для URL-адреса изображения «feature».

Есть ли способ получить URL для объекта внешнего ключа Image, гдеfeature = True в исходном запросе?

Текущий код:

products = Product.objects.values('id')

products_list = []
​
for product in products:
​
    image_url = Image.objects.filter(product=product["id"]).order_by('-feature').values("url").first().get("url", None)

    image = resize_image(image_url, 500)

    products_list.append({
        "id": product["id"]
        "image": image,
    })

return Response({ "products": products_list }, status=status.HTTP_200_OK)

Что бы я хотел сделать:

products = Product.objects.values('id', 'images__url')

​products_list = []

for product in products:

    image = resize_image(product["images__url"], 500)

    products_list.append({
        "id": product["id"]
        "image": image,
    })

return Response({ "products": products_list }, status=status.HTTP_200_OK)

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

Чтобы исправить это, я попытался добавить .distinct ('id') кконец, но потом я получил эту ошибку:

NotImplementedError('annotate() + distinct(fields) is not implemented.')

После этого я не был уверен, как действовать, или если это возможно?

Модели (для справки):

class Product(models.Model):
    title = models.CharField(max_length=255)

class Image(models.Model):
    product = models.ForeignKey(Product, on_delete=models.CASCADE, null=True, related_name="images")
    url = models.CharField(max_length=255, blank=True)
    feature = models.BooleanField(default=False)

Любая помощь очень ценится!

РЕДАКТИРОВАТЬ: Добавлен еще немного кода для контекста

1 Ответ

1 голос
/ 03 ноября 2019

Выполнить этот запрос в поиске значений сложно, так как вы не вернете продукты, у которых нет показанных изображений

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

products = Product.objects.prefetch_related('images')
for product in products:
    print(product.images.all()) # This will not perform an additional query

Вы можете отфильтровать набор запросов, который заполняет обратную связь, используя Предварительная выборка объекты

products = Product.objects.prefetch_related(Prefetch(
    'images',
    queryset=Image.objects.filter(feature=True),
    to_attr='featured_images'
))
for product in products:
    print(product.featured_images.all()) # Will return all featured images

Мы можем использовать отдельное предложение, чтобы вернуть только 1 изображение для каждого продукта

products = Product.objects.prefetch_related(Prefetch(
    'images',
    queryset=Image.objects.filter(feature=True).order_by('product').distinct('product'),
    to_attr='featured_image'
))

Теперь в вашем шаблоне вы можете зациклить этот атрибут и вернуть только одно изображение

{% for image in product.featured_image.all %}
    {{ image.url }}
{% endfor %}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...