I've been trying to modify a string before passing it to my HTML page in Flask (replacing occurrences of '\n' with '<br>'), but the typical methods I use aren't working for some reason.
finalstring = textstring.replace('\n', '<br>')
return render_template('my-form-result.html', emailresponse = finalstring)
This should work, but for some reason, nothing is replaced. How can I get this to work? Thanks!
A better way to replace \n in HTML is using CSS styles.
Your replace() is alright. Debug your code and make sure there is \n before replace().
To be able to view linebreaks in HTML you should use safe filter in the template. But beware that you become open to XSS attacks. To get round this problem you should escape the string before replacing the \n character. This is the code:
from flask import escape
...
...
safe_html = str(escape(text)).replace('\n', '<br/>')
return render_template('[HTML file].html', safe_html=safe_html)
---------
#in the template:
<span> {{ safe_html | safe }} </span>
If you don't use the str() call before replace, then the <br/> will be scaped too. Because the return value from escape() is not string.
Disclaimer: I never worked with Flask, I just looked it up and hope it does what you want to do.
So somewhere in your template my-form-result.html you should find a line containing:
{{ emailresponse }}
You can replace this with:
{% for line in emailresponse.split('\n') %}
{{ line }}
<br />
{% endfor %}
To add an br after every newline
Your replace() code is correct. Make sure you escape the HTML in the template:
{{ emailresponse|safe }}
To diagnose, try this:
finalstring = textstring.replace('\n', '<br>')
print(finalstring)
return render_template('my-form-result.html', emailresponse = finalstring)
Also, show us the source code from the web page, to see what is actually rendering in the template
I am working on a project in Django where I simply count the number of words when I input a sentence. I also try to save the number of words in a .txt file evry time I use the website.
The views.py is:
from django.http import HttpResponse
from django.shortcuts import render
def homepage(request):
return render(request,'home.html')
def count(request):
fulltext = request.GET['fulltext']
wordlist = fulltext.split()
f=open('abc.txt','a+')
f.write('\n')
f.write(wordlist)
f.close()
return render(request,'count.html', {'fulltext':fulltext, 'count':len(wordlist)})
The homepage where I give the input sentence is:
<h1> Word Count </h1>
<form action = "{% url 'count' %}">
<textarea col='40' rows = '5' name = "fulltext"></textarea>
<br/>
<input type = 'submit' value= 'count!' />
</form>
The page where I show the output along with the number of words is:
<h1> hey, there are {{count}} words</h1>
<h1> your text </h1>
{{fulltext}}
The program runs well in the UI portion. As I give the input sentence in the homepage and submit it, I get the results in the output page. It also generates a abc.txt file in the working directory. However, there is a repetation of the part of the code there as in the .txt file I get the same output twice. That is, if the input sentence is "Tom and Jerry" then the .txt file stores 3 (the number of words in the sentence) twice instead of once.
Can someone help?
Looking for recommendation of a library in Python(first preference) or NodeJS that can generate a pdf file preferably from dynamic html template to be run in AWS. Requirement is to generate invoice pdf to be sent to customers.
Have come across below 2 Node libraries:
PDFKit
jsPDF
Here we might have to deal with numbers for X and Y.
Better approach would be something where we can simply use html/css to generate template with placeholders which can be replaced with dynamic data(coming from database query).
Any suggestions would be appreciated.
Thanks!
This approach worked for me in Python using below libraries:
Jinja2 - for generating HTML with custom data
xhtml2pdf - for generating PDF from HTML
Consider within your PROJECT DIR, there is a template file(invoice.html) and python file(pdf_generator.py)
pdf_generator.py
from xhtml2pdf import pisa
import jinja2
templateLoader = jinja2.FileSystemLoader(searchpath="./")
templateEnv = jinja2.Environment(loader=templateLoader)
TEMPLATE_FILE = "invoice.html"
template = templateEnv.get_template(TEMPLATE_FILE)
# This data can come from database query
body = {
"data":{
"order_id": 123,
"order_creation_date": "2020-01-01 14:14:52",
"company_name": "Test Company",
"city": "Mumbai",
"state": "MH",
}
}
# This renders template with dynamic data
sourceHtml = template.render(json_data=body["data"])
outputFilename = "invoice.pdf"
# Utility function
def convertHtmlToPdf(sourceHtml, outputFilename):
# open output file for writing (truncated binary)
resultFile = open(outputFilename, "w+b")
# convert HTML to PDF
pisaStatus = pisa.CreatePDF(
src=sourceHtml, # the HTML to convert
dest=resultFile) # file handle to receive result
# close output file
resultFile.close()
# return True on success and False on errors
print(pisaStatus.err, type(pisaStatus.err))
return pisaStatus.err
if __name__ == "__main__":
pisa.showLogging()
convertHtmlToPdf(sourceHtml, outputFilename)
invoice.html
<!DOCTYPE html>
<html lang="en">
<body>
Name: {{ json_data.company_name }} <br>
City/State: {{ json_data.city }}, {{ json_data.state }} <br>
Date: {{ json_data.order_creation_date }} <br>
Order ID: {{ json_data.order_id }} <br>
</body>
</html>
https://www.npmjs.com/package/pdfmake
The above library allows flexibility when it comes to dynamic invoices in node.js
With https://getpdfapi.com you can design PDF templates using a web-based editor and once you finish, a REST API endpoint will be created just for you.
This endpoint can be used to send your data in JSON format to the PDF template you've just created.
The only code you need to write is the code that integrates the API.
You can check a quick demo here: https://www.youtube.com/watch?v=cv4ZYd_aJO8
I have a dataframe that contains a column containing <canvas> something </canvas> element. In a flask application, I passed this data to a template using df.to_html(), but it never is working and always shows the <canvas> within displayed html table.
To enable showing the characters <, >, and & signs in to_html() method, we need to change the escape attribute to False. Because by default to_html method converts the characters <, >, and & to HTML-safe sequences. Also we need to use safe filter in the template file to show the tags inside the table.
As you have already found how to show the HTML properly in Flask template, I am giving an example of the operation for future readers.
app.py contains a dataframe with html tags which we want to render in the template:
import pandas as pd
from flask import Flask, render_template
def get_panda_data():
tags = ["<h1>Example header</h1>",
'<div style="color: red;">Example div</div>',
'<input type="text" name="example_form" \
placeholder="Example input form">'
]
pd.set_option('display.max_colwidth', -1)
tags_frame = pd.DataFrame(tags, columns = ["Tag Example"])
tags_html = tags_frame.to_html(escape=False)
return tags_html
app = Flask(__name__)
#app.route('/')
def index():
html_data = get_panda_data()
return render_template("dataframe_example.html", html_data = html_data)
if __name__ == '__main__':
app.run(debug = True)
Then in template file which is dataframe_example.html we can easily show the data table generated by pandas to_html method:
<!DOCTYPE html>
<html>
<head>
<title>Dataframe Flask Example</title>
</head>
<body>
<h1>Dataframe Flask Example</h1>
{{ html_data | safe }}
</body>
</html>
The output looks like:
I realized that I had to utilize the option to_html(escape=False) to solve this problem
I have a string that is HTML encoded:
'''<img class="size-medium wp-image-113"\
style="margin-left: 15px;" title="su1"\
src="http://blah.org/wp-content/uploads/2008/10/su1-300x194.jpg"\
alt="" width="300" height="194" />'''
I want to change that to:
<img class="size-medium wp-image-113" style="margin-left: 15px;"
title="su1" src="http://blah.org/wp-content/uploads/2008/10/su1-300x194.jpg"
alt="" width="300" height="194" />
I want this to register as HTML so that it is rendered as an image by the browser instead of being displayed as text.
The string is stored like that because I am using a web-scraping tool called BeautifulSoup, it "scans" a web-page and gets certain content from it, then returns the string in that format.
I've found how to do this in C# but not in Python. Can someone help me out?
Related
Convert XML/HTML Entities into Unicode String in Python
With the standard library:
HTML Escape
try:
from html import escape # python 3.x
except ImportError:
from cgi import escape # python 2.x
print(escape("<"))
HTML Unescape
try:
from html import unescape # python 3.4+
except ImportError:
try:
from html.parser import HTMLParser # python 3.x (<3.4)
except ImportError:
from HTMLParser import HTMLParser # python 2.x
unescape = HTMLParser().unescape
print(unescape(">"))
Given the Django use case, there are two answers to this. Here is its django.utils.html.escape function, for reference:
def escape(html):
"""Returns the given HTML with ampersands, quotes and carets encoded."""
return mark_safe(force_unicode(html).replace('&', '&').replace('<', '&l
t;').replace('>', '>').replace('"', '"').replace("'", '''))
To reverse this, the Cheetah function described in Jake's answer should work, but is missing the single-quote. This version includes an updated tuple, with the order of replacement reversed to avoid symmetric problems:
def html_decode(s):
"""
Returns the ASCII decoded version of the given HTML string. This does
NOT remove normal HTML tags like <p>.
"""
htmlCodes = (
("'", '''),
('"', '"'),
('>', '>'),
('<', '<'),
('&', '&')
)
for code in htmlCodes:
s = s.replace(code[1], code[0])
return s
unescaped = html_decode(my_string)
This, however, is not a general solution; it is only appropriate for strings encoded with django.utils.html.escape. More generally, it is a good idea to stick with the standard library:
# Python 2.x:
import HTMLParser
html_parser = HTMLParser.HTMLParser()
unescaped = html_parser.unescape(my_string)
# Python 3.x:
import html.parser
html_parser = html.parser.HTMLParser()
unescaped = html_parser.unescape(my_string)
# >= Python 3.5:
from html import unescape
unescaped = unescape(my_string)
As a suggestion: it may make more sense to store the HTML unescaped in your database. It'd be worth looking into getting unescaped results back from BeautifulSoup if possible, and avoiding this process altogether.
With Django, escaping only occurs during template rendering; so to prevent escaping you just tell the templating engine not to escape your string. To do that, use one of these options in your template:
{{ context_var|safe }}
{% autoescape off %}
{{ context_var }}
{% endautoescape %}
For html encoding, there's cgi.escape from the standard library:
>> help(cgi.escape)
cgi.escape = escape(s, quote=None)
Replace special characters "&", "<" and ">" to HTML-safe sequences.
If the optional flag quote is true, the quotation mark character (")
is also translated.
For html decoding, I use the following:
import re
from htmlentitydefs import name2codepoint
# for some reason, python 2.5.2 doesn't have this one (apostrophe)
name2codepoint['#39'] = 39
def unescape(s):
"unescape HTML code refs; c.f. http://wiki.python.org/moin/EscapingHtml"
return re.sub('&(%s);' % '|'.join(name2codepoint),
lambda m: unichr(name2codepoint[m.group(1)]), s)
For anything more complicated, I use BeautifulSoup.
Use daniel's solution if the set of encoded characters is relatively restricted.
Otherwise, use one of the numerous HTML-parsing libraries.
I like BeautifulSoup because it can handle malformed XML/HTML :
http://www.crummy.com/software/BeautifulSoup/
for your question, there's an example in their documentation
from BeautifulSoup import BeautifulStoneSoup
BeautifulStoneSoup("Sacré bleu!",
convertEntities=BeautifulStoneSoup.HTML_ENTITIES).contents[0]
# u'Sacr\xe9 bleu!'
In Python 3.4+:
import html
html.unescape(your_string)
See at the bottom of this page at Python wiki, there are at least 2 options to "unescape" html.
Daniel's comment as an answer:
"escaping only occurs in Django during template rendering. Therefore, there's no need for an unescape - you just tell the templating engine not to escape. either {{ context_var|safe }} or {% autoescape off %}{{ context_var }}{% endautoescape %}"
If anyone is looking for a simple way to do this via the django templates, you can always use filters like this:
<html>
{{ node.description|safe }}
</html>
I had some data coming from a vendor and everything I posted had html tags actually written on the rendered page as if you were looking at the source.
I found a fine function at: http://snippets.dzone.com/posts/show/4569
def decodeHtmlentities(string):
import re
entity_re = re.compile("&(#?)(\d{1,5}|\w{1,8});")
def substitute_entity(match):
from htmlentitydefs import name2codepoint as n2cp
ent = match.group(2)
if match.group(1) == "#":
return unichr(int(ent))
else:
cp = n2cp.get(ent)
if cp:
return unichr(cp)
else:
return match.group()
return entity_re.subn(substitute_entity, string)[0]
Even though this is a really old question, this may work.
Django 1.5.5
In [1]: from django.utils.text import unescape_entities
In [2]: unescape_entities('<img class="size-medium wp-image-113" style="margin-left: 15px;" title="su1" src="http://blah.org/wp-content/uploads/2008/10/su1-300x194.jpg" alt="" width="300" height="194" />')
Out[2]: u'<img class="size-medium wp-image-113" style="margin-left: 15px;" title="su1" src="http://blah.org/wp-content/uploads/2008/10/su1-300x194.jpg" alt="" width="300" height="194" />'
I found this in the Cheetah source code (here)
htmlCodes = [
['&', '&'],
['<', '<'],
['>', '>'],
['"', '"'],
]
htmlCodesReversed = htmlCodes[:]
htmlCodesReversed.reverse()
def htmlDecode(s, codes=htmlCodesReversed):
""" Returns the ASCII decoded version of the given HTML string. This does
NOT remove normal HTML tags like <p>. It is the inverse of htmlEncode()."""
for code in codes:
s = s.replace(code[1], code[0])
return s
not sure why they reverse the list,
I think it has to do with the way they encode, so with you it may not need to be reversed.
Also if I were you I would change htmlCodes to be a list of tuples rather than a list of lists...
this is going in my library though :)
i noticed your title asked for encode too, so here is Cheetah's encode function.
def htmlEncode(s, codes=htmlCodes):
""" Returns the HTML encoded version of the given string. This is useful to
display a plain ASCII text string on a web page."""
for code in codes:
s = s.replace(code[0], code[1])
return s
You can also use django.utils.html.escape
from django.utils.html import escape
something_nice = escape(request.POST['something_naughty'])
Below is a python function that uses module htmlentitydefs. It is not perfect. The version of htmlentitydefs that I have is incomplete and it assumes that all entities decode to one codepoint which is wrong for entities like ≂̸:
http://www.w3.org/TR/html5/named-character-references.html
NotEqualTilde; U+02242 U+00338 ≂̸
With those caveats though, here's the code.
def decodeHtmlText(html):
"""
Given a string of HTML that would parse to a single text node,
return the text value of that node.
"""
# Fast path for common case.
if html.find("&") < 0: return html
return re.sub(
'&(?:#(?:x([0-9A-Fa-f]+)|([0-9]+))|([a-zA-Z0-9]+));',
_decode_html_entity,
html)
def _decode_html_entity(match):
"""
Regex replacer that expects hex digits in group 1, or
decimal digits in group 2, or a named entity in group 3.
"""
hex_digits = match.group(1) # '
' -> unichr(10)
if hex_digits: return unichr(int(hex_digits, 16))
decimal_digits = match.group(2) # '' -> unichr(0x10)
if decimal_digits: return unichr(int(decimal_digits, 10))
name = match.group(3) # name is 'lt' when '<' was matched.
if name:
decoding = (htmlentitydefs.name2codepoint.get(name)
# Treat > like >.
# This is wrong for ≫ and ≪ which HTML5 adopted from MathML.
# If htmlentitydefs included mappings for those entities,
# then this code will magically work.
or htmlentitydefs.name2codepoint.get(name.lower()))
if decoding is not None: return unichr(decoding)
return match.group(0) # Treat "&noSuchEntity;" as "&noSuchEntity;"
This is the easiest solution for this problem -
{% autoescape on %}
{{ body }}
{% endautoescape %}
From this page.
Searching the simplest solution of this question in Django and Python I found you can use builtin theirs functions to escape/unescape html code.
Example
I saved your html code in scraped_html and clean_html:
scraped_html = (
'<img class="size-medium wp-image-113" '
'style="margin-left: 15px;" title="su1" '
'src="http://blah.org/wp-content/uploads/2008/10/su1-300x194.jpg" '
'alt="" width="300" height="194" />'
)
clean_html = (
'<img class="size-medium wp-image-113" style="margin-left: 15px;" '
'title="su1" src="http://blah.org/wp-content/uploads/2008/10/su1-300x194.jpg" '
'alt="" width="300" height="194" />'
)
Django
You need Django >= 1.0
unescape
To unescape your scraped html code you can use django.utils.text.unescape_entities which:
Convert all named and numeric character references to the corresponding unicode characters.
>>> from django.utils.text import unescape_entities
>>> clean_html == unescape_entities(scraped_html)
True
escape
To escape your clean html code you can use django.utils.html.escape which:
Returns the given text with ampersands, quotes and angle brackets encoded for use in HTML.
>>> from django.utils.html import escape
>>> scraped_html == escape(clean_html)
True
Python
You need Python >= 3.4
unescape
To unescape your scraped html code you can use html.unescape which:
Convert all named and numeric character references (e.g. >, >, &x3e;) in the string s to the corresponding unicode characters.
>>> from html import unescape
>>> clean_html == unescape(scraped_html)
True
escape
To escape your clean html code you can use html.escape which:
Convert the characters &, < and > in string s to HTML-safe sequences.
>>> from html import escape
>>> scraped_html == escape(clean_html)
True