ValueError The 'image' attribute has no file associated with it

112 Views Asked by At

I'm having problem with Django templates not receiving any data in image.url when having more than one object in context QuerySet all other data is working fine. If there is only one object in QuerySet, image.url works fine. I'm storing images on S3 and there is nothing wrong with the images or the bucket permission.

I'm new with Django templates is there anything I'm missing?

Here is the code:


models.py

`
from django.db import models
from django.core.validators import MaxValueValidator, MinValueValidator
from django.utils.translation import gettext_lazy as _
from site_content.models import PageCategory, Page
from site_content.utils import file_upload_to

class PpcOffersPagesManager(models.Manager):

   def get_queryset(self):
       return super(PpcOffersPagesManager, self) \
          .get_queryset() \
          .filter(page_category__category_name="ppc-offer-page")


class PpcOfferPages(Page):

   objects = PpcOffersPagesManager()

   class Meta:
       proxy = True

   def __str__(self):
       return self.page_name

   def save(self, *args, **kwargs):
       self.page_category = PageCategory.objects.get(category_name="ppc-offer-page")
       self.page_site_type = "ppc"
       super(PpcOfferPages, self).save(*args, **kwargs)


class PpcOfferContent(models.Model):
    related_page = models.ForeignKey(
       Page, verbose_name=_("Page"),
       related_name="ppc_offer_content",
       on_delete=models.SET_NULL, 
       null=True
   )
   order = models.IntegerField(verbose_name=_("Order of offer appearance"), default=0)
   image = models.ImageField(
       verbose_name=_("Casino banner image"), 
       upload_to=file_upload_to, 
       null=True, 
       blank=True,
       help_text="Casino banner image, Size (300x500)"
   )
   header = models.CharField(
       verbose_name=_("Header text"), 
       max_length=500, 
       null=False, 
       blank=False
   )
   is_active = models.BooleanField(verbose_name=_("Is offer active"), default=True)

   class Meta:
       verbose_name = _('PPC_Offer Page Content')
       verbose_name_plural = _('PPC_Offer Page Content')

   def __str__(self):
       return self.related_page.page_name
`

views.py

`
from django.views.generic import DetailView
from ppc_site_control.models import PpcOfferContent

class PpcOffersDetailView(DetailView):
   model = PpcOfferContent
   def get_template_names(self):
       page = self.model.objects \
           .filter(related_page__slug = self.kwargs['slug']) \
           .first().related_page.page_template.template_path
       return page

   def get_object(self):
       return self.model.objects \
           .filter(related_page__slug=self.kwargs['slug']) \
           .filter(is_active=True) \
           .order_by('offer_order')

   def get_context_data(self, **kwargs):
       context = super().get_context_data(**kwargs)
       return context
`

.html

`
{% extends "slotsselection/base.html" %}
{% load i18n static reviews sstags %}

{% for offer in object %}
   <div>
       <div >
           <img loading="lazy" src="{{offer.offer_image.url}}" alt="image">
       </div>
       <div>
       <p>{{offer.header}}</p>
       <p>{{offer.is_active }}</p>
       </div>
  <div>
{% endfor %}
`

I tried sending data in the context as new key and adding QuerySet object again with .values()(to exclude possibility of problem with "get_object" query) still have the same result. When I remove the images from template, all other data is displayed accordingly, without images.

I also tried with ListView same error ValueError The 'image' attribute has no file associated with it.

Data in context:

`{'object': <QuerySet [<PpcOfferContent: PPC PageName>, 
 <PpcOfferContent: PPC PageName>, <PpcOfferContent: PPC PageName>, 
 <PpcOfferContent: PPC PageName>]>, 'view': 
 <ppc_site_control.views.PpcOffersDetailView object at 0x7f2d8230f430>}
`
1

There are 1 best solutions below

0
Kristijan Kitevski On

The problem was caused from missing images because they were not required in the model the simplest solution is adding "if" condition in the template:

`{% if offer.offer_image %}
    <img loading="lazy" src="{{offer.image.url}}" alt="Casino image">
 {% endif %}`

I also manage to find workaround:

views.py

`from slotsselection.components.s3_settings import MEDIA_URL` 

then in the context data I added

 `def get_context_data(self, **kwargs):
    context = super().get_context_data(**kwargs)
    context['media_url'] = MEDIA_URL
    return context
 `

.html

and in html I removed .url to get the half of the link as string and added media_url

`<img loading="lazy" src="{{media_url}}{{offer.offer_image}}" alt="Casino image">`

not best approach but it works to.