Django returning static HTML in views.py? - python

So I have a standard Django project with a basic view that returns a simple HTML confirmation statement. Would it be plausible for me to define all of my HTML in the view itself as a really long string and return that using HttpResponse() I know it's a bit unorthodox, but this is an example of what I'm thinking about:
from django.shortcuts import render
from django.http import HttpResponse
from django.shortcuts import render_to_response
def index(request):
html = """
<html>
<body>
This is my bare-bones html page.
</body>
</html>
"""
return HttpResponse(html)
My corresponding JS and stylesheets would be stored in the same directory as views. py in my app in this example. Just making sure: I'm not asking if this works, because I already know the answer is yes, I just want to know if there are any disadvantages/drawbacks to this method, and why don't more people do this?

You can use built-in template renderer to get works filters/templatetags/etc

Most people dont use this because it mixes Python with HTML and gets very messy and out of hand very quickly

To answer your question, this solution works alright, but it is not adopted by many programmers because it makes the whole code disorganized and not easy to understand.
Also, this system would not be good for large projects because the code would contain lots of html in the same file as the python. It is always nice and time saving to separate code into files based on performance.
A better solution
Save your html in a folder called templates in the current directory, in this case, the templates folder can contain an index.html file which would have
<html>
<body>
This is my bare-bones html page.
</body>
</html>
in the views create an index view for this template using the code below
def index(request):
return render(request, 'index.html')
if you would need to pass in some data to the html you can use context in the request as shown below:
def index(request):
context = {
"name":"some name"
}
return render(request, 'index.html', context=context)
access the data in html using the structure below:
<html>
<body>
The data passed to the page is {{name}}.
</body>
</html>
I hope this helps

Related

Unable to embed JSON Bokeh Plot in Django template

I have a script which takes uploaded data, munges it together, turns it into a plot (using Bokeh) and then exports it to a directory as JSON.
At some point in the future, a user can hit the right URL and the appropriate plot should be displayed to the user as part of the HTML template.
I can generate the plot. I can save it as JSON. I can get the URL to retrieve it as JSON, but I cannot get the JSON plot to render within the template.
I've had a dig around the Bokeh documentation and examples, but they all seem to use a flask app to serve the pages.
I think I'm on the right track, using views.py to find and return JSON as part of a render() response, and then have Bokeh.embed.embed_items() do the work in the template to make it look right, but it's not working out - everything but the plot is displayed.
1) Create the plot and puts it in the directory for later use (app/results/1)
create plot.py
import os
import json
from django.conf import settings
from bokeh.embed import json_item
from bokeh.plotting import figure
x=[1,2,3,4,5]
y=[0,-1,-2,3,4]
p=figure(title="test_example")
p.line(x, y)
#json_export = json_item(p, "result")
json_export = json_item(p)
with open(os.path.join(settings.RESULTS_DIR,"1", "test.json"), 'w') as fp:
fp.write(json.dumps(json_export))
2) Set up the url
urls.py
urlpatterns=[
path('result/<int:pk>', views.resultdetailview, name='result-detail'),
]
3) Take the request, use the pk to find the plot json and render it all in the appropriate template.
views.py
def resultdetailview(request, pk):
results=str(pk)
with open(os.path.join(settings.RESULTS_DIR, results, "test.json"), 'r') as fp:
#data=json.load(fp)
data=json.loads(fp.read())
#context={'result':data}
#return render(request, 'app/sandbox_detail.html', context)
return render(request=request,
context={'json_object':data, 'resources':CDN.render()})
NB: If I instead use return JsonResponse(data, safe=False) then the url returns the json successfully ...
I think therefore that the issue is in the template.
4) Show the wonderous plot to the user
sandbox_detail.html
<header>
<link rel="stylesheet" href="http://cdn.bokeh.org./bokeh/release/bokeh-0.11.1.min.css" type="text/css" >
<script type="text/javascript" src="http://cdn.bokeh.org./bokeh/release/bokeh-0.11.1.min.js"> </script>
</header>
<h1> Title: Test </h1>
<div>Test</div>
<body>
<div id="result"></div>
<script>
Bokeh.embed.embed_item({{json_object}}, "result");
</script>
</body>
This template renders everything but the 'result' div.
What have I missed?
This is what I see so far:
FIRST: You are mixing 2 methods for injecting plot json data into the page.
According to documentation you can do it using either of these two methods:
1) specify the div directly:
Python: json_data = json.dumps(json_item(p, "myplot"))
JavaScript: Bokeh.embed.embed_item(item);
2) specify the div in embed_item function:
Python: json_data = json.dumps(json_item(p))
JavaScript: Bokeh.embed.embed_item(item, "myplot");
But not both of them at the same time. Could this be the problem?
SECOND: Preferably don't insert Bokeh resources by hand: rather use CDN.render() or INLINE.render() to automatically include all that your script needs:
import json
from bokeh.resources import CDN
return render(request = request,
template_name = 'app/sandbox_detail.html',
context = { json_object = json.loads(json_string),
resources = CDN.render() } )
sandbox_detail.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
{{ resources }}
</head>
<body>
<div id="result"></div>
<script>
Bokeh.embed.embed_item({{ json_object }}, "result");
</script>
</body>
</html>
THIRD: Make sure what you embed in the page is json object not a string (see variable naming above)
It helps when you debug your rendered template in your browser's debug tool.
I tried a very similar approach and found one large flaw: My browser noted that it could not find the None object. The reason here is that python stores the empty value as None, while JavaScript expects a null object.
The solution? Python already translates None to null, when you run json.dumps. To keep it that way, read the json string as a string. So instead of your data=json.loads(fp.read()) use data=fp.read().

How to display object in template Flask as json?

I have a route method:
#app.route('/add', methods=['GET'])
def add_view():
return render_template('add.html', categories=api.categories())
Then I tried to display categories as JSON inside template add.html:
{{ categories | json }}
It does not work
I find it hard to understand exactly what you're looking for here so I'd like to see more details but here's an answer based on what I think you're asking for (I'll edit this to suit your needs / remove this comment entirely if things change).
You're invoking api.categories() and are looking to render this as JSON on your HTML template, yes?
OK what I'd recommend here is to ensure that api.categories() is returning an instance of dict. For example, your api.categories() call should return something like this:
{
"testKey1": "testValue1",
"testKey2": "testValue2"
}
Now to render this as JSON in your HTML template. You can import the json module in your Flask module using the following import:
import json
Now your return statement in your add_view method will be as follows:
return render_template('add.html', categories=json.dumps(api.categories()))
You can now do something like as follows in your HTML template:
<script>
document.write("{{categories}}");
<script>
This should render your JSON for you just fine.

Create a webpage with charts or tables from csv data using the pyramid framework

I have data in csv format and I want to create a webpage with charts or tables. I'm using the Pyramid Framework, chameleon, and deform_bootstrap.
I'm new to web development and there doesn't seem to be any tutorials for this out there. Can anyone point me in the right direction?
Without knowing more details its difficult to say. However, basically you will need a route registered in your config (in the root __init__.py file), a view callable (this can be just a method) to read the file and pass the data to a renderer and a chameleon template to render the data.
First set a route in your configuration. For example, to add a route for the table and one for the chart you could do something like this in your __init__.py file.
config.add_route('show_table', '/table')
config.add_route('show_chart', '/chart')
The choice of names and paths is up to you of course.
Then, you need to implement a view callable for each route. These would read the file and return a dictionary containing the data. They also tie the data to a particular renderer, in your case a chameleon template. Something like this might be right for your case where both routes need the same data.
from pyramid.view import view_config
def read_file():
"""read the file and return the data in a suitable format"""
return [1,4,2,4,56,7,45,3]
#view_config(route_name='show_table', renderer='templates/table.pt')
def table_view(request):
data = read_file()
return {'data': data}
#view_config(route_name='show_chart', renderer='templates/chart.pt')
def chart_view(request):
data = read_file()
return {'data': data}
Finally, you will need to implement the template files. These will be different depending on what you need.
<!DOCTYPE html>
<html xmlns:tal="http://xml.zope.org/namespaces/tal">
<head>
</head>
<body>
<table>
<tr><th>Data</th></tr>
<tr tal:repeat="datum data"><td>${datum}</td></tr>
</table>
</body>
</html>
To make charts I use d3.js but this is another question I think. Here is a simple example based on the first steps in this tutorial. First your template needs to make the data available to javascript. One way is to write the data into a javascript variable. This will work but is a bit messy - see this question for alternative approaches. In a real app you might want to use ajax so you would be writing the url to access the data here.
<!DOCTYPE html>
<html xmlns:tal="http://xml.zope.org/namespaces/tal">
<head>
<script src="http://d3js.org/d3.v3.min.js" charset="utf-8"></script>
</head>
<body>
<div class="chart"></div>
<script type="text/javascript">
var data = ${data};
var x = d3.scale.linear()
.domain([0, d3.max(data)])
.range([0, 420]);
d3.select(".chart")
.selectAll("div").data(data)
.enter().append("div")
.style("width", function(d) { return x(d) + "px"; })
.text(function(d) { return d; });
</script>
</body>
</html>
This should work but is untested, if you have any problems let me know and I will update it when I have a moment.

Python Pyramid: Load view based on database variable

I just started pyramid and have a problem with loading views. I want to load a view based on a variable fetched from the database like my PHP solution here: rewrite url with htaccess
I've build a script that can do this, but I'm quite sure this is not the right way to do it. I think when I use this in a real site it will get very complicated and messy. Could someone explain how to this properly or point me to an other solution?
My current script:
config.add_route('home', '/')
config.add_route('admin_home', '/admin')
config.add_route('admin_pages', '/admin/pages')
config.add_static_view(name='static', path='website:static')
config.add_route('view_loader', '/*url')
views.py
class ViewLoader(object):
def __init__(self, request):
self.request = request
#view_config(route_name="view_loader", renderer="templates/view_loader.pt")
def view_loader(self):
request = self.request
url = "/%s" % request.matchdict["url"]
page = DBSession.query(Pages).filter_by(url=url).one()
return dict(title=page.title, include=page.template)
view_loader.pt
<!DOCTYPE html>
<html>
<body>
<metal:main use-macro="load: ${include}"></metal:main>
</body>
</html>
Idea of the system:
Admins can create pages in a cms with random url's and have to select a template. The system has to generate these pages.
url = /random/random -> look for template in db -> render template_1
url = /random2/random2 -> look for template in db -> render template_2
So I want to render the template after the class/method is being called to determine what template has to be rendered
I found a more logical approach for my problem with the help of this question Map different URLs to same view. Actually the solution is quite simple I just didn't know it is possible to declare a renderer in add_view()
main.py
pages = DBSession.query(Pages)
for page in pages:
config.add_route(str(page.name), page.url)
if page.template.decode('utf-8') == "home_view":
config.add_view(home_view, route_name=str(page.name), renderer='templates/home.pt')
elif page.template.decode('utf-8') == "detail_view":
config.add_view(home_view, route_name=str(page.name), renderer='templates/detail.pt')
views.py
def home_view(self, request):
return dict(.....)

Django: Template composed of Templates

In one of my Django templates, I have a chunk of HTML which repeats at several places in the page. Is there a way I could use another template for this chunk alone and "instantiate" the template where required?
You need to read about template inheritance.
Or you can use template composition.
Inheritance is, generally, a better way to go.
I've met the same issue some time ago and here is what I got.
Seems like it's not really well documented, but there is quite obvious solution - insert HTML blocks in your main template and then pass the result of the other template render there.
Example:
In main template (app/main.html):
<!-- ... -->
{% autoescape on %}
{{html}}
{% autoescape off %}
<!-- ... -->
In view code:
from django.template.loader import get_template
def my_view(request, ...):
# Do stuff...
context = {'data': 'data'}
t = get_template('app/partial_template.html')
html = t.render(context=context)
return render(request, 'app/main.html', context={'html': html, 'rest_data': 123})
Thus you'll get some template rendered inside another template with perfect separation of concerns (parent template doesn't know anything about child's context nor about child itself).

Categories

Resources