Flask Url_for with dynamic file name - flask

I'm running into issues with Flask caching my bundle.js file despite setting app.config['SEND_FILE_MAX_AGE_DEFAULT'] = 0 when I'm running webpack in watch mode, so I've decided to add a build version to my bundle.js in an effort to break the browser cache.
Presently, I have:
<script src="{{url_for('static', filename='bundle.js')}}"></script>
in my html file and I'll need to add a variable to it. The problem is I don't know what the version will be, so is there a way to grab the file name in flask, and send it in with my render_template? I imagine something like: <script src="{{url_for('static', filename='bundle{}.js'.format(version))}}"></script>
and then grabbing the version from app.py by looking in the static folder for a file that begins with bundle, has an integer, and ends with .js

In your app.py file:
app.jinja_env.globals['js_bundle_file'] = 'bundle-1.1.js'
In your template:
<script src="{{url_for('static', filename=js_bundle_file)}}"></script>
Instead of hardcoding your bundle file, you could also look for it using a slightly hacky list comprehension:
app.jinja_env.globals['js_bundle_file'] = [f for f in os.listdir('static') if f.endswith('.js') and f.startswith('bundle')][0]
or this cleaner looking glob:
import glob
app.jinja_env.globals['js_bundle_file'] = glob.glob('static/bundle*.js')[0]

Related

How to use images loaded with webpack in django templates?

I am using Webpack 2 and use url-loader to load all of my images. before using webpack, I used the static template tag like this:
<img src="{% static "img.png" %}" ... />
and now webpack renames all of the images to some hash and ext like this:
img.png becomes img-[somehash].png. (I use this for cache invalidation).
the problem is how to load the new image (with the hash) in django templates ?!
thanks in advance.
How about passing correct path in context data? In Django view you are passing context data to the template. You can use regular expressions to find the name of file with hash. Let say that your images are in the directory which variable called STATIC_ROOT links to (place where all static files are). First, you need to find files:
from yourproject.SETTINGS import STATIC_ROOT
all_files = os.listdir(STATIC_ROOT)
Let say that name of the file you want is picture.png, and it was changed to picture-asd12edaq.png Then, find correct file name using regex or simple in operator:
for file in all_files:
if 'picture' in file and '.png' in file:
context['src'] = file
break
Then in template use simple <img src="{% static {{src}} %}" ... />

django I18n javascript_catalog with react weird comportment

I'm using Django 1.9, React and webpack, I used externals to load the django I18n functions such as gettext in my javascript files.
This is loaded like this from a view :
<script type="text/javascript" src="{% url 'django.views.i18n.javascript_catalog' %}/0"></script>
Here is my webpack config :
externals: {
// require("jquery") is external and available
// on the global var jQuery
"jquery": "jQuery",
"utils": "utils",
"gettext":"gettext",
"django":"django",//I18n functions are encapsulated in the django object
},
In my jsx files I load gettext like this :
import {gettext, interpolate, ngettext} from 'django'
render(){
var login_header_text = gettext("blablabla.");
....
Actually almost everything works, when I use django-admin makemessages -d djangojs -l it recovers many gettext, however some gettext are ignored by the script so sometime I have to put the gettext at the beginning of my render function and then it works..., I don't know why this is happening.
In the end with my technic I can make it work totally but maybe I did something wrong. Maybe I should generate mo file with grunt and load it dynamically with po loader with webpack because I will need soon to load them dyamically into the page.
Maybe you can guide me a bit ? Thanks

Is it possible to hardcode CSS link in django?

I have an django project and want to hardcode a link to CSS (I do not want to use STATIC_FILES...etc). The reason is because I want to be able to click index.html and it will work on browser (including getting the css file).
I put both index.html and index.css in the same directory and added this line in index.html:
<link rel="stylesheet" type="text/css" href="./index.css"/>
When I double-click index.html, it imports index.css perfectly.
However, when I load it with the django development server and open via browser, it does not import the index.css.
What should be done so that index.html takes the index.css?
The answer by Christopher Schäpers works nicely, I'd like to extend her answer by showing how you may actually do what she suggests.
Let's say you have
<link rel="stylesheet" type="text/css" href="/index.css"/>
which means the browser is requesting to localhost:8000/index.css, so in your root urls.py file, you add something like this
from django.urls import path
from django.conf import settings
from django.http import HttpResponse
def css_path(request): # This is basically a "view"
path = settings.BASE_DIR / 'index.css' # For earlier Django version: os.path.join(settings.BASE_DIR, 'index.css')
with open(path, 'rb') as f:
content = f.read()
return HttpResponse(content, content_type='text/css')
urlpatterns = [
# ... (your other url patterns)
path('index.css', css_path)
]
NOTE: Remember to set the content_type keyword argument correctly base on what you are serving (Example: application/javascript for .js, image/png for .png, .etc).
That's because the browser uses a directory based approach.
Say your template directory looks like this:
/home/yura/project/templates/
→ index.html
→ index.css
When opening index.html with your browser it plainly looks for index.css in the same directory, thus for /home/yura/project/templates/index.css.
Now when you run the development server it's not directory based anymore. There's the urls.py file that specifies where each path leads to.
You probably have a route / that leads to index.html even though index.html isn't called nothing. You could also add a route /blog/ that may lead to blog_home.html even though the file is called blog_home.html.
Every url that enters django is routed through the urls.py file.
This is one of django's core concepts. URLs should be user-typable and readable without cruft as .php, .html and so on that comes from directory based approaches like PHP or CGI.
Since you haven't defined a route called /index.css thus index.css isn't found.
If the thing you are doing is a one-off your best bet would be to just add a route to /index.css that delivers index.css.
Otherwise there is no way of doing this, since django isn't directory based, as pointed out above.
You might then want to think about why exactly you want to be able to open the raw html file directly in the browser too, since it makes the django templating language entirely useless for you, thus you can't do anything variable, loop and logic related and are stuck with basic html where you, instead of the django-dev server could just as well use a simple http-server instead.

Dygraph is not defined, using Flask

I am using flask and trying to get the dygraph sample to work. Here is the sample code (2nd example from the tutorial page: http://dygraphs.com/tutorial.html):
<html>
<head>
<script type="text/javascript"
src="dygraph-combined.js"></script>
</head>
<body>
<div id="graphdiv2"
style="width:500px; height:300px;"></div>
<script type="text/javascript">
g2 = new Dygraph(
document.getElementById("graphdiv2"),
"temperatures.csv", // path to CSV file
{} // options
);
</script>
</body>
</html>
Here is my Flask code (I'm trying to use render_template()):
from flask import Flask, render_template
app = Flask(__name__)
#app.route('/')
def render_plot():
return render_template('sample.html')
if __name__ == '__main__':
app.run()
When I run this through python firebug gives me the error "Dygraph is not defined." from the line g2 = new Dygraph(
Sample.html works in my folder, but it does not work when I try to access it from my url after running my flask code from python. My folders look like this:
FlaskStuff/main.py
FlaskStuff/templates/sample.html
FlaskStuff/templates/dygraph-combined.js (To load sample.html in my folder).
FlaskStuff/js/dygraph-combined.js
I am new to Flask. Similar answers did not help me to solve this problem.
Where is dygraph-combined.js located? It needs to be somewhere it can be served. You will most likely what to place it inside your static folder. It's a fairly common practice to group like files inside static (e.g., css, js).
Using this structure
static/
js/
dygraph-combined.js
you'll want to update sample.html as follows
<script type="text/javascript" src="{{ url_for('static', filename='js/dygraph-combined.js') }}"></script>
This will allow the Flask development server to serve the file. You'll also want to add a rule to your HTTP server to serve content from /static directly.
You will also have to do a similar thing for the temperature.csv file. (I've placed it in the static folder)
"{{ url_for('static', filename='temperatures.csv') }}", // path to CSV file

Using Django urls in javascript files

I am trying to use url-names in my javascript/jquery files for AJAX requests and I have found several solutions that can solve this problem. The one that I am currently using is the following.
I define a url to serve javascript files:
urls.py
url(r'^js/([\w\.\-]+)/([\w\.\-]+)/$', 'views.get_javascript_file', name='get_javascript_file')
url(r'^getmoredicus/$', 'load_discussions', name="load-discus"),
Then I define the view that renders the javascript files.
views.py:
def get_javascript_file(request, app_name, js_file):
'''
Used to request and serve rendered javascript/jquery files.
'''
return render_to_response("%s/%s.js" % (app_name, js_file),
context_instance=RequestContext(request))
Now in the html files, we can use the get_javascript_file url to get the rendered javascript files.
html files:
<script type="text/javascript" src="{% url get_javascript_file 'myapp' 'jsfile' %}"></script>
Now in any javascript file, I can access the url-names through {% url url-name %}.
Questions:
1) Is there a better/faster way to use url-names in javascript files? I know that there are some apps already created to accomplish this but I want to get everyone's(django experts) opinion on the best way to accomplish this.
2) Can we cache the rendered javascript files after they have been rendered the first time so that in each subsequent request, we don't have to render them again? If yes, then how can we go about doing that.
3) In this method, we are rendering the script files from their apps folders. Is there a way to access the static files located in STATIC_ROOT from the get_javascript_file view? I am just thinking about how this would work in a production environment. Is it a good practice to access static files from their apps folders rather than putting them in STATIC_URL and accessing them from there?
NOTE
I know that there are already some questions on SO that answer some parts of this question, but I just wanted to get to the bottom of this once and for all for future django learners. What is the best way to use url-names in javascript or any script for that matter?
I'm not a fan of running external js through the view rendering. Especially if you're using something like django-compressor to compress and cache your js files.
I prefer to just include the variables in a script tag prior to including the external files.
<script>
my_var = "{{ MY_PROPERTY }}"
</script>
<script type="text/javascript" src="{{ STATIC_URL }}js/external_script.js"></script>
That solution is also not always ideal, but I'm open to other solutions.