How to write multi line input in Django - django

I am making a very basic BBS system (like blog) in Django.
I've made a form where user can type in their content which I call 'body' and I declare it as
folowing in the forms.py:
body = forms.CharField(widget= forms.Textarea, label="body",required=True)
and in the models.py,
body = models.TextField()
I somehow can't seem to be able to write multi line texts...
To sum it up,
I can write multiple lines into my form like:
Hello this is test
This is sample test2
333333
But When I submit it,
I only see
Hello this is test This is sample test2 333333

The error happened when display it.
Textarea uses cr\lf to break lines. That is how it would
be saved into db. But html will ignore cr\lf you need to replace cr\lf with <br> or <p>
A template tag linebreaks can help you, when you display it.
{{ value|linebreaks }}

Related

Trying to render a django form field as a variable in a script tag in an html template, but the javascript isn't working

My issue is simple enough--I am trying to render a form field from a django form into a javascript variable, defined within a <script> tag, within a django template.
When I output a CharField, there's no problem. But when I try to render a ChoiceField, the resulting output breaks the html, and prevents the script tag from correctly parsing my variable.
To demonstrate my setup, I have a form defined in forms.py, exactly like this example form:
from django import forms
form = TestForm(forms.Form):
testfield = forms.ChoiceField(initial="increase_rate",
choices=[
("a", "option a"),
("b", "option b"),
("c", "option c"),
("d", "option d")
])
I am instantiating the form in views.py, and passing it into a django template to be rendered.
from django.shortcuts import render
from .forms import TestForm
[...]
#require_http_methods(["GET"])
def webpage(request):
form = TestForm()
return render(request, 'index.html', {"form":form})
Then, finally, in my template, I have something like the following:
[...]
<script>
window.testfield = '{{ form.testfield }}'
</script>
[...]
Up until this point, everything works perfectly. No trouble at all. But when I render the field into the template, and inspect it in my browser, I get the following:
<script>
window.testfield = '<select name="trigger" id="id_trigger">
<option value="a" selected>option a</option>
<option value="b">option b</option>
<option value="c">option c</option>
<option value="d">option d</option>
</select>'
</script>
This output breaks the html, and prevents the script tag from being interpreted as a variable like I want. This is a major problem, because I want to reuse these programmatically elsewhere on the page.
I tried the following:
<script>
window.testfield = '{{ form.testfield|escape }}'
</script>
But was still unsuccessful. Any help anyone can give would be greatly appreciated!
I am actively researching a solution. My current guess is that the output needs to be escaped somehow that I don't understand. I figure the template tags and filters have my answer, I just have to find it. Will post an update once a solution is found.
Use <script type="text/template"></script>.
This way the browser knows it's just text and will ignore it.
So, I figured it out. Turns out that the issue was that the presence of white space, line breaks, and unescaped double quotes (") were breaking the tag when it was parsed at HTML.
So I ended up using the following:
{% spaceless %}
<script>
window.testfield = '{{ form.testfield|addslashes }}'
</script>
{% endspaceless %}
And it worked, allowing me to store the string representation of the django form field in a javascript variable. As per the documentation, the {% spaceless %} "Removes whitespace between HTML tags. This includes tab characters and newlines." [1]. As for the filter |addslashes, it "Adds slashes before quotes. Useful for escaping strings in CSV" [2]. In my case, both solutions were needed, as without either of them, the script tag broke.
As for why the |escape filter didn't work on it's own, I'm not sure. Reading the documentation, it seems like it probably should have. The following is what the |escape filter actually does [3]:
Escapes a string’s HTML. Specifically, it makes these replacements:
< is converted to <
> is converted to >
' (single quote) is converted to '
" (double quote) is converted to "
& is converted to &
I can only guess why this didn't work. I figure it's because it didn't do anything about the white space. But I shouldn't speculate. I welcome any explanations you might have. As ever, understanding the way the machine thinks is better than any single, specific solution. Thanks.
[1] - https://docs.djangoproject.com/en/dev/ref/templates/builtins/#spaceless
[2] - https://docs.djangoproject.com/en/dev/ref/templates/builtins/#addslashes
[3] - https://docs.djangoproject.com/en/dev/ref/templates/builtins/#escape

How to use linebreak in Django templates

Hi I am new to python Django.
I want new line in specific places, So I tried
def abc(request):
text = "This is\n a good example"
return render(request, 'test.html', {'text' : text})
In HTML part
Hello {{ text|linebreaks }}
And this is working perfectly fine with output
Hello This is
a good example
Here is my question
I store some 400 - 800 words in my database which has approximately 4-5 paragraph.
I want to new line here.
So, I store data like "This is\n a good example" in my database.
And simply call it in django template(Html side)
but it prints
Hello This is\n a good example
In here why line break is not working?
My HTML true code
{% for essay in eassays %}
{{ essay.description|linebreaks }}
{% endfor %}
I have changed name. Also, I am loading 100 such data.
Any possible solution or other logic!
Thankyou!
So, I store data like "This is\n a good example" in my database.
You likely stored '\\n' in the database, so a backslash, followed by an n. Not a new line chacter '\n' [wiki]. Note that if you write \n in a form element, then it will be escaped and thus stored accordingly.
It might be better to use a <textarea> in your form elements to let users use new lines (by pressing Enter).
You can try to fix the damage by substituting the strings, with:
from django.db.models import Replace, Value
Essay.objects.update(
description=Replace('description', Value('\\n'), Value('\n'))
)
and thus update your database such that '\\n' is now replaced by '\n'.

Submit Button Confusion and Request being sent Twice (Using Flask)

I'm pretty much trying to create a web app that takes 2 svn urls and does something with them.
The code for my form is simple, I'm also using WTForms
class SVN_Path(Form):
svn_url=StringField('SVN_Path',[validators.URL()])
I'm trying to create 2 forms with 2 submit buttons that submit the 2 urls individually so my test3.html looks like this:
<form action="" method="post" name="SVNPath1">
{{form1.hidden_tag()}}
<p>
SVN Directory:
{{form1.svn_url(size=50)}}
<input type="submit" value="Update">
<br>
{% for error in form1.svn_url.errors %}
<span style="color: red;">[{{error}}]</span>
{% endfor %}
</p>
</form>
<form action="" method="post" name="SVNPath2">
{{form2.hidden_tag()}}
<p>
SVN Directory:
{{form2.svn_url(size=50)}}
<input type="submit" value="Update">
<br>
{% for error in form2.svn_url.errors %}
<span style="color: red;">[{{error}}]</span>
{% endfor %}
</p>
</form>
MY FIRST QUESTION is how do I know which submit button was clicked so I can run the proper function on the corresponding svn url. I have tried doing something like
if request.form1['submit'] == 'Update':
if request.form2['submit'] == 'Update':
but that does not work at all. I'm new to web dev in general and flask so a detailed explanation would be helpful.
SECONDLY, since submits weren't working properly I also tried an alternative to keep my work moving so in my .py file I have
#app.route('/test3', methods=['GET','POST'])
def test3():
basepath=createDir()
form1=SVN_Path()
form2=SVN_Path()
if request.method=="POST":
if form1.validate_on_submit():
svn_url = form1.svn_url.data
prev_pdf=PDF_List(svn_url,basepath,'prev') #some function
if form2.validate_on_submit():
svn_url2 = form2.svn_url.data
new_pdf=PDF_List(svn_url,basepath,'new') #some function
return render_template('test3.html', form1=form1, form2=form2)
CreateDir is a function that creates a directory in the local /tmp using timestamps of the local time.
Whenever I go the webpage it creates a directory, lets call it dir1, since its calling CreateDir. Thats what I want, but when I click submit on the form it creates another directory dir2 in the tmp folder which is NOT what I want since I want everything to being the same dir1 directory.
In addition when I put a url in one of the forms and click submit, it automatically puts it the same value in the 2nd form as well.
Sorry if this is really long and possibly confusing, but any help is appreciated.
:) Let's see if we can clarify this a little.
To your first question:
As #dim suggested in his comment, You have a few options:
You can submit your form to separate unique urls. That way you know which form was submitted
You can create two similar but different Form classes (the fields will need different names like prev_svn_url and cur_svn_url). This way in your view function, you instantiate two different forms and you'll know which form was submitted based on form.validate_on_submit()
The third option would be to add a name attribute to your submit button and then change the value attributes to something like 'Update Previous' and 'Update Current'. This way in your view function you can check the value of request.data[<submit button name>] to determine if 'Update Previous' was pressed or 'Update Current'.
To your second question:
Multiple directories are being created because you're calling createDir() each time the page is loaded to show the forms and when the forms get posted. In order to create just once, you'll need some kind of logic to determine that the directory was not previously created before calling createDir()
In addition: Since both forms are from the same SVN_Path class, they read post data exactly the same way, that's why whatever you type in form 1 appears in form 2.
Now for my 2 cents:
I assume you're trying to write some kind of application that takes two SVN urls as input, creates a folder and does something with those URLs in that folder. If this is the case, the way you are currently going about it is inefficient and won't work well. You can achieve this with just one form class having 2 svn_url fields (with different names of course) and then handling all of that in one post.
EDIT: The job of the submit button is to tell the browser that you're ready to send the data on the form to the server. In this case you should only need one submit button (SubmitFiled => when rendered). Clicking that one submit button will send data from both input fields to your view function.
Your form should look something like:
class SVN_Path(Form):
prev_svn_url=StringField('Previous SVN_Path',[validators.URL()])
new_svn_url=StringField('New SVN_Path',[validators.URL()])
and your view function:
def test():
form = SVN_Path()
if request.method == "POST":
if form.validate_on_submit():
basepath = createDir() # Only create dir when everything validates
prev_svn_url = form.prev_svn_url.data
new_svn_url = form.new_svn_url.data
prev_pdf = PDF_List(prev_svn_url, basepath, 'prev')
new_pdf = PDF_List(new_svn_url, basepath, 'new')
...
return render_template('test3.html', form1=form1, form2=form2)

adding line breaks and headers in django's admin interface

EDIT: If you are going to give a downvote, at least explain why -.-
Also, read comments if my post is still unclear. I tried to explain it a bit more in the comments but if it is still unclear about what I'm saying, let me know and I will take printscreens and explain using images.
I have created a model like so
class Post(models.Model):
title_of_post = models.CharField(max_length=100)
actual_post = models.TextField()
and I put this model in the admin interface and enabled the admin interface. Now, when I go to 127.0.0.1/admin/ and sign in, I can add this model. The posts created in the Post model can be seen on the homepage (127.0.0.1) so say my "title_of_post" is "title" and my "actual_post" is "the actual post", if I go to 127.0.0.1 I can see both the title and actual post on the homepage. The problem is, when I am in the admin interface and in the actual_post text box / TextField section, suppose I write this.
Something.
else
It would not recognize that I pushed the enter key after the period. I tried
Something. <br>
else
but that also didn't work. It does not go on a new line after the period. Is there any way to go to the next line when inputting information from the text box / TextField in the django admin interface? Is there any way to put headers from the admin interface, not from the template? Essentially, I want to be able to create this html from the admin interface.
<h1>Something.</h1> <br>
else
in order to show html inside a property, you need to place like this in your template:
{{ post.actual_post|safe }}
the safe template filter its good for not escaping html tags inside your template.
And this will print as:
Something
else
intead of:
Something <br /> else

Django textarea widget <p>

In django admin I am using the textarea widget.
When I save data, it is saved inside a <p></p> tag.
I dont want this - any solutions, I just want to get the data out without being wrapped in a <p>.
Any suggestions?
I don't know how to save it without html coding, but maybe it is enough to you to display without that . Just put a |safe in the template after the variable name, example:
{{ variable|safe }}
http://docs.djangoproject.com/en/dev/ref/templates/builtins/?from=olddocs