Find if static file exists before calling in deployment - Django - django

In production I am able to run:
#views.py
from django.contrib.staticfiles import finders
result = finders.find(f'Images/{var}')
context = {"r", results}
#template.html
{% if r %}
{% with 'Images/'|add:var as var %}
<img src="{% static var %}">
{% endwith %}
{% endif %}
However, now that my files are being stored in Google's buckets finders.find(f'Images/{var}') keeps returning False and my images aren't being displayed. I need a way to test if files exists prior to calling them to avoid displaying empty boxes when a variable's image does not exist.
Incase there's a way to search through the remote buckets, here is my settings.py configuration:
#settings.py
. . .
STATIC_URL = http://storage.googleapis.com/env("BUCKET")/static/
STATIC_ROOT = http://storage.googleapis.com/env("BUCKET")/static/

you could use request lib:
import request
r = requests.head(file_url)
if r.status_code == 200:
do something...
but that's gonna cost you a lot (I mean response time, not money)
better solution would be using JS, something like this (this is jquery):
<script>
$("img").on("error", function () {
//$(this).attr("src", "broken.gif"); // set default pic
$(this).hide(); // hide img
});
</script>
That way you can hide or change all images in the page, when it doesn't load

After looking through a bunch of websites (mostly SO,) I found this solution really helpful:
{% with 'Images/'|add:var as var %}
<img src="{% static var %}" class="img" onerror="this.onerror=null;this.style.display='none';src='';this.class='';" />
{% endwith %}

Related

django common templates for apps with variables

I want to make project-wide templates, but with app variables and app base subtemplates:
/home/project/
templates/document.html
app1/templates/app1/base.html
app2/templates/app2/base.html
And app1/views.py:
def page1(request):
document = get_document('title',app_email='test#example.com')
context = {
'document' : document,
'app_title_header' : document.header
}
return render(request,'document.html', context)
templates/document.html
{% extends app_name|add:'/base.html' %}
{% load static %}
{% block content %}
{% autoescape off %}
{{ document.body }}
{% endautoescape %}
{% endblock %}
(app_name is set by context_processors.py registered in settings.py)
def appname(request):
return {'app_name': request.host.name, 'app_base' : '{}/base.html'.format(request.host.name) }
app1/templates/app1/base.html (almost identical like app2)
{% load static app1 %} <--- difference with app2
<!doctype html>
<html lang="pl">
<head>
<meta charset="utf-8">
{% block head %}
{% endblock %}
<title>{% app_title %} - {{ app_title_header }}</title>
{% include "app1/google.html" %}
</head>
app1/templates/app1/google.html
{% load app1 %}
<!-- Global site tag (gtag.js) - Google Analytics -->
<script async src="https://www.googletagmanager.com/gtag/js?id={% g_tag %}"></script>
<script>
window.dataLayer = window.dataLayer || [];
function gtag(){dataLayer.push(arguments);}
gtag('js', new Date());
gtag('config', '{% g_tag %}');
</script>
and now:
render takes document.html from project/templates. First it extends app_name/base.html - so it is including google.html (Google Analytics ).
And it works. But now I want to move google.html and fb.html to project templates, but theres unique G_TAG, so it has to be a tag or sth for this. I can't just move it because of {% load app1 %} in google.html.
I think it is too complicated - and I think there's easy solution - but don't have idea which way to go.
The most important limitation - I don't want to use context_processors from apps. I use context_processor only for common things, because i use the same variables in app1 and app2 and context_processor overrides it.
(Note: you may be suffering from DRY fascination ~:))
You need to hardcode the value somewhere, whether it's property in a ViewMixin, retrieve it from a shared storage or a template file - thing is, you have come to the point where you the shared functionality is as insignificant as the variable that differentiates each call: you need to output the value of a variable with some surrounding elements. That variable needs to come from somewhere, so repetition of variable = value is going to happen in one form or another.
My 2 cents...If I didn't understand the question well enough, let me know.
So if this is in your template:
<script async src="https://www.googletagmanager.com/gtag/js?id={{ g_tag }}"></script>
And this is a view mixin:
from django.views import generic
from centralapp.models import ConfigModel
class GoogleTagMixin(generic.base.ContextMixin):
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
app_config = ConfigModel.objects.get(host=self.request.get_host())
context['g_tag'] = app_config.google_tag
return context
Then you have one template and can just use the mixin in whatever view you need it to be.
If you don't want a mixin, you can do the same with Middleware and set the value on the request object.
I'm not sure what you're looking for that is "better".

problem with images on a custom 404 page, django

I am trying to make custom 404 page by adding an image to the page. Problem is that image is not displaying on a page. This image is accessible from any other page in each app in DEBUG TRUE or FALSE mode, no difference, except 404 page where it represented as a just an empty frame.
Image is placed in app/static/app root. Tried to place it is main static root -no difference.
# urls.py
handler403 = curry(permission_denied, exception=Exception('Permission Denied'),
template_name='errors/403.html')
handler404 = curry(page_not_found, exception=Exception('Page not Found'),
template_name='errors/404.html')
handler 403 and handler 404 works fine, except images failure.
# template
<!-- templates/errors/404.html -->
{% extends "base.html" %}
{% block title %} error 404 {% endblock %}
{% load static %}
{% block content %}
<img src="{% static "appname/404.png" %}" alt="404">
{% endblock content %}
Problem is only on 404/403 pages. Everywhere else -no problems at all. Text itself displays normally.
Question is what should I check in terms of possible pitfalls I possible keeping out of scope ?
thanks in advance
p.s. tried
<img src="{% get_static_prefix %}404.png" >
still no effect
Solution is to run server in the following mode:
manage.py runserver --insecure

How do you dynamically display images in Django

I'm trying to dynamically display Images in Django. this is my details page
{% extends 'base.html' %}
{% load staticfiles %}
{% block header %}
<!-- Set your background image for this header on the line below. -->
<header class="intro-header" style="background-image: url('{% static 'blog/img/about-bg.jpg' %}')">
<div class="container">
<div class="row">
<div class="col-lg-8 col-lg-offset-2 col-md-10 col-md-offset-1">
<div class="page-heading">
<h1>{{ post.title }}</h1>
<hr class="small">
<span class="subheading">blog detail</span>
</div>
</div>
</div>
</div>
</header>
{% endblock %}
{% block content %}
<h1>{{ post.title }}</h1>
<h4>{{ post.body }}</h4>
{% lorem 5 p random %}
<hr>
<div id="disqus_thread"></div>
<script>
/**
* RECOMMENDED CONFIGURATION VARIABLES: EDIT AND UNCOMMENT THE SECTION BELOW TO INSERT DYNAMIC VALUES FROM YOUR PLATFORM OR CMS.
* LEARN WHY DEFINING THESE VARIABLES IS IMPORTANT: https://disqus.com/admin/universalcode/#configuration-variables
*/
/*
var disqus_config = function () {
this.page.url = PAGE_URL; // Replace PAGE_URL with your page's canonical URL variable
this.page.identifier = PAGE_IDENTIFIER; // Replace PAGE_IDENTIFIER with your page's unique identifier variable
};
*/
(function() { // DON'T EDIT BELOW THIS LINE
var d = document, s = d.createElement('script');
s.src = '//eights.disqus.com/embed.js';
s.setAttribute('data-timestamp', +new Date());
(d.head || d.body).appendChild(s);
})();
</script>
<noscript>Please enable JavaScript to view the
comments powered by Disqus.
</noscript>
<script id="dsq-count-scr" src="//eights.disqus.com/count.js" async></script>
{% endblock %}
So far I tried storing these approaches. I tried storing this in the database
{% static 'blog/img/about-bg.jpg' %}
and called it like this
style="background-image: url('{{ post.title }}')"
that didn't work. Then I tried storing it in the database like this
'blog/img/about-bg.jpg'
and calling it like this
style="background-image: url('{% static '{{ post.title }}' %}')
then I ried storing it like this in the database
static/blog/img/about-bg.jpg
and calling it like this
style="background-image: url('{{ post.title }}')"
I've also tried defining it in the views.py
pic = "path/pic.img"
context = {
"pic": pic
context and calling it
{{pic }}
none of these methods work. It's a little different from Laravel. In laravel
path/{{ post->title }}
would have worked. How can I do this in Django? any and all suggestions are welcome. To be clear I want all my articles to display an image on the index page, then when I click one of them, I am taken to the details page that image for that particular article is displayed
I've figured it out. It's supposed to be stored as
/static/blog/img/about-bg.jpg
not
static/blog/img/about-bg.jpg
the forward slash makes it work. in Laravel this does not matter
From you question I understand that by dynamically you mean that you want to upload an image to your site. So it's not just a static image that is always the same like a logo of your page or something.
You have to do this:
In models.py
from django.contrib.sites.models import Site
def generate_filename(filename): #it adds the image in a folder with the current year
ext = filename.split('.')[-1]
year = datetime.datetime.now().year
return str(year) + '/' + str(int(time())) + '.' + ext
class PageWithImage(models.Model):
image = models.ImageField(upload_to=generate_filename, blank=True, null=True)
site = models.ForeignKey(Site, blank=True, null=True)#this if you want the image linked with your site
Then in setting.py you have to add:
import os
BASE_DIR = os.path.dirname(os.path.dirname(__file__))
MEDIA_ROOT = os.path.join(BASE_DIR, 'img')
MEDIA_URL = '/img/'
Then in the template:
<img itemprop="image" src="http://{{ object.site }}{{ object.image.url }}">
And don't forget to add the image field to admin.py
For adding images dynamically to your webpage using Django :
As we mostly use Jinja for templates,
<img src="{%static 'images/beach.svg' %}" alt="A beach image">
We give this kind of commands to access static image files. But for dynamic, we have to change the 'beach.svg' to something like {{dest2.img}} in the above HTML image tag, if my "views.py" function is like :
def index(request):
dest2 = Destination() // Imported class 'Destination()' from models.py .
dest2.name = 'Beach'
dest2.img = 'beach.svg' // The image name we need.
dest2.desc = 'Some beach description'
dest2.price = 2000
return render(request, 'index.html', {'dest2' : dest2}) // Passing the object value to html page.
If we logically think, the code should be like :
<img src="{%static 'images/{{dest2.img}}' %}" alt="A beach image"> // we cannot do this here!!!
We cannot use a Jinja code inside another Jinja code. So we add :
{% static 'images' as base_url %}
at the top of our HTML page. 'images' is the default folder for images and we are calling it as 'base_url' in this HTML page. So we have to use 'base_url' as path and 'dest2.img' as the file name. so the image source will be like :
<img src="{{base_url}}/{{dest2.img}}" alt="A beach image">
So finally we're done making the dynamic images in Django.!!!😋
First, you cannot use {% static 'blablabla' %} in CSS files.
Second, use this code:
style="background: url(/static/blog/img/about-bg.jpg) no-repeat"
Third, if you will be working with images from models in the future then your code should be:
style="background: url(/{{ your_object.your_img_field }}) no-repeat"

Resolve Static URL on Server

All of my user's have the option to link a profile picture. There are several templates that need to load this profile picture. If the user has not uploaded a picture, we use a default. When I want to display this profile picture, my code looks like this
<img src="{% if user.profile_picture.search_thumbnail.url %}{{ user.profile_picture.search_thumbnail.url }}{% else %}{% static "alternate.jpg" %}{% endif %}">
This is way too verbose for me, especially considering I need to repeat it out in multiple templates. I could use {% with %} blocks to store user.profile_picture.search_thumbnail.url, but that won't help me too much.
My solution was to write a function attached to the user model that returns the url of the static file. Unfortunately, the {% static %} is a template function. {% url %} has an equivalent function on the server called django.core.urlresolvers.reverse(). Does the alternative thing exist for the {% static %} tag?
In case anyone asks, I want to use the static function because my static files are stored in different places depending on the environment. My dev machine serves files locally, while my PRD machine serves static files from s3.
Thank you,
Nick
why not write a filter so you can do this.
<img src="{{ user.profile_picture.search_thumbnail.url|custom_filter }}">
and in the custom_filter you read from the settings.STATIC_URL to return the correct URL the user one is not set.
you could make the filter even shorter like this
<img src="{{ user|user_pic_url }}">
and in the filter pull out the .profile_picture.search_thumbnail.url /checks
This is what the static templatetag does underneath, and you can use it just fine in your own code:
from django.contrib.staticfiles.storage import staticfiles_storage
def static(path):
return staticfiles_storage.url(path)

Include css, js, html from apps in Django project, in a modular way

I have django project with several apps. In my main html template I am including the relevant resources -- js, css in this case and those entries are coded in by hand like so:
<script src="{% static 'js/test.js' %}"></script>
I'd like to modularize this so that I can somehow loop over my projects and have their dependencies included only if they are installed/enabled. In this way I can also add more apps in the future and not have to touch my main template.
Is there an elegant way to accomplish this?
My thought is that if I can pass each application's required resources to the main template as parameters via views.py then maybe I can loop over them (utilizing sekizai...):
{# Include external app resources #}
{% for app, template in installed_apps.items %}
{% include template %}
{% endfor %}
And views.py would go something like:
external_apps = [foo, bar]
external_apps = settings.EXTERNAL_APPS # Ok, this should exist in settings already
def main(request):
installed_apps = {}
for app in external_apps:
installed_apps[app] = app + "_template.html"
template = loader.get_template('main_template.html')
context = RequestContext(request, {
'installed_apps': installed_apps,
})
return HttpResponse(template.render(context))
Then for each app I would create a template that would fill out the necessary blocks in the main template file.
This approach seems pretty rigid though and I'm wondering if there is a more common or standardized way to go about this.
base.html:
...
<script src="{% static 'js/test.js' %}"></script>
{% block extra_js %}{% endblock extrajs %}
...
In your app template:
{% block extra_js %}<script src="{% static 'js/myapp.js' %}"></script>{% endblock extra_js %}