i recently started my django course online nad getting some problem.
i am not able to use my variable which i passed from index.html to about.html.
but in about.html it is not shown up.
.py file code :
from django .http import HttpResponse
from django.shortcuts import render
def index(request):
return render(request , 'index.html')
def about(request):
t1 = print(request.GET.get('text' , 'default'))
return render(request , 'about.html' , t1)
index.html file code:
<!DOCTYPE html>
<html>
<head>
<title>template</title>
</head>
<body>
<h1> hello everyone </h1>
<form action="/about" , method="get">
<textarea name="text" style="margin: 0px; width: 1245px; height: 171px;"></textarea>
<input type="submit" name="OK">
</form>
</body>
</html>
about.html file code :
<!DOCTYPE html>
<html>
<head>
<title>template</title>
</head>
<body>
<h1>you typed {{t1}}</h1>
</form>
</body>
</html>
print(..) does not return anything. You can pass the variable to the context, for example:
def about(request):
return render(
request ,
'about.html' ,
{'t1': request.GET.get('text' , 'default')}
)
Related
so I was studying flask and how to request http methods.I am able to run html.But when i request url they are showing error.please guide me.code is attached herewith.Thanks in advance.
<html>
<head> sub </head>
<body>
<form action="http://localhost:5000/submit",method="path">
<p>Enter name</p>
<p> <input type="text",name="nm" /> </p>
<p><input type="submit",value="submit" /></p>
</form>
</body>
</html>
from flask import Flask,url_for,redirect,request
app=Flask(__name__)
#app.route('/page/<name>')
def display(name):
return 'Hello %s'%name
#app.route('/submit',methods=['POST','GET'])
def submit():
if request.methods=='POST':
user=request.form['nm']
return redirect(url_for('display',name=user))
else:
user=request.args.get('nm')
return redirect(url_for('display',name=user))
if __name__=='__main__':
app.run(debug=True)
Use url_for template tag for mentioning url in html and also method should be POST and remove those , in your html.
<form action="{{ url_for('sumbit') }}" method="POST">
Always .format for string operations
return "Hello {}".format(name)
I'm writing my first Django app by following along with this book:
http://chimera.labs.oreilly.com/books/1234000000754/ch05.html#_passing_python_variables_to_be_rendered_in_the_template
In the book there is a test that is verifying that the html is being returned as it is supposed to. Here is the test:
def test_home_page_returns_correct_html(self):
request = HttpRequest()
response = home_page(request)
expected_html = render_to_string('home.html')
print(expected_html)
print(response.content.decode())
self.assertEqual(response.content.decode(), expected_html)
My test is failing on the assertEqual test because I have added a csrf token in my HTML using the Django Template Language. Here is what my HTML page looks like:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>To-Do lists</title>
</head>
<body>
<h1>Your To-Do list</h1>
<form method="POST">
<input name="item_text" id="id_new_item" placeholder="Enter a to-do item"/>
{% csrf_token %}
</form>
<table id="id_list_table">
<tr><td>{{ new_item_list }}</td></tr>
</table>
</body>
</html>
My assert is failing due to the render_to_string method not including the token. Here is what my two print statements included in my test print out:
F<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>To-Do lists</title>
</head>
<body>
<h1>Your To-Do list</h1>
<form method="POST">
<input name="item_text" id="id_new_item" placeholder="Enter a to-do item"/>
</form>
<table id="id_list_table">
<tr><td></td></tr>
</table>
</body>
</html>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>To-Do lists</title>
</head>
<body>
<h1>Your To-Do list</h1>
<form method="POST">
<input name="item_text" id="id_new_item" placeholder="Enter a to-do item"/>
<input type='hidden' name='csrfmiddlewaretoken' value='VAiGvXZLHCjxWEWdjhgQRBwBSnMVoIWR' />
</form>
<table id="id_list_table">
<tr><td></td></tr>
</table>
</body>
</html>
F.
He doesn't have this problem in the book (he's using 1.8), so I was wondering if the method behavior has changed, or how I would write this test to pass.
The request argument was added to render_to_string in Django 1.8. You could try changing the line in your test to:
expected_html = render_to_string('home.html', request=request)
It's only required to make this change in Django 1.9+, the test passes without the request in Django 1.8.
I found this solution which has worked for the latest Django version - 3.0.6
#add a function to the post request test function
def remove_csrf_tag(text):
"""Remove csrf tag from TEXT"""
return re.sub(r'<[^>]*csrfmiddlewaretoken[^>]*>', '', text)
...
# then change assertion
def test_home_page_can_save_a_POST_request(self):
...
self.assertEqual(
remove_csrf_tag(response.content),
remove_csrf_tag(expected_html)
)
I am following the book "Test-Driven Development in Python" and have the following functions:
tests.py:
def testHomePageCanSaveAPostRequest(self):
request = HttpRequest()
request.method = 'POST'
request.POST['itemText'] = 'A new list item'
response = homePage(request)
if response:
response = response.content.decode('UTF-8')
self.assertIn('A new list item', response)
expectedHTML = render(request, 'lists/home.html', {'itemText':'A new list item'})
if expectedHTML:
expectedHTML = expectedHTML.content.decode('UTF-8')
print(response)
print(expectedHTML)
if response==expectedHTML:
print('Same')
self.assertIn('A new list item', expectedHTML)
self.assertEqual(response, expectedHTML)
views.py
def homePage(request):
print(request.POST.get('itemText'))
return render(request, 'lists/home.html', {'itemText':request.POST.get('itemText')})
home.html:
...
<form method=POST>
<input id=newItem name=itemText placeholder="Enter a to-do item">
</form>
<table id=listTable>
<tr><td>{{itemText}}</td></tr>
</table>
...
Both assertIn(..., response) and assertIn(..., expectedHTML) are successful, which means both response and expectedHTML have 'A new list item' in them.
I also print out response and expectedHMTL, and they look exactly the same. The comparison also print out 'Same' showing that they are the same.
However, the assertEqual fails with the following line by line comparison:
...
<table id=listTable>
- <tr><td>None</td></tr>
? ----
+ <tr><td></td></tr>
</table>
...
One is None and the other is empty.? What did I do wrong?
EDIT:
The entire test output is listed in the following:
Creating test database for alias 'default'...
A new list item
<!doctype html>
<html>
<head>
<title>To do list</title>
<meta charset=utf-8>
</head>
<body>
<h1>Your to do list</h1>
<form method=POST>
<input id=newItem name=itemText placeholder="Enter a to-do item">
</form>
<table id=listTable>
<tr><td>A new list item</td></tr>
</table>
</body>
</html>
<!doctype html>
<html>
<head>
<title>To do list</title>
<meta charset=utf-8>
</head>
<body>
<h1>Your to do list</h1>
<form method=POST>
<input id=newItem name=itemText placeholder="Enter a to-do item">
</form>
<table id=listTable>
<tr><td>A new list item</td></tr>
</table>
</body>
</html>
Same
.None
F.
======================================================================
FAIL: testHomePageReturnsCorrectHTML (lists.tests.HomePageTest)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/home/yltang/course/TDD/lecture/python/webapps/git/superlists/superlists/lists/tests.py", line 27, in testHomePageReturnsCorrectHTML
self.assertEqual(response, expectedHTML)
AssertionError: '<!do[231 chars]stTable>\n <tr><td>None</td></tr>\n</table>\n</body>\n</html>' != '<!do[231 chars]stTable>\n <tr><td></td></tr>\n</table>\n</body>\n</html>'
<!doctype html>
<html>
<head>
<title>To do list</title>
<meta charset=utf-8>
</head>
<body>
<h1>Your to do list</h1>
<form method=POST>
<input id=newItem name=itemText placeholder="Enter a to-do item">
</form>
<table id=listTable>
- <tr><td>None</td></tr>
? ----
+ <tr><td></td></tr>
</table>
</body>
</html>
----------------------------------------------------------------------
Ran 3 tests in 0.017s
FAILED (failures=1)
Destroying test database for alias 'default'...
You have added the print statements to a different test. The print statements are in testHomePageCanSaveAPostRequest, which is passing.
The failing test is testHomePageReturnsCorrectHTML, which you have not included in your question.
I have a Flask app that will run on OpenShift, that takes a while to generate data and can lead to a timeout error.
From looking at examples, I thought that I could render a "please wait" template which returns immediately, while also calling my long running, run_analysis() function. When the data was finished being collected, run_analysis() would render a new page.
Either this isn't possible or I'm doing it wrong. Thanks for your help.
from flask import Flask
import jinja2
app = Flask(__name__)
please_wait_template = jinja2.Template('''
<!DOCTYPE html>
<html lang="en">
<head>
<title>please wait for data</title>
<meta charset="UTF-8">
</head>
<body>
<h1>Collecting data, this could take a while.</h1>
</body>
</html>''')
input_template = jinja2.Template('''
<!DOCTYPE html>
<html lang="en">
<head>
<title>Input Keywords</title>
<meta charset="UTF-8">
</head>
<body>
<h1>Doing stuff</h1>
<form action="/please_wait/" method="POST">
Enter keywords<br>
<input type="text" name="kw" placeholder="data science"><br>
<input type="submit" value="Submit" name="submit">
</form>
</body>
</html>''')
output_template = jinja2.Template("""
<!DOCTYPE html>
<html lang="en-US">
<head>
<title>results</title>
<meta charset="UTF-8">
</head>
<body>
<h1>RESULTS</h1>
{{ results }}
</body>
</html>
""")
#app.route('/')
def render_input_page():
return input_template.render()
#app.route('/please_wait/')
def please_wait():
return please_wait_template.render()
#app.route('/please_wait/', methods=['post'])
def run_analysis():
kws = request.form['kw']
zips = request.form['zipcodes']
template = run_long_analysis(kws, zips)
return template
def run_long_analysis(kws, zips):
import time
time.sleep(2400)
return output_template(results="testing")
Yes, it is possible. You will want to break out of the single file however. i.e. creating a templates directory and storing your templates there. http://flask.pocoo.org/docs/0.10/quickstart/#rendering-templates
Quoting the docs basic example:
from flask import render_template
#app.route('/hello/')
#app.route('/hello/<name>')
def hello(name=None):
return render_template('hello.html', name=name)
You can see render_template is used instead of the .render() or output_template. This is convenient and it makes reading the Flask logic easier.
Specifically to your code:
#app.route('/please_wait/', methods=['post'])
def run_analysis():
kws = request.form['kw']
zips = request.form['zipcodes']
template = run_long_analysis(kws, zips)
The line zips = request.form['zipcodes'] would be troublesome, because I don't see a form under the please_wait route. Perhaps you realize that though.
In general, a tool that will help in situations like this, in my experience is the Flask session object. Which is basically a global dictionary that persists across a user session. See more here in the docs http://flask.pocoo.org/docs/0.10/quickstart/#sessions.
Quoting that example:
from flask import Flask, session, redirect, url_for, escape, request
app = Flask(__name__)
#app.route('/')
def index():
if 'username' in session:
return 'Logged in as %s' % escape(session['username'])
return 'You are not logged in'
#app.route('/login', methods=['GET', 'POST'])
def login():
if request.method == 'POST':
session['username'] = request.form['username']
return redirect(url_for('index'))
return '''
<form action="" method="post">
<p><input type=text name=username>
<p><input type=submit value=Login>
</form>
'''
#app.route('/logout')
def logout():
# remove the username from the session if it's there
session.pop('username', None)
return redirect(url_for('index'))
# set the secret key. keep this really secret:
app.secret_key = 'A0Zr98j/3yX R~XHH!jmN]LWX/,?RT'
You can see in the above example that the session object behaves like a dict. It also allows you to dynamically change content displayed, via Jinja2. In other words, it can be passed into the template. These methods in conjunction, should give you the functionality you are looking for.
I was having trouble exporting images in an html file as pdf, a similar solution exists here.
The html is being rendered properly on the server. I verified it by cross checking it on a url.
but while trying to download/render the pdf **i get a pdf but which is blank, also it says error in the third line of the download function in views.py
Here is what i tried:
html file:
<html>
<head>
<link href="{{ STATIC_URL }}css/certificate.css" rel="stylesheet"
type="text/css" />
</head>
<body>
<div class="certificate_container">
<div class="statictext">
<p>{{ name }}</p>
</div>
</div>
</body>
<html>
css file:
body{margin:0px; padding:0px;}
.certificate_container{ width:792px; height:612px; background:url("../images/certificate.gif") no-repeat;}
.statictext{width:400px; margin:0px auto; padding-top:240px; height:30px; text-align:center; font:bold 14px Arial, Helvetica, sans-serif; color:#333;}
views.py:
#relevant imports
from reportlab.pdfgen import canvas
import xhtml2pdf.pisa as pisa
import cStringIO as StringIO
def download(request):
html = render_to_string("certificate.html", { 'pagesize' : 'A4', }, context_instance=RequestContext(request))
result = StringIO.StringIO()
pdf = pisa.pisaDocument(StringIO.StringIO(), dest=result, link_callback=fetch_resources )
if not pdf.err:
return HttpResponse(result.getvalue(), mimetype='application/pdf')
return HttpResponse('Gremlins ate your pdf! %s' % cgi.escape(html))
def fetch_resources(uri, rel):
path = os.path.join(settings.STATIC_ROOT, uri.replace(settings.STATIC_URL, ""))
return path
def home(request):
return render(request, 'certificate.html', {'name':'user1'} )
The urls have been taken care of properly.
I later found, this could not be achieved using the above tech stack, hence i tried getting a template image and used PIL to modify it based on context. And that worked.