0

Suppose you are making a site to simply list your products.

You want to upload an unspecified number of pictures for your each of your products. So you, following Django's many-to-one documentation, make two models:

# files stored under my_app/static/my_app/product_images/product_<id>/<img_name>
def product_img_dir_path(instance, filename):
    return 'my_app/static/my_app/product_images/product_{0}/{1}'.format(instance.product.id, filename)

class Product(models.Model):
    name = models.CharField ...
    ... # other attributes of the product, e.g. price, etc

class ProductImage(models.Model):
     product = models.ForeignKey("Product", on_delete=models.CASCADE)
     image = models.ImageField(upload_to=product_img_dir_path)

Now if I want all of the images for say product 1, I can retrieve them using:

ProductImages.objects.filter(product__pk=1)

My question starts here.

Suppose you want an index page which just shows the listings for all of your products and for simplicity, the first image associated with each product.

You make a template page with

{% for product in product list %}
    <div class="product-listing" style="display:inline">
        <!-- image for product goes here -->
        <!-- brief description goes here -->
    </div>
{% endfor %}

where product_list was passed in your context:

 # inside /my_app/views.py
 def index(request):
     ...
     context = {"product_list": Product.objects.all()}
     ...

Question: what is the best way to also have access to the images for displaying the images in the template page?

Currently I thought constructing a parallel image list would suffice:

# inside /my_app/views.py

def index(request):
    ...
    product_list = Product.objects.all()
    image_list = [product.productimage_set.all()[0] for product in product_list]

    context = {"product_list": product_list, "image_list": image_list}
    ...

and then somehow using the forloop counter to get the corresponding image for the product.

e.g.

{% for product in product list %}
    <div class="product-listing" style="display:inline">
        <img src="{{ image_list[<forloop counter>].image.url }}" />
        <!-- brief description goes here -->
    </div>
{% endfor %}

Is there a better way to do this?

SumNeuron
  • 4,850
  • 5
  • 39
  • 107

2 Answers2

1

As long as you can access product.productimage_set, you can try to iterate it in your template and do not pass it as a view context.

In your Django template:

{% for product in product_list %}
    <div class="product-listing" style="display:inline">
        {% for product_image in product.productimage_set.all %}
            <img src="{{ product_image.image.url }}" />
            <!-- brief description goes here -->
        {% endfor %}
    </div>
{% endfor %}
wencakisa
  • 5,850
  • 2
  • 15
  • 36
  • You can also access it in your template. I forgot to write `.all` in my answer, now it is edited. See this: https://stackoverflow.com/questions/6217638/access-foreignkey-set-directly-in-template-in-django – wencakisa Aug 16 '17 at 09:31
  • Where it throws 404? When you try to access your `image.url` ? – wencakisa Aug 16 '17 at 09:34
  • yes, I have one app so instead of `/my_app/` I am just using `/`. The url it provides is correct `my_app/product/static/product_images/product_1/image_1.jpg` – SumNeuron Aug 16 '17 at 09:36
  • Have you configured your `MEDIA_ROOT` in `settings.py` correctly? See this link, I think it will be helpful: https://docs.djangoproject.com/en/1.11/ref/models/fields/#django.db.models.FileField.storage – wencakisa Aug 16 '17 at 09:44
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/152028/discussion-between-wencakisa-and-sumneuron). – wencakisa Aug 16 '17 at 09:44
  • I hit you up on chat – SumNeuron Aug 16 '17 at 10:03
0

I think that it will be easier for you to solve this if you simplify your design by moving the images to your Product model. If you want to save the path to an image it will be easier to use CharField, but if you want to save many paths why not using JSONField?

My suggestion look like this:

class Product(models.Model):
    name = models.CharField(null=True, blank=True)
    main_image = models.CharField(null=True, blank=True) # Optional
    images = JSONField(null=True, blank=True)
shlomta1
  • 148
  • 1
  • 11