6

I have a django application storing static images on digital ocean spaces. I can easily display these static images in my template by doing:<img>{% static 'images/my_image.png' %}</img>

If I inspect the HTML page after this loads, I will see something like:

https://nyc3.digitaloceanspaces.com/nameofmyspace/nameofmyspace-space-static_DEV/images/my_image.png?AWSAccessKeyId=XXXXXXXXXXXXXX&Signature=XXXXXXXXXXXXXXXXXX%3D&Expires=1621600823

But now I want to have this image change dynamically using javascript.

So I tried:

document.getElementById(id+"dynamicImage").src = "{% static 'images/my_image_2.png' %}";

Which almost works, but the image does not load. And the reason for this is after inspecting the src that the javascript supplied:

https://nyc3.digitaloceanspaces.com/nameofmyspace/nameofmyspace-space-static_DEV/images/my_image.png?AWSAccessKeyId=XXXXXXXXXXXXXX&amp;Signature=XXXXXXXXXXXXXXXXXX%3D&amp;Expires=1621600823

You can see wherever there was an & it appended amp; to it. What is the correct way to do this?

I can think of 2 ways to correct this, but they seem hacky.

  1. I could hard code the URL's into the javascript, which will be an updating nightmare as things change
  2. I could do <img id = 'my_image' hidden >{% static 'images/my_image.png' %}</img> for all the links I plan on using, then access this URL in the javascript using let URL = document.getElementById("my_image").innerHTML;. This will be less of an updating nightmare, but seems hacky and must be a better way.
MattG
  • 1,682
  • 5
  • 25
  • 45
  • Have you tried `decodeURI` by any chance? This SO question has a couple of options mentioned can you try them? https://stackoverflow.com/questions/23445703/django-ajax-request-url-is-not-working – Bhavani Ravi May 26 '21 at 13:28
  • Just tried, I was hoping it would work, but unfortunately, it does not. I tried to do `'{% static 'images/my_image_2.png' %}'` and `decodeURI('{% static 'images/my_image_2.png' %}'`) - both still do not remove the strange formatting – MattG May 26 '21 at 13:41

5 Answers5

2

if your Django is running on port 8000 use

http://localhost:8000/static/images/my_image_2.png

all your static files are served using baseurl/static/{your file path}

Pranav Tripathi
  • 117
  • 1
  • 3
  • 2
    You can the static path by changing the name in STATIC_URL = '/static/' in your settings.py file – Pranav Tripathi May 26 '21 at 16:06
  • 2
    Thanks for the comment, but as mentioned above I am using digital ocean spaces, and to access private image files I need to pass in the aws token from the settings.py file. I am unable to hard code the URLs, as they will expire, and this works around the settings.py static setup – MattG May 26 '21 at 17:28
2

I solved it by doing:

document.getElementById(id+"dynamicImage").src = ("{% static 'images/my_image_2.png' %}").replace(/&amp;/g, "&");

.replace(/&amp;/g, "&") will replace all &amp; with &. The/ and /g is regex to replace all.

MattG
  • 1,682
  • 5
  • 25
  • 45
1

I can't comment yet, But I did it this way with AWS, So here it is, If it is just what you want the users to see, You don't have to modify the actual Images stored in digital ocean, All you need to do is to generate a base64 image URL and send that "copy" image to the frontend and then use JS to do whatever it is u want the user to do, Even if you wish to modify the image, You can always save the Image to it's original name and set the "file_over_write" to True

  • Not sure I follow, sounds like you are hardcoding a base64 image url into the js? – MattG May 26 '21 at 17:30
  • not hardcoded, I know you are looking for an easy template solution, I don't know if there is one, However if there isn't, Imagebase64 is the way to go – Hello World May 27 '21 at 21:01
  • you can retrieve the image no? Then just convert it to base64 and then play with the copied image however u like, You can do it in either frontend with JS or in your views.py – Hello World May 27 '21 at 21:13
  • On a second thought, why not use a canvas, Your images are being displayed properly no? I mean as long as they are being displayed what's there to worry about, Then use a canvas to draw a copy of it, Play with the copy, Save it as the same name when you are done and set fileoverwrite to True if u wish to store it, Problem solved! Easy! – Hello World May 27 '21 at 21:26
1

my first thought after reading your question is plain javascript is very limited for web interactivity

you might find a better solution by importing a framework like vuejs.

generally speaking, Vuejs conditional rendering could offer a faster and cleaner javascript solution

to start using vuejs in HTML file you need to only insert this

<script src="https://unpkg.com/vue/dist/vue.js"></script> in the HTML file.

this is a quick sample of how you can isolate the URL data images from the code that displays the data, since the display code is isolated from the URL code, you can adjust the URL data to connect with Django settings.py

<meta charset="UTF-8">

<script src="https://unpkg.com/vue/dist/vue.js"></script>

<html>

<style>
*{
  background-color:#e8eae6;
 
}
</style>


<div id="app">
    <h2>vuejs testing </h2>
    <div class="row">
        <img width="400px" height="400px" v-for="img in images" v-bind:src="img"/>
      </div>


   
</div>
  
  <script>


new Vue({
  el: '#app',
 
data() {
    return {
        images:["https://images.unsplash.com/photo-1534258915617-99d572d9f684?ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&ixlib=rb-1.2.1&auto=format&fit=crop&w=889&q=80", 
        "https://images.unsplash.com/photo-1559825481-12a05cc00344?ixid=MnwxMjA3fDB8MHxzZWFyY2h8Mnx8d2F0ZXJ8ZW58MHx8MHx8&ixlib=rb-1.2.1&auto=format&fit=crop&w=500&q=60",
        "https://images.unsplash.com/photo-1621786505687-9a36ca978b27?ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&ixlib=rb-1.2.1&auto=format&fit=crop&w=334&q=80"
    ]
    }
}

});


  </script>


</html>

for more info about v-for directive syntax

the other solution, which I'm not sure how practical or if it would be counterproductive for your use case,

but if I had this problem I will just move the images to different storage like google storage system; they have fine-grained control for every single collection.

so it depends on how you want to organize these images

tony19
  • 125,647
  • 18
  • 229
  • 307
Sami
  • 21
  • 1
  • 1
  • 5
1

To do this, you could set the static URL as a global variable and reference it later on. Basically:


// Initial setting of the global static URL
var staticURL = "{% static '' %}";

// Function to retrieve the full URL given the 
function getStatic (URL) {
    let fullURL = staticURL + '/' + URL;
    return fullURL;
};


// Example to get the URL of an image
document.getElementByID('image').src = getStatic('images/my_image');

In the example above, I used the function getStatic to retrieve a static file at any point using javascript. To change an image, you just retrieve another URL and set that as the source file for the image.

Abc Bcd
  • 76
  • 1
  • 6