Flask set local html as the src of the iframe - html

I am trying to understand how to render an html inside another html using iframe and flask
I have tried using the<iframe src="{% include 'status.html' %}" width="100%" height="100%" style="outline:none; border:none; top:5%;"></iframe> way however the server is having a weird Not Found error "GET /%3C!DOCTYPE%20html%3E%3Chtml%20lang= HTTP/1.1" 404
I have also tried using another method, as well <iframe src="{{ status }}" width="100%" height="100%" style="outline:none; border:none; top:5%;"></iframe> and in the flask
status_render = os.path.join(app.root_path, 'templates', 'status.html')
#app.route("/")
def main():
return render_template(
"index.html",
status=status_render
)
Using the second method I am getting this error "GET /home/dimitris/Documents/SmartHome/MobileApp/templates/status.html HTTP/1.1" 404 despite of the fact that the status.html does exist on the above path
I read online that it should be a a separate request which means another flask route, however I am not really sure that I am understanding how this should be implemented.

For security reasons, html files can only be rendered by calls from within the function of the flask application.
Include this code within your .py application:
#app.route('/show_status')
def show():
return render_template('status.html')
In your html file, render the file as follows:
<iframe src="{{ url_for('show_frame') }}"></iframe>
There is no need to pass arguments to the html index in the main () function:
#app.route("/")
def main():
return render_template("index.html")
Funcionou para mim.
Espero ter ajudado.

I am not sure but there is some problem is displaying any kind of static or predefined urls of html/image in flask.
In order to achieve the desired output, follow the below steps:
In the <iframe> tag, give a value that will be used as a route in app.py. For example, let say you need to display iframe in the index.html. Then create iframe tag in index.html as:
<iframe src="/statusRoute" height="200", width="500">
Now create a route with the same name in the app.py as:
#app.route('/statusRoute')
def showStatus():
  return flask.render_template('status.html')
Ensure that the status.html is present inside the templates folder.
This would render the status.html inside an iframe of the index.html page.

Related

Django Nested Views

I'm developing an internal application and I would like to be able to nest my views to keep everything nice and organized. I plan on doing this by keeping different parts of the page in their own HTML files with their own Views (separate sidebar and navbar, separate charts, etc).
views.py
from django.shortcuts import render
from django.views.generic import TemplateView
import Recall.data_logger.models as DLM
class ReportHome(TemplateView):
template_name = 'data_logger/index.html'
class SelectorSidebar(TemplateView):
template_name = 'data_logger/sidebar.html'
def get(self, request, *args, **kwargs):
companies = DLM.Company.objects.order_by('company_name').all()
return render(request, self.template_name, {'companies':companies,})
index.html
<html>
<head></head>
<body data-gr-c-s-loaded="true">
{% include 'data_logger/navbar.html' %}
<div class="container-fluid">
<div class="row">
{% include 'data_logger/sidebar.html' %} <!-- This is the part I need help with-->
</div>
</div>
</body>
</html>
sidebar.html
<div class="col-sm-3 col-md-1 sidebar">
<ul class="nav nav-sidebar">
{% for company in companies %}
<li>{{ company.company_name }}</li>
{% endfor %}
</ul>
</div>
I understand that by just using {% include 'data_logger/sidebar.html' %} it's just loading the HTML and bypassing SelectorSidebar, how do I direct it through the View?
I'd like a solution that allows me to access anything from a simple list of names to relitively large datasets being fed into a D3 chart.
Solution
This is what I ended up using:
index.html
<html>
<head>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js"
integrity="sha384-vk5WoKIaW/vJyUAd9n/wmopsmNhiy+L2Z+SBxGYnUkunIxVxAv/UtMOhba/xskxh"
crossorigin="anonymous"></script>
<script>
$.get("_sidebar", function(data, status){
$("#_sidebar").html(data);
});
</script>
</head>
<body data-gr-c-s-loaded="true">
{% include 'data_logger/navbar.html' %}
<div class="container-fluid">
<div class="row" id="_sidebar"></div>
</div>
</body>
</html>
Where _sidebar is the URL to SelectorSidebar:
urlpatterns = [
path('', v.ReportHome.as_view(), name='ReportHome'),
path('_sidebar', v.SelectorSidebar.as_view(), name='SelectorSidebar'),
]
I think you are making some confusion on how Django templates and views work together.
In very simple terms a Django template is what defines the HTML code that makes up a page. You can keep your templates very modular and organized; to do this you can use the include template tag or you can use template inheritance, which is a very powerful way to have "modular" templates.
A Django view is basically a function (or a class of you are using class based views) that receive an HTTP request and build an HTTP response.
It doesn't make much sense to have "nested" views because usually you have just one HTTP request and you want to build just a response with the HTML needed to display the page.
So I think that you can happily use Django templates to put together all the modules that make up your page (header, sidebar, etc.), but each page should correspond to a single Django view.
Another approach could use AJAX and Javascript to make different HTTP requests and build up the page client-side, but I think that this is not the approach you are considering here.
As #baxeico answered, you can't have multiple views to serve a page, because one HTTP request is one view.
If you have content that needs to appear on a lot of pages, like your sidebar, and that content also requires some context information to render (like a list of companies to fetch from the db), you have two options:
If the stuff required to add to the sidebar is fairly limited, create a template context processor that you add to the list of context processors in your settings (TEMPLATES setting).
def sidebar_context(request):
return {'companies': DLM.Company.objects.order_by('company_name').all()}
and in your settings, you'd add something like 'myapp.custom_contexts.sidebar_context' at the top of the list.
Now, every single template has access to the context variable companies, including your sidebar template.
If the stuff shown in the sidebar is more dynamic, or more complex, you should consider fetching the data from within the browser using AJAX. You would create a view that returns JSON instead of HTML and in your sidebar template add javascript to fetch the data and populate the sidebar.
The view is as simple as your current one:
def sidebar(request):
return JsonResponse({'companies': Company.objects.all().values('name', 'id')})
which will return a list of dicts containing name and id of each company. In your AJAX handler for the successful response (which receives the data), you can then loop through data and access data[i].name and data[i].id which you can use to populate your list.
I won't go as far as posting the full javascript (please search for jQuery, ajax and django) but here's a bit to give you an idea, assuming jQuery:
$(window).on('load', function() {
$.ajax({
url: "{% url 'sidebar' %}", // assuming this is inside a template, if not {% url %} won't work and you'll have to get it in a different way
success: function(data) {
if (data.length > 0) {
for (var i=0; i<data.length; i++) {
var elem = $("<li>" + data[i].name + "</li>")
$("#companies").append(elem)
}
}
})
})

Exact Same CSS Code works for one page not the other

I have a CSS stylesheet linked to a HTML page (results.html) but the CSS works only when the HTML is rendered from one route and not the other.
Both routes direct to the same HTML but CSS only works on one of them.
results.html:
<head>
<link rel="stylesheet" type="text/css" href="static/css/tab.css?version=3423">
</head>
css works here:
#app.route('/kinase', methods=['GET', 'POST'])
def kinase():
search = KinaseSearchForm(request.form)
if ...
return k_search_results(search)
return render_template('kinase.html', form=search)
#app.route('/k_search_results')
def k_search_results(search):
results = []
search_string = search.data['search']
...
else:
# display results
return render_template('results.html', results=results)
but not here:
#app.route('/profile/<kinase>')
def profile(kinase):
...
return render_template('results.html', results=results)
I put the .css and .html in the same root folder but no luck there either.
I also tried all hard reset/bypassing cache options.
the message I get is (not sure why its adding profile here - have no directory called profile):
"GET /profile/static/css/tab.css?version=3423 HTTP/1.1" 404 -
whereas with the first html it seems to know where the tab.css file is:
"GET /static/css/tab.css?version=3423 HTTP/1.1" 200 -
Since you are pointing to the same CSS file from different directories, you need to use an absolute path. /static/css/tab.css?version=3423.

PDF renders as empty white box

I have a project named "Project", and a PDF file caled "file.pdf" located in Project/app/assets/file.pdf. I want to render the PDF on a page called "file.html", located in Project/app/views/static/file.html.
I wrote the following code, but all that displays is an empty white box.
<embed src="../../assets/file.pdf" width="500" height="375" type='application/pdf'>
I'm pretty sure my browser can't find the file. What could I be doing wrong?
UPDATE: I also tried it with an image, placed in app/assets/images/Image.png, like so:
<embed src="../../assets/images/Image.png" width="500" height="375" type='image/png'>
but that doesn't render either.
UPDATE 2: Output from console:
Started GET "/file" for 127.0.0.1 at 2016-02-21 04:48:27 -0600
Processing by StaticController#file as HTML
Rendered static/file.html.erb within layouts/application (63.8ms)
Completed 200 OK in 757ms (Views: 749.4ms | ActiveRecord: 0.0ms)
Started GET "/assets/application.self-e570ac372b74f676a029186250aeeba9bf7016bcd014314d103b5d18b3eb858e.css?body=1" for 127.0.0.1 at 2016-02-21 04:48:28 -0600
Started GET "/assets/pdf-8f705790d319666d8f804cf8809f4d74f036483049ef8c520646d6c98ebedc5f.png" for 127.0.0.1 at 2016-02-21 04:48:28 -0600
Started GET "/assets/Advanced_Reading_Sample.pdf" for 127.0.0.1 at 2016-02-21 04:48:28 -0600
In your controller write,
def file
pdf_filename = File.join(Rails.root, "/assets/file.pdf")
send_file(pdf_filename, :filename => pdf_filename, :disposition => 'inline', :type => "application/pdf")
end
Rename your file.html => file.html.erb and place it under views/controller_name/file.html.erb, also add route to this controller action.
In above setup when you access controller/file/ pdf will shown in the browser(inline).
Try this and see if it works
<iframe src="yourfile.pdf" style="width:100%; height:700px;" frameborder="0"></iframe>
Create folder called pdf (for example) in app/assets and put there your file.pdf then in app/views/static/file.html change src of embed tag to /assets/file.pdf. This should do the trick.
Try, This will help
Click To View
thanks
Mark SykOv
Well I have no idea why my app can't find the file. I just ended up using iframes and the absolute url of the file:
<iframe src="http://www.project.com/file.pdf" style="width:100%;height:100%;"><p>Your browser does not support iframes.</p></iframe>
And finally, the file renders.

GSP Template fails to retrieve passed template from another template

I'm working on a Grails 2.4.4 project. I have the following code on my gsp page (not a template) that calls a sub template that calls another template: main gsp page > gsp template > yet another gsp template:
main.gsp
...
<g:render template="/details" model="[param_one:'param_one', param_two:'param_two']" />
...
_details.gsp
...
<p>On details: ${param_one}</p>
<g:render template="/segments/segment-one" model="[param_two:'${param_two}']" />
...
_segment-one.gsp
<p>Segment One: ${param_two}</p>
Now when it renders the whole page, it only shows something like this:
On details: param_one
Segment One: ${param_two}
Why does _segment-one.gsp fails to render the passed param_two? Is it not allowed to have template from another template rendering? Thanks guys.
First, you are allowed to have gsp pages call templates that call templates indefinitely. When you call a template, you are literally including the code of the template into the including page at runtime; in other words, a template is part of the caller and it would have access by default to all objects visible to the caller. All you have to do is to change your second inclusion to:
<g:render template="/segments/segment-one" />
Now, template segment-one will already have access to param_one and param_two. You only need to use your model tag again if you are passing something new created in the local template (or gsp) you are in.
I fixed the code in _segment-one.gsp by adding the params keyword:
<p>Segment One: ${params.param_two}</p>
^^^^^^

Creating HTML wrapper in django for matplotlib images

I would like to take python generated matplotlib images and embed them into an HTML page that is generated by django. I am relatively new to django and have been struggling to get this to work. I can successfully generate a matplotlib image alone on a webpage but have been unable to embed into an HTML page. Django makes sense as my application will have many users that will have custom views with different data and frequently changing data coming from a database. I would like to avoid creating many static files.
I have looked at several posts but I am clearly missing something. For example:
Generating dynamic charts with Matplotlib in Django, images on django site from matplotlib and Dynamically serving a matplotlib image to the web using python.
I generate my matplotlib image view with temp and I think the wrapper is detail. detail does not seem to work. The filename plotdata.py and under the django tutorial example polls
from datetime import datetime, time
from django.http import HttpResponse
from matplotlib.backends.backend_agg import FigureCanvasAgg as FigureCanvas
from matplotlib.figure import Figure
from django.contrib.auth.decorators import login_required
from django.shortcuts import render
#login_required()
def temp(request,x_id):
#... code to generate fig for ploting - works well
#This works but does not seem to pass file to HTML
canvas = FigureCanvas(fig)
response = HttpResponse(content_type='image/png')
canvas.print_png(response)
return response
#login_required()
def detail(request, x_id):
render(request, 'polls/plotdata.html', {'x_id': x_id})
My urls.py is as follows. temp works fine
from django.conf.urls import patterns, url
from django.views.generic import DetailView, ListView
from polls.models import Poll
from polls import plotdata
urlpatterns = patterns('',
#polls url chopped out for brevity - follows tutorial
url(r'^(?P<x_id>\d+)/plotdata/temp.png$', plotdata.temp, name='temp'),
url(r'^(?P<x_id>\d+)/plotdata/detail$', plotdata.detail, name='detail'),
)
My plotdata.html is as follows
<!DOCTYPE html>
<html lang="en">
<head>
<link rel="stylesheet" href="style.css" />
<title>{% block title %}Plotting Template{% endblock %}</title>
</head>
<body>
<div id="content">
{% block content %}
<img src="{% url 'temp' x_id %}" >
{% endblock %}
</div>
</body>
</html>
The error generated is as follows.
NoReverseMatch at /polls/1303070002/plotdata/detail
Reverse for 'temp' with arguments '('1303070002',)' and keyword arguments '{}' not found.
This probably not the only problem with the above. I am certain I have missed something critical.
I tried hardcoding, as a test, to
<img src="/polls/1303070002/plotdata/temp.png" >
but it generated the following error
ValueError at /polls/1303070002/plotdata/detail
The view polls.plotdata.detail didn't return an HttpResponse object.
I would like to get this framework working so I can put text and buttons around the data plot. I am open to other ways to more efficiently create a solution. Thank you very much for helping out!
Repaired code, plotadata.py, is as follows
#same header information from above before this line
canvas = FigureCanvas(fig) #This needs to remain for savefig or print_png command
response = HttpResponse(content_type='image/png')
fig.savefig(response, format='png') #Produces all white background
return response
def detail(request, salesorder_id):
return render(request, 'rsa/plotdata.html', {'x_id':x_id})
I included return before render this time... Changed path to hmtl file to avoid confusion with polls app. Using savefig versus print_png as it formats more generically. urls.py is the same. I am trying to get plotdata.html to work as above, passing a variable to url via {{ x_id }} but I am missing something. Same error as above, NoReverseMatch. If I replace, in plotdata.html
<img src="{% url 'temp' x_id %}" >
with
{% load staticfiles %}
<img src="{% static '/rsa/1303070001/plotdata/temp.png' %}" >
the image is embedded as desired. Now adding a dynamic path such as
<img src="{% static '/rsa/{{ x_id }}/plotdata/temp.png' %}" >
just escapes the literal x_id => /rsa/%7B%7B%20x_id%20%7D%7D/plotdata/temp.png. Trying x_id|safe ends up escaping the pipe and including literal safe... %7B%7B%20x_id%7Csafe%20%7D%7D. Hence I am trying to go back to using url versus static. Seems cleaner. I think there is something wrong with the variable I am passing, x_id