I want to input the content of a text area and want to output it on another page but seems like there is nothing like multiline-text area in Flask. When I do the following
content = request.form['content']
it returns a string with line breaks as '\n' but when I try to output that content with replacing \n with or
, it doesn't seem to work.
So I thought I can store the multiline content in the form of a list.
So is there db column for the list, something like
content = db.Column(db.list(String))
or is there any other alternative.
Just to clarify, to the computer these 2 text examples are exactly equivalent:
myString = """Hello
World
"""
myString = "Hello\nWorld"
We can confirm this by checking the repr value for both versions
repr(myString)
# 'Hello\nWorld'
Whether or not the formatting is performed in a "friendly way" where the newlines are rendered as such, is entirely dependent on how you choose to display them. In HTML, newlines are denoted with a <br> tag, so one option would be to store the actual HTML-formatted string in your database after inserting them. However, this may pose a security hazard by either allowing malicious links to be made clickable, or by allowing Javascript snippets to be executed when rendering the page.
The simplest solution would be to use the HTML <pre> tag, which tells it that you have already handled the formatting ahead-of-time. Using the same myString value as before, we can display it nicely with
<pre>
{{ myString }}
<pre>
using the Jinja2 syntax, as long as we pass this string to the render_template function, for example
#app.route("/")
def index():
myString = "Hello\nWorld"
return render_template("index.html", myString=myString)
Related
Lets say i have the following script in a html template of a flask application
<script type="text/javascript">
console.log('{{ url_for('root', arg1='hello', arg2='world') }}')
<script>
and i have a flask endpoint root()
#app.route('/', methods=['GET'])
def root():
print(print(request.args))
when i call my page the internal script is rendered to
console.log('/api/art_structure?arg2=world&arg1=hello')
When I call this url my request.args dict is:
ImmutableMultiDict([('amp;arg1', 'hello'), ('arg2', 'world')])
Which is not correct since the key of arg1 is wrong.
Any clues how I can prevent jinja2 from converting & to &?
The ampersand
The correct URL is /api/art_structure?arg2=world&arg1=hello.
The problem with the above URL is that ampersand (&) cannot be written directly in HTML, because the ampersand is used for entity references. For example, to write < character in HTML, which is not a tag start, one can write <. Because of that, to write &, one should escape it, i.e. write it as &.
Jinja2 templating engine does that by default. So, you can dump the contents of any string variable even if it contains special characters and they will be correctly escaped, e.g. & will become & as in your case.
How does that work?
So, if you actually put this in your jinja template: link, it would write the following HTML code: link, and if you clicked on the link in the browser, it would correctly replace & with & and open /api/art_structure?arg2=world&arg1=hello.
(note, however, that writing plain & as it is into HTML may sometimes also work, because browsers may guess how to fix the error)
So why does it not simply work in this case?
Because you are generating JavaScript and not HTML (you are generating code within <script> and </script>. In JavaScript, & is fine and should not be escaped, so you are free to write it as it is. To tell Jinja that you do not want it to escape the string, you can use the safe filter, i.e. {{ url_for('root', arg1='hello', arg2='world') | safe}}.
Try using safe
Ex:
console.log("{{ url_for('root', arg1='hello', arg2='world') | safe}}")
MoreInfo
I have code like this `
celldata=""
count=0
for tableData in y:
count = count+1
strcount=str(count)
celldata += strcount + ")" + tableData .text + "\n"
return celldata
`
I am returning the value to be used in flask, the issue is I want each for loop row in a new line but after trying \n, and in the flask web app I am getting celldata in one single line with one space each between each output line of the for loop.
Here is my current output for celldata in flask web
1)xxxx 2)yyyy
I want the flask web url to return
1)xxxx
2)yyyy
You're presumably returning HTML, and viewing that HTML in a browser.
In HTML, all runs of whitespace are equivalent—there's no difference between '\n' and ' '. The browser should convert them all to single spaces, and then decide how to flow the results nicely.
So, you're going to have to learn some basic HTML. But here are a few quick hints to get you started:
<p>one paragraph</p> <p>another paragraph</p> defines two separate paragraphs.
<p>one paragraph<br />with a line break in the middle</p> defines a paragraph with a line break in the middle.
<table><tr><td>row one</td></tr> <tr><td>row two</td></tr></table> defines a table of two rows (and one column).
The last one is the most complicated, but given that you've got things named tableData and celldata, I suspect it may be what you actually want here.
HTML itself only specifies "structure", not layout. It's up to the browser to decide what "two paragraphs" or "a line break" or "two rows" actually means in terms of actual pixels. If you want finer control, you need to learn CSS as well as HTML, which lets you specify explicit styles for these elements.
If you are trying to format this as HTML, I would suggest you add <br /> also to the returned text:
celldata = []
for count, tableData in enumerate(y, start=1):
celldata.append('{}) {}<br/>'.format(count, tableData.text))
return '\n'.join(celldata)
This first builds a list of entries with the correct numbering, and then joins each line together with a newline. The newline is purely cosmetic and will only effect how the HTML appears when viewed as source. It is the <br /> which will ensure each entry appears on a different line.
enumerate() is used to automatically count your entries for you.
I can do this:
>>>some_string = 'this is {0} a {1}'
>>>print(some_string.format('totally', 'string'))
>>>this is totally a string
What I want to do is kind of form a html list like that. Is there any way I can do something like...
my_list_items = ['<li>One</li>', '<li>Two</li>', '<li>Three</li>']
my_list = """<ol>
{list}
</ol>"""
print(my_list).format(list=my_list_items)
and get
<ol>
<li>One</li>
<li>Two</li>
<li>Three</li>
</ol>
The rationale being; I'm writing a small cgi app for my school. I would rather be able to keep template html pages and insert the right values when the cgi script calls the page in the manner below, than have a billion print calls in the cgi file itself, as that's scrappy and difficult to debug.
group = '11bg/En1'
AP = 'AP1'
def process_input(group, AP):
"""
Any processing necessary, followed by calling the template and inserting the values
"""
return read_file('pages/group_page.html').format(group=group, AP=AP)
print(process_input(group, AP))
I instantly realised I was being an idiot. Just turn the list into a string of course.
I have a web app that reads from the Tumblr API and reformats the way that "reblog chains" are formatted.
With Tumblr, commentary for a post is stored as HTML blockquotes. As users respond to the commentary above, another level gets added to the blockquote chain, eventually resulting in many nested reblog chains.
Here is an example of how a "reblog chain" looks in plain HTML:
<p><a class="tumblr_blog" href="http://chainsaw-police.tumblr.com/post/96158438802/example-tumblr-post">chainsaw-police</a>:</p><blockquote>
<p><a class="tumblr_blog" href="http://example-blog-domain.tumblr.com/post/96158384215/example-tumblr-post">example-blog-domain</a>:</p><blockquote>
<p>Here is an example of a Tumblr post.</p> <p>It can have multiple <p> elements sometimes. It may only have one, though, at other times.</p>
</blockquote>
<p>This is an example of a user “reblogging” a post. As you can see, the previous comment is stored above as a <blockquote>.</p>
</blockquote>
<p>This is another reblog. As you can see, all of the previous comments are stored as blockquotes, with earlier ones being residing deeper in the nest of blockquotes.</p>
And this is what it looks like when rendered.
I want to be able to reformat the reblog chain so that it looks more like this:
example-blog-domain:
Here is an example of a Tumblr post.
It can have multiple <p> elements sometimes. It may only have one, though, at other times.
chainsaw-police:
This is an example of a user “reblogging” a post. As you can see, the previous comment is stored above as a <blockquote>.
example-blog-domain:
This is another reblog. As you can see, all of the previous comments are stored as blockquotes, with earlier ones being residing deeper in the nest of blockquotes.
I know, It's an incredibly confusing structure, hence why I'm trying to write something to make it more readable.
Is there any way to interpret the HTML and split the reblogs up into individual "comments"? For example, having an array or dict that has the username and the commentary would be more than enough. However, after messing with lxml and BeautifulSoup for months, I'm at my wits' end.
If there was even a way to do it in CSS, which I highly doubt, that would be fine.
Thanks in advance, everyone!
I guess CSS does not have a such functionality.
You need parse to a structure by lxml, ... and render it. It is easier way. You can also create a filter using regexp that does not pass wrong items of html code.
reddit user /u/joyeusenoelle has answered my question over at /r/LearnPython using a tonne of convoluted regexes that end up looking more like a voodoo magic spell than a text manipulation script.
Lots of regexes later, I think I've solved this for an
arbitrarily-deep comment chain.
import re
with open("tcomment.txt","r") as tf:
text = ""
for line in tf:
text += line
tf.close()
text = text.replace("\n","")
text = text.replace(">",">\n")
text = text.replace("<","\n<")
text = re.sub("</p>\s*<p>","<br><br>", text)
text = text.replace("<p>\n", "")
text = text.replace("</p>\n","\n")
text = re.sub("<[/]{0,1}blockquote>","<chunk>",text)
text = re.sub("<a class=\"tumblr_blog\"[^>]+?>","<chunk>",text)
text = text.replace("</a>","")
text = re.sub("\n+","", text)
text = re.sub("\s{2,}"," ", text)
text = re.sub("<chunk>\s*<chunk>","<chunk>",text)
bits = text.split("<chunk>")
bits[0] = "Latest:"
comments = []
for i in range(len(bits)):
temp = ""
j = 0 - (i+1)
if (len(bits)-i) > i:
temp = "<b>" + bits[i] + "</b> " + bits[j]
comments.append(temp)
comments.reverse()
for comment in comments:
print("<p>%s</p>" % (comment))
print()
The line bits[0] = "Latest:" can be changed to whatever you want the
most recent comment to display, and you'll probably want to change how
the text comes into the script.
For the text you provided, this gives me:
<p><b>example-blog-domain:</b> Here is an example of a Tumblr post.<br><br>It can have multiple <p> elements sometimes. It may
only have one, though, at other times.
<p><b>chainsaw-police:</b> This is an example of a user "reblogging" a post. As you can see, the previous comment is stored
above as a <blockquote>.
<p><b>Latest:</b> This is another reblog. As you can see, all of the previous comments are stored as blockquotes, with earlier ones
being residing deeper in the nest of blockquotes.
e: Some thoughts: this is in Python 3, but everything but the print
statements should work in Python 2, I think. I used text.split()
whenever possible because direct string manipulation is typically
faster than regular expressions are, but that may not be appropriate
here. And finally, it's possible that I'm making more work for myself
than I need to in the substitutions section, but at this point I've
looked at the code too long to figure out if it could be slimmed down.
Ajax output is
\u001b[1mGetting NS records for yahoo.com\u001b[0m\n\n\n\nIp Address\tServer Name\n\n----------\t-----------\n\n68.180.131.16\tns1.yahoo.com\n\n98.138.11.157\tns4.yahoo.com\n\n203.84.221.53\tns3.yahoo.com\n\n68.142.255.16\tns2.yahoo.com\n\n119.160.247.124\tns5.yahoo.com\n\n202.43.223.170\tns6.yahoo.com\n\n\n\nZone Transfer not enabled\n\n
When I append into html it looks like
[1mGetting NS records for yahoo.com[0m Ip Address Server Name ---------- ----------- 68.180.131.16 ns1.yahoo.com 98.138.11.157 ns4.yahoo.com 203.84.221.53 ns3.yahoo.com 68.142.255.16 ns2.yahoo.com 119.160.247.124 ns5.yahoo.com 202.43.223.170 ns6.yahoo.com Zone Transfer not enabled
"\t" "\n" doesnt seem to be working.
Please help.
HTML does not render tabs and line breaks. For a line break in HTML, use <br>. There are no tabs in HTML, but if you just want to insert some spaces, you can use for each blank space (of course, you can always insert a single space, but multiple spaces will get collapsed unless you explicitly use ).
Another option is to wrap your text in a <pre></pre> element to display the text exactly as you have it formatted in the HTML source (you may need to play with the CSS if you don't like the default formatting of <pre> content). web2py also includes a CODE() helper, which uses <pre> but also enables line numbers and syntax highlighting.