pythondjangoimagedjango-oscar

How to programatically add product images in django oscar?


I am currently programatically importing products into my product catalog, however, I am having difficulty uploading images for each product. Here's what my code looks like:

# frobshop/custom_utils/product_importer.py

from oscar.apps.catalogue.models import Product
...

for product in my_product_import_list:
    ...
    product_entry = Product()
    product_entry.title = my_product_title
    product_entry.product_class = my_product_class
    product_entry.category = my_category
    product_entry.primary_image = "product_images/my_product_filename.jpg"
    product_entry.save()

The details such as product title and product class are successfully saved when I check using the development server, however, I am unsure how to set an image for each product.

The entire product_images folder was initially located outside of my media directory, but since I wasn't getting any results, I copy pasted the entire folder of my images into the media directory but still with no results. I am assuming that quite a number of steps are being skipped, and maybe there's a convention on how to arrange images in the media directory. However, I am not sure where to find these steps and conventions.

Here's the portion of my settings.py file that deals with my installed apps, the media directory, and static files:

# frobshop/frobshop/settings.py

...

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',

    'django.contrib.sites',

    'django.contrib.messages',
    'django.contrib.staticfiles',

    'django.contrib.flatpages',

    'compressor',
    'widget_tweaks',
] + get_core_apps(['custom_apps.shipping', 'custom_apps.payment', 'custom_apps.checkout'])

...


STATIC_ROOT = 'static'
STATIC_URL = '/static/'
MEDIA_ROOT = 'media'
MEDIA_URL = '/media/'

For further clarity, here's my urls.py

from django.contrib import admin
from django.urls import path
from django.conf.urls import include, url
from oscar.app import application
from django.conf import settings
from django.conf.urls.static import static


urlpatterns = [
    url(r'^i18n/', include('django.conf.urls.i18n')),
    path('admin/', admin.site.urls),
    url(r'', application.urls),
] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)

Solution

  • I think you can do it like this using File class:

    from django.core.files import File
    
    for product in my_product_import_list:
        ...
        product_entry = Product()
        product_entry.title = my_product_title
        product_entry.product_class = my_product_class
        product_entry.category = my_category
        image = File(open("product_images/my_product_filename.jpg", 'rb'))
        product_entry.primary_image = image
        product_entry.save()
    

    Update

    probably you should use OSCAR_MISSING_IMAGE_URL in settings:

    OSCAR_MISSING_IMAGE_URL = "product_images/my_product_filename.jpg"  # relative path from media root
    

    Alternatively, you can use ProductImage, like this:

        from oscar.apps.catalogue.models import ProductImage
    
        product_entry = Product()
        product_entry.title = my_product_title
        product_entry.product_class = my_product_class
        product_entry.category = my_category
        product_entry.save()
        product_image = ProductImage()
        image = File(open("product_images/my_product_filename.jpg", 'rb'))
        product_image.original = image
        product_image.caption = "Some Caption"
        product_image.product = product_entry
        product_image.save()
    

    As ProductImage has a ForignKey relation to Product Model, and primary_image is a method in Product model, which takes image from ProductImage model, and returns the first one(ProductImage objects ordered by display_order field in that field)