I am a beginner to Python and Tornado web framework. When I was studying the template part in the book "Introduction to Tornado", one line confused me:
<link rel="stylesheet" href="{{ static_url("style.css") }}">
How can the application know where to call the function static_url when there is no library imported to the namespace? I found static_url() in Tornado's web module, but I can not figure out how can this function be successfully called in that template file?
The RequestHandler class has a method get_template_namespace(), documented here. If you click the source link then you'll see how it creates a dictionary where 'static_url' is set to self.static_url.
Related
Previously, I know how to run Vue and Django (jinja2 template) together.
by handling the custom delimiters, e.g delimiters: ['[[', ']]'].
But for some reason, my supervisor just need to run the compiled vue project inside my existing django project. As we can see, the vue has npm run serve or yarn run serve to run it.
Does django can handle this case? If yes, what I should do?
In this case, we doesn't use direct web server like nginx, apache, etc to run.
Charanjit Singh answer is correct and your 404 problem is not related to vueJs. Since you are not using a direct web server you are making it harder.
Also If your vue application implements vue-router in history mode that'll cause even more problems since you're not using neither nginx or apache.
My only approach for this is Haproxy that'll make your sub application handle those routes.
For example your app domain is myawesomedomain.com and your vue app is in myawesomedomain.com/myvueapp then you need to configure your Haproxy to let your vueapp handle all routes in myawesomedomain.com/myvueapp/*.
If you don't have a vue-router in your app then you need to place th vueapp folder in your deployed web folder and don't forget to add a routing rule for your html file (I don't know about Django but I did it with symfony and it is working)
Deployed
|
|_vueapp ===> your compiled folder
|
|_htmlFile ===> your html file
Finally, this is what I've been working on. I put the compiled index.html file from dist/index.html to templates/vueapp/index.html (django templates folder). The other files & folders is put inside static/ folder.
templates/vueapp/index.html => the compiled html file.
static/vueapp/ (includes: css, js, fonts, etc). => the compiled vue static files.
my views.py;
from django.views.generic import TemplateView
class VueAppView(TemplateView):
template_name = 'vueapp/index.html'
and my urls.py;
from django.contrib import admin
from django.urls import (path, include)
from my_app.views import (HomeTemplateView, VueAppView)
urlpatterns = [
path('admin/', admin.site.urls),
path('', HomeTemplateView.as_view()),
path('vueapp/', VueAppView.as_view()),
]
also inside the vueapp/index.html. As we can see, I modified the source of /static/vueapp/ and linked to the static folder.
<!DOCTYPE html>
<html lang=id>
<head>
<meta charset=utf-8>
<meta http-equiv=X-UA-Compatible content="IE=edge">
<meta name=viewport content="width=device-width,initial-scale=1">
<link rel=icon href=/static/vueapp/favicon.ico>
<title>siap-ums</title>
<link rel=stylesheet href="https://fonts.googleapis.com/css?family=Roboto:100,300,400,500,700,900">
<link rel=stylesheet href="https://fonts.googleapis.com/css?family=Material+Icons">
<link href=/static/vueapp/css/chunk-01c619b4.ff54e24d.css rel=prefetch>
<link href=/static/vueapp/css/chunk-308637dc.e4c5f763.css rel=prefetch>
<link href=/static/vueapp/css/chunk-616b136f.404f3685.css rel=prefetch>
<link href=/static/vueapp/js/app.876efdb8.js rel=preload as=script>
<link href=/static/vueapp/js/chunk-vendors.2b11f5ad.js rel=preload as=script>
<link href=/static/vueapp/css/chunk-vendors.a6a7bf01.css rel=stylesheet>
</head>
<body>
<noscript><strong>We're sorry but siap-ums doesn't work properly without JavaScript enabled. Please enable it to continue.</strong></noscript>
<div id=app></div>
<script src=/static/vueapp/js/chunk-vendors.2b11f5ad.js></script><script src=/static/vueapp/js/app.876efdb8.js></script>
</body>
</html>
Every times the vueapp have changes, I must compile it first and do the same step as above.
I have run into a problem with static files after a redirect in Flask.
The web app I am writing will redirect users after logging in for the first time to a site where they need to change the default password they've been provided. On this site my custom stylesheets are entirely broken and images won't display either.
A quick inspection in the Chrome dev tools showed that after the redirect the content type for the all files from the static folder is set to text/html. I suspect that this is the issue.
In my template html the stylesheet is linked in the following way:
<link rel="stylesheet" href="{{ url_for('static', filename='css/colorVariables.css') }}">
The stylesheets and images work fine on every other page of the app and also if you go to the exact same page without the redirect.
The redirecting part looks like this:
if user.first_login:
return redirect(url_for("change_password"))
I have found the issue. The redirect was happening in a function run with app.before_request. Wrapping the routes with the function manually solved the problem.
I have this master html template:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Start Bootstrap - SB Admin Version 2.0 Demo</title>
<!-- Core CSS - Include with every page -->
<link href="css/bootstrap.min.css" rel="stylesheet">
<link href="font-awesome/css/font-awesome.css" rel="stylesheet">
<!-- SB Admin CSS - Include with every page -->
<link href="css/sb-admin.css" rel="stylesheet">
<!-- Core Scripts - Include with every page -->
<script src="js/jquery-1.10.2.js"></script>
<script src="js/bootstrap.min.js"></script>
<script src="js/plugins/metisMenu/jquery.metisMenu.js"></script>
<!-- SB Admin Scripts - Include with every page -->
<script src="js/sb-admin.js"></script>
</head>
this is the test.py file:
from wheezy.template.engine import Engine
from wheezy.template.ext.core import CoreExtension
from wheezy.template.loader import FileLoader
T = ['where/project/folderbase/is']
engine = Engine(
loader=FileLoader(T),
extensions=[CoreExtension()]
)
master_template = engine.get_template(r'master.htm')
#route('/test')
def login_name():
return master_template.render({})
I'm a complete n00b at templating and web design.
lets say i run this via any of python web server like flask on localhost:port/test
Nothing shows up.
Why?
And what is this #path_for in wheezy.template?
Do I need to include #require(path_for) or anything else?
is that necessary to server static files in the html file to define all the files in a specific folder-> 'static'
or can they be accessed from where they are now, as in the code above?
You had lots of questions. I'll answer even though you may not care anymore...
If you have correctly configured Flask, and served that template on the route/url 'test', then nothing would appear as you have not defined a <body> with any content in the html.
In wheezy.templates, you access local variables/functions with the #my_variable syntax (ie you prefix it with an # symbol). If you want to access a variable that was passed to the template as part of the context, you need to require it first, #require(my_variable). Your example uses an empty dict as the context, so there would be no variables to access/require.
path_for is part of wheezy.routing, not wheezy.templates. It is used for getting the url of a named route (ie you could do #path_for('test'), and it would return localhost:1234/test. Using path_for would only make sense if you are using the complete wheezy.web framework (which uses wheezy.routing and wheezy.templates). Flask would have its own functions for doing this (I'm not sure what they are though, I don't use Flask). You would need to pass these functions into the template via the context, then #require them to use them though (or make some custom extension for wheezy.template).
My Platform : Django 1.5.4 , running with a wsgi module in apache
Issue: I am trying to deploy a django site using a secure connection for one route, and for this route, css fails to work (it seems to load though, meaning, the resource is fetched correctly and I can see the code when I go to its path)
I have an alias in my Virtual Host Section on the http.conf file that allows the wsgi to load static files that looks something like this:
Alias /static/ /home/username/public_html/mysite/static_dir/
And, I have a rewrite rule that looks like this so that I can make one of my routes secure:
RewriteRule ^/product/(.*)/buy/$ https://%{SERVER_NAME}/product/$1/buy/ [L,R]
This works in terms of getting to the secure product page where customers will input credit card info, yet the css will not load correctly. The images will load normally, and they share the thew same path as the style.css that loads.
What's weird is that when I navigate to the css path that is loaded in the head of the page, I see my CSS code!
Here are my static files settings in settings.py
STATIC_ROOT = '/home/username/public_html/mysite.com/static/'
STATIC_URL = 'http://34.56.78.93/~username/mysite.com/static/'
STATICFILES_DIRS = (
'/home/username/public_html/path/to/project/static/',
and I'm loading the css like this in a base template <link rel="stylesheet" type="text/css" href="{% static 'style.css' %}" />
If you've ever experienced this or have any clue whats going on, please respond. Thanks
I am trying to reroute all of my /static content to host on Amazon S3. My first thought was to use global config['path'] throughout my jinja templates, but this won't work for external css and js files, plus it is kind of messy. I found the static_folder and static_url_path released in 0.7 and this seems like what I want. However, when I go to http://localhost:8000/static/img/abc.jpg it does not locate the files on S3. Am I using this feature right or is there some other way to do this?
Thanks!
I recently developed a Flask extension to deal with just this situation. It's called Flask-S3, and you can read the documentation for it here.
As an example, here is how you would integrate it into your Flask application:
from flask import Flask
from flask_s3 import FlaskS3
app = Flask(__name__)
app.config['S3_BUCKET_NAME'] = 'mybucketname'
s3 = FlaskS3(app)
You can use the extension to upload your assets to your chosen bucket:
>>> from my_application import app
>>> from flask_s3 import create_all
>>> create_all(app)
Flask-S3 is blueprint aware, and will upload all assets associated with any registered blueprints.
I wish the flask.Flask constructor's static_url_path argument would accept a full URI, but it screams about the path needing a leading slash when you try that. If it accepted it, you could just use url_for after setting static_url_path='http://my_s3_bucket.aws.amazon.com/' or so.
Another possible solution is to use a context processor. I believe this is the cleanest solution, but I don't have much experience with flask. It sure looks clean. Using a context processor, I pull the URL from the environment (I'm using heroku so it's wicked easy to set). Then the context processor makes the static_url variable available in my templates.
In app.py:
# Environment has STATIC_URL='http://my_s3_bucket.aws.amazon.com/'
#app.context_processor
def inject_static_url():
"""
Inject the variable 'static_url' into the templates. Grab it from
the environment variable STATIC_URL, or use the default.
Template variable will always have a trailing slash.
"""
static_url = os.environ.get('STATIC_URL', app.static_url_path)
if not static_url.endswith('/'):
static_url += '/'
return dict(
static_url=static_url
)
In the template:
<link rel="stylesheet" type="text/css" href="{{ static_url }}css/main.css" />
The result
<link rel="stylesheet" type="text/css" href="http://my_s3_bucket.aws.amazon.com/css/main.css" />
I know this is an old question but here's how I get around this issue.
Import Flask's url_for method under a different name (e.g., flask_url_for)
Create your own custom url_for method, which calls flask_url_for and then uses string replacement to add in your S3 bucket url.
I like this strategy because it's simple and intuitive to use, and the interface is exactly like the original url_for method.
from flask import url_for as flask_url_for
from flask import current_app
PRODUCTION_URL = 'https://s3.amazonaws.com/MY-BUCKET-NAME'
def url_for(path, **kwargs):
url = flask_url_for(path, **kwargs)
if url.startswith("/static") and not current_app.debug:
url = url.replace("/static", "", 1)
return PRODUCTION_URL + url
return url
what you are trying to accomplish is to be able to write
{{ url_for(app.static, file='img/abc.jpg', _external=True) }}
and have that resolve to a url in s3?
i believe that static_folder and static_url_path are setup so that if you call
app = Application('app', static_folder='foo', static_url_path='bar')
then going to
the above url_for would output
http://localhost:8000/bar/img/abc.jpg and it would look for static/img/abc.jpg in the filesystem.
i think what you want to do is potentially write a custom filter that would translate your path to an s3 url so that you could make a call something like
{{ 'img/abc.jpg'|s3_static_url }}
there's some documentation on that here: flask custom filters
What you need is the Amazon S3 public file URL instead of http://localhost:8000/static/img/abc.jpg. If its just a few files, maybe hardcode them in your template with the full URL or if you are going to have a local version for testing and use S3 on production site (like we do) then you can try the following method.
Define a new variable probably called STATIC_ROOT in the top of your base template (which other templates inherit), and use that as the file path prefix.
For example:
{% if app.debug %}
{% set STATIC_ROOT = url_for('static', filename='') %}
{% else %}
{% set STATIC_ROOT = 'http://s3.amazonaws.com/bucketname/' }
{% endif %}
This will give you the default path when you might be testing your application locally, and the public S3 url when in production (based on debug flag).
Using it:
<script src="{{ STATIC_ROOT }}js/jquery.min.js">