Refer to the docs, where there is a nice explanation of it.
Actually the {% static %} template tag know the location of STATICFILE_STORAGE
As docs say :
{% load static from staticfiles %} <img src="{% static "images/hi.jpg"
%}" alt="Hi!" /> The previous example is equal to calling the url method of an instance of STATICFILES_STORAGE with "images/hi.jpg".
This is especially useful when using a non-local storage backend to
deploy files as documented in Serving static files from a cloud
service or CDN.
If you’d like to retrieve a static URL without displaying it, you can
use a slightly different call:
{% load static from staticfiles %}
{% static "images/hi.jpg" as myphoto %}
<img src="\{\{ myphoto }}" alt="Hi!" />
The staticfiles contrib app's static template tag "uses the configured STATICFILES_STORAGE storage to create the full URL for the given relative path", which is "especially useful when using a non-local storage backend to deploy files".
The built-in static template tag's documentation (linked to above) has a note that says to use the staticfiles contrib app's static template tag "if you have an advanced use case such as using a cloud service to serve static files", and it gives this example of doing so:
I don't know what the difference is supposed to be, but I found a use case difference (using django 1.9.1 running via apache, wsgi on Python 3.4). In my app, I have some images in ImageFields in the database. If I use code like this in my template:
then, if I use {% load static %}, django throws a TypeError (Cannot mix str and non-str arguments). This is presumably because the object.image is not a string, it's an ImageField, that gets converted to a string at some later stage. However, if one uses {% load staticfiles %} no such error occurs.
Unfortunately, I discovered this difference after spending hours trying to debug the problem. I managed to find a workaround for when using the first option, namely to add a string-converter method to the object like this: