Django более быстрый способ хранить изображения локально с URL-адреса? - PullRequest
0 голосов
/ 29 мая 2020

Я работаю над веб-сайтом, на котором я хочу заполнить данные о продукте из внешнего API. Этот api содержит данные о сотнях продуктов, и у каждого продукта есть десятки вариантов. Каждый продукт и данные имеют свои изображения, которые я использую ImageField Django из моделей для локального хранения. Теперь проблема в том, что существует более 15000 изображений, а заполнение данных изображений занимает целую вечность. Вот структура API:

{
...
Single Product Image: ...
    { Product Variant1: ..., [list of 4 images] }
    { Product Variant2: ..., [list of 4 images] }
    { Product Variant3: ..., [list of 4 images] }
}

Каждый продукт имеет где-то от 10-50 вариаций. Вот что я сделал. Для изображений вариантов я использую таблицу отношений «многие-к-одному» для хранения всех изображений каждого варианта:

models.py:

class ProductsVariation(models.Model):
    ....

class VariationImages(models.Model):
    prd_id = models.ForeignKey(ProductsVariation, on_delete=models.CASCADE)
    img = models.ImageField(
        upload_to=settings.MEDIA_ROOT + 'product_variation')

get_products.py:

from django.core.files import File
from tempfile import NamedTemporaryFile
import requests

for product in api_data: #Loop over main product
    ...
    main_product_request = requests.get(product['IMAGE_NAME'])

    main_img_temp = NamedTemporaryFile(delete=True)
    main_img_temp.write(main_product_request.content)
    main_img_temp.flush()

    main_product.prd_img.save(product['GENERIC_NAME'] + ".jpg", File(main_img_temp), save=True)
    main_product.save()
    # Populate this product's variants
    for variants in product['Product']: # Loop through each variant of this product
        ....
        for img in variants['Images']: # For each variant, save their images to DB
            vari = VariationImages.objects.create(prd_id=prd_variant)

            vari_product_request = requests.get(img)

            vari_img_temp = NamedTemporaryFile(delete=True)
            vari_img_temp.write(vari_product_request.content)
            vari_img_temp.flush()

            vari.img.save(product['GENERIC_NAME'] + ".jpg", File(vari_img_temp), save=True)
            vari.save()

Чтобы уточнить, изображение main_product и изображения вариантов go находятся в отдельных таблицах в БД. Другого способа сохранить изображения я не нашел. Может есть способ лучше хранить изображения из API? А может проблема в том, как я это делаю? Я не знаю, как это оптимизировать.

РЕДАКТИРОВАТЬ: После дополнительных испытаний я совершенно уверен, что узкое место возникает из-за файлов, сохраняемых на диск. Я попытался сохранить файлы прямо в локальное хранилище из URL-адресов API, и это оказалось очень медленным. Чтобы сохранить около 500 изображений, требуется примерно 30-40 секунд. Я пробовал использовать urllib.request.urlretrieve, Pillow и dload, BytesIO, но все они дают примерно одинаковый результат.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...