HTML show media files as images on hover

Hi, I am trying to show some image files upon hovering some text but I am struggling with my HTML “img src” part, I do not know what is the way to pass my arguments into the img src portion for my receipts images. Right now, the error I’m getting is ‘ImageFieldFile’ object has no attribute ‘endswith’

Here is my settings file, the main point being the media portions since it is where the images are saved

STATIC_URL = '/static/'
MEDIA_URL = '/media/'
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
STATICFILES_DIRS=(os.path.join(BASE_DIR, 'static'),)

Here is the models.py for the claims, the main point being the “claim_receipt” image field.

class Claims(models.Model) :

    name = models.CharField(max_length=128)

    company = models.CharField(max_length=128)


    claim_type = models.CharField(max_length=256)

    currency = models.CharField(max_length=128)

    # claim number and amount cannot be empty so null=F

    claim_number = models.IntegerField(null=False)

    claim_amount = models.DecimalField(max_digits=20, decimal_places=2, null=False)

    claim_date = models.DateTimeField()

    # must have claim receipt so null = F

    claim_receipt = models.ImageField(null=False, upload_to="receipts/")


    def __str__(self):

        return self.name

This is my view.py file

class ClaimView(LoginRequiredMixin, View):

    def get(self, request):

        claimcount = Claims.objects.all()

    

        contxt = {'claim_count': claimcount}

        

        return render(request, 'claims/claim_list.html', contxt)



class ClaimCreate(LoginRequiredMixin, CreateView):


    model = Claims



    template_name = 'claims/claim_form.html'

 

    fields = '__all__'



    success_url = reverse_lazy('claims:all')

class ClaimUpdate(LoginRequiredMixin, UpdateView):

    model = Claims

    template_name = 'claims/claim_form.html'

    fields = '__all__'

    success_url = reverse_lazy('claims:all')

class ClaimDelete(LoginRequiredMixin, DeleteView):

    model = Claims

    template_name = 'claims/claim_confirm_delete.html'

    fields = '__all__'

    success_url = reverse_lazy('claims:all')

my urls.py file

app_name = 'claims'

urlpatterns = [

    

    path('', views.ClaimView.as_view(), name='all'),

    path('create/', views.ClaimCreate.as_view(), name='claim_create'),


    path('<int:pk>/update/', views.ClaimUpdate.as_view(), name='claim_update'),

    path('<int:pk>/delete/', views.ClaimDelete.as_view(), name='claim_delete'),

]

And finally my claim_list.html file, where I am having an issue with the “img src” part.

<!-- Make claim list -->

<!doctype html>

<html lang="en">

  <head>

      <!-- Add CSS for tables -->

    <style>

        table {

          font-family: arial, sans-serif;

          border: 2px solid black;

          width: 100%;

          text-align: left;

          

        }

        

        th {

        background-color: #04AA6D;

        border: 1px solid #000000;

        color: white;

        

}

        

        td {

          background-color:rgba(185, 185, 185, 0.3);

          border: 1px solid #000000;

          text-align: center;

        }

        </style>

        

<!-- extend bootstrap after CSS table otherwise will interfere -->

{% extends "claim_bootstrap.html" %}

{% load static %}

{% block content %}

  <h1>Claim List</h1>

  <!-- if list is present -->

  {% if claim_count %}

  <!-- claim table -->

  <table>

    <tr>

      <th>Name</th>

      <th>Company</th>

      <th>Type</th>

      <th>Currency</th>

      <th>Claim number</th>

      <th>Amount</th>

      <th>Date</th>

      <th>Receipt</th>

      <th>Edit</th>

      <th>Remove</th>

    </tr>

    

      {% for claim in claim_count %}

      <tr>

      <!-- list each of the items -->

      <td>{{ claim.name }}</td>

      <td>{{ claim.company }}</td>

      <td>{{ claim.claim_type }}</td>

      <td>{{ claim.currency }}</td>

      <td>{{ claim.claim_number }}</td>

      <td>{{ claim.claim_amount }}</td>

      <td>{{ claim.claim_date }}</td>

      <td onmouseover="imageAppear()" onmouseout="imageDisappear()">{{ claim.claim_receipt }}

        <!-- img src issue, can't load the receipt images -->

        <img src="{% static claim.claim_receipt %}" id="place-holder-1" style="zindex: 100; position: absolute; visibility: hidden;"/></td>

      <td><a href="{% url 'claims:claim_update' claim.id %}">Update</a></td>

      <td><a href="{% url 'claims:claim_delete' claim.id %}">Delete</a></td>

      </tr>

      {% endfor %}

    

  </table>

  <a href="{% url 'claims:claim_create' %}">Add another claim here</a>

  <!-- javascript for receipt to appear on hover -->

  <script>

    function imageAppear() { 

    document.getElementById('place-holder-1').style.visibility = "visible";}

    function imageDisappear() { 

    document.getElementById('place-holder-1').style.visibility = "hidden";}

    </script>

  <!-- if no claim present -->

  {% else %}

  <p>There are no claims in the library.</p>

  <a href="{% url 'claims:claim_create' %}">Add a claim here</a>

{% endif %}

{% endblock %}

I am sure there is an error in this part: {% static claim.claim_receipt %}
because when I use a normal image url, there is no error message shown. Now my question is, how do I parse an image variable inside? Is it even possible? I tried searching abit on the net but I couldn’t find much so I had to ask here. I’ve read online that it is hard for image files to have a primary key, so that’s a barrier there.
Also, I can’t exactly “load” the media, like how I can just {% load static %}, so what should I do?

I can view the images in the file “media/receipts/imagename” just fine but how should I include it as part of the img src?
Any help would be appreciated!

Please post your Claims model. (More specifically, it would be helpful to know what the field “claim_receipt” is.)

Now to address a couple items.

This does not “load” anything in your page. It’s a directive to the Django template engine to load the static tag.

Whether or not this is right will depend upon what the variable “claim_receipt” is.
Be mindful that the src attribute is a URL.

Also, is this an image provided by the system (a static file) or is this a file that has been uploaded? (a media file) If the latter, then you would not use the static tag to identify the url.

If this is a FileField (or ImageField), see the FileField api for the attribute to use to access the URL needed to access the actual image.

Hi Ken,

I did upload my claims model in my first post, which contained the claims_receipt image field. I’ll just highlight the receipt field here

claim_receipt = models.ImageField(null=False, upload_to="receipts/")

Ok, I’ll remove the load static portion. I know that the src attribute is a URL, but I’ve seen from other websites that they used “/filename/imagename” too, so I thought it would be ok.
This image is a media file that has been uploaded by the user.
Thank you for the link, I have looked at it and I’m thinking that I need to add on a .save for my image model to save the image.

Oops, I missed it.

If you’re loading any static files on that page (JS, CSS), you’ll still want that {% load static %} directive.

That too is a URL. It just happens to implicitly refer to the same site.

I don’t know if that’s true -

implies to me that you’re saving the images.

The issue I noticed is that with:
<img src="{% static claim.claim_receipt %}" id="place-holder-1" style="zindex: 100; position: absolute; visibility: hidden;"/></td>
(or changed to: <img src="claim.claim_receipt" id="place-holder-1" style="zindex: 100; position: absolute; visibility: hidden;"/></td>)

claim.claim_receipt is not a URL - it’s an ImageField. An ImageField contains a url, but the ImageField is not a url.

The link provided previously identifies all the different data attributes available with an ImageField. You want to use the url attribute of that field.

Yes! Thank you so much! I changed it to

<img src="{{claim.claim_receipt.url}}" id="place-holder-1" style="zindex: 100; position: absolute; visibility: hidden;"/></td>

and now the image shows!
Now I just need to fix 1 last thing, since all of them shows the same image as the first

Fixed using jQuery.
Couldn’t get unique image id for each image, therefore upon hover everything just displayed the first image.

Replace the relevant code segment with this

<td onmouseover="$(this).children('img').css('visibility','visible');" onmouseout="$(this).children('img').css('visibility','hidden')">{{ claim.claim_receipt }}
        <img  src="{{ claim.claim_receipt.url }}" style="zindex: 100; position: absolute;"/></td>

One easy way to fix that is to generate the id attribute from some unique attribute of the claim object - its primary key:

<img src="{{claim.claim_receipt.url}}" id="place-holder-{{claim.id}}" style="zindex: 100; position: absolute; visibility: hidden;"/></td>

1 Like

Hi Ken,

Thank you for the suggestion! I actually tried that, but I couldn’t get the id right in the javascript portion.

I’ve tried this

<!-- javascript for receipt to appear on hover -->
   <script>
    function imageAppear() { 
    document.getElementById("place-holder-{{claim.id}}").style.visibility = "visible";}

    function imageDisappear() { 
    document.getElementById("place-holder-{{claim.id}}").style.visibility = "hidden";}
    </script>

And other various combinations of

getElementById('place-holder-{{claim.id}}')
and
getElementById(place-holder-{{claim.id}})

but it does not work. That is why jQuery was used.

That’s correct - the template is rendered on the server, but the JavaScript runs in the browser.

Your JavaScript needs to pull the target id from the element being hovered over - it needs to be more dynamic than trying to retrieve the element by a constant value.