It seems I'm misunderstanding how the route in a Flask application is related to local files (images).
Basic example:
On the home page of my website (#main_bp.route('/index'), I have some content, including a navigation bar. The nav bar contains an image, call it logo.svg. The image in the nav bar always renders correctly on the home page ('/index').
The nav bar is rendered in base.html. The img src is ../static/images/logo.svg
I have another page, call it web_content/<content_number>.
In routes.py, it looks like this: #main_bp.route('/web_content/<content_number>', methods=['GET', 'POST'])
Images, including logo.svg in the nav bar, render just fine when I navigate to this page. This page uses {% extends 'base.html' %}
I'm trying to add a layer in my website, call it content_category. So, modified routes.py like this: #main_bp.route('/web_content/<content_category>/<content_number>
This page renders, so I believe my code in routes.py is OK (content_category is defined in the function, etc.) However, when I add the content_category parameter, the image in the nav bar breaks on the content page. If I go back to the home page, the image in the nav bar renders just fine. So it doesn't seem to be a global breakage, only on the /web_content page when I add in another parameter.
This is confusing to me because I define the nav bar in only 1 place, base.html, and if the images render in one place I expect them to render everywhere.
Using a path like ../static/images/logo.svg will make the browser load that image, relative to the path in the URL. By adding parameters like content_category this is changing that URL path.
Instead use Flask's url_for function, in your template, to render the correct path dynamically:
<img src="{{ url_for('static', filename='logo.svg') }}" />
Related
I am displaying an iFrame on my template, the contents of which is from a local .html that I have uploaded as a media file.
I have X_FRAME_OPTIONS = 'SAMEORIGIN' set in my settings to allow the displaying of the contents, however when I run the --check deploy check, I get this message:
WARNINGS:
?: (security.W019) You have 'django.middleware.clickjacking.XFrameOptionsMiddleware' in your
MIDDLEWARE, but X_FRAME_OPTIONS is not set to 'DENY'. Unless there is a good reason for your site
to serve other parts of itself in a frame, you should change it to 'DENY'.
Seems like I should be keeping this set to DENY when I go to production, however by doing that, my iFrame is "unable to connect" to display the content.
I've read the documentation here that says you can set exemptions on the view level if you set it to DENY, however it's not working for me.
On the view function, I've tried using the decorators #xframe_options_sameorigin and #xframe_options_exempt like:
# #xframe_options_sameorigin # Doesn't work
# #xframe_options_exempt # Also doesn't work
# Setting X_FRAME_OPTIONS = 'SAMEORIGIN'
# and use #xframe_options_deny also doesn't work
def work_detail(request, pk):
work = Work.objects.get(pk=pk)
context = {
'work': work
}
return render(request, 'work_detail.html', context)
...but all of them still do not connect the iFrame. What else can I try?
This doesn't solve the issue, but as a workaround, instead of using an iframe, I found this solution worked for me in the template.html file:
<div w3-include-html="{{ work.html.url }}"></div>
Define the javascript on top of the template, but below {% block page_content %}
Add
<script>
includeHTML();
</script>
to the bottom of the page, but before {% endblock %}.
4. Clear cache and restart runserver. I can use that in place of the iframe, but would be nice to know why the exempts weren't working as desired?
So I am making a web app in Flask. In the layout.html file, there is a navbar on the top of the screen. It has 2 elements: Create Family and Join Family. I only want these to appear when a user a not created or joined a family.
I cannot even use the parameters of render_template() becuase the layout.html is not rendered anywhere in my app.py file
Normally, you'd have in your app.py a route that returns the template:
return render_template('child.html', data=data)
child.html extends layout.html.
data contains everything your template needs.
In your template, you'll have an if
{% if data.show_create_join_family %}
I am trying to create a blog page where my requirement is to list a group od links in a html page.
app.py:
#app.route("/blog")
def blog():
return render_template('blog.html')
blog.html:
{% extends "index.html" %}
{% block content %}
<ul>
<li>
Chapter 1
</li>
<li>
Chapter 2
</li>
<ul>
{% endblock content %}
Stored all my html pages in templates directory.
I am able to open the localhost:8000/blog where I can view all the Chapter1, chapter2 links, but when I click on the link I get error:
http://localhost:5000/templates/chapter%201.html
Not Found
The requested URL was not found on the server. If you entered the URL manually please check your spelling and try again.
I am sure that this will not work as it is pointing to different URL, can some one guide how do I implement the list of Chapter in Flask app?
If you had the static html files already, you should serve it as static file as mentioned in document here. Then, put urls for these files in your main page:
url_for('static', filename='chapter1.html')
The templates directory is not linked to a URL, the files in that directory are not 'published'. You shouldn't put files there you intent to serve without processing (executing the templates).
With the default configuration only files in the static directory are accessible via the /static/ URL path prefix, see the Static Files section of the Flask Quickstart.
The intent for the templates directory is for the files to be loadable as Jinja2 templates using the render_template() function, where you use that function in endpoint functions you registered with Flask for specific URLs.
You may want to try out the Flask tutorial first, it covers both templates and static files in more detail.
For a blog site, the normal pattern would be for you to store the blog post data in a database or text files in some way Python can easily load, then use a single template to render the contents. You'd register a URL with a pattern, which would call a function that can load any blog page data, then use the blog page template to render the output:
#app.route('/blog/<page_name>')
def blog_page(page_name):
page_data = load_blog_page(page_name)
if not page_data: # no page? Produce a not found error.
abort(404)
return render_template('blog_page.html', **page_data)
The above function will be called when a browser visits URLs that start with /blog/, and is called with the next part as the page_name variable; e.g. /blog/chapter-1 would result in page_name being set to 'chapter-1'. Note that URLs can't have spaces in them (spaces would have to be encoded to %20 for the URL to still be a URL).
The function then loads the page data (with a load_log_page() function you'd have to write yourself), then provided page_data is not empty or None or some other false-y value indicating that the page doesn't actually exist, uses the render_template() function to produce HTML output. render_template() will use the file templates/blog_page.html as the template file here, and page_data is assumed to be a dictionary whose key-value pairs make the variables the template can use.
I am trying to interactively display plots from matplotlib in django. From this answer, I see that I can send the plot from a view with this code:
response = HttpResponse(mimetype="image/png")
# create your image as usual, e.g. pylab.plot(...)
pylab.savefig(response, format="png")
return response
So the view sends the plot as an Httpresponse, but how do I reference that in the html code of the template? I'm guessing it will be something like this but am having a tough time finding examples of html code:
<img src={ some reference to the plot here }>
Again, I think I can generate the plot with a view but am not sure how to reference that output in the html template.
A view is served by a URL. This view exists purely to serve the content of an image, therefore you should simply use its URL as the src in your img tag. For instance:
urlpatterns = [
path('path/to/my/image', views.my_image, 'my_image')
]
...
def my_image(request, ...):
response = HttpResponse(mimetype="image/png")
# create your image as usual, e.g. pylab.plot(...)
pylab.savefig(response, format="png")
return response
...
<img src="{% url "my_image" %}">
Using frozen flask to make my website static, I have the following problem.
While all of my pages are being built (file//c:/correctpath/build/2014/page-title/index.html) the links to the pages are file:///c:/2014/page-title/.
Is there something I have missed?
EDIT:
In my template I have something like
{% for page in pages %}
{{ page.title }}
{% endfor %}
where .url() is a method on the page object:
return url_for('article', name=self.name, **kwargs)
url_for produces absolute paths (e. g. /2014/page-title) - when you open up your files in the browser it follows the rules regarding relative URL resolution and strips the extra file contents. If you just want to view your files as they will be seen on the server, Flask-Frozen has a run method that will let you preview your site after generating it.
Alternately, you can set FREEZER_RELATIVE_URLS to True to have Flask-Frozen generate links with index.html in them explicitly.
Rather than setting FREEZER_RELATIVE_URLS = True, with resulting URLs ending on index.html, you can also set FREEZER_BASE_URL to <http://your.website/subdir>.