Working in Python cgi with form. Empty input error - python

I am trying to work with forms on python and I have 2 problems which I can't decide for a lot of time.
First if I leave the text field empty, it will give me an error. url like this:
http://localhost/cgi-bin/sayHi.py?userName=
I tried a lot of variants like try except, if username in global or local and ect but no result, equivalent in php if (isset(var)). I just want to give a message like 'Fill a form' to user if he left the input empty but pressed button Submit.
Second I want to leave what was printed on input field after submit(like search form). In php it's quite easy to do it but I can't get how to do it python
Here is my test file with it
#!/usr/bin/python
import cgi
print "Content-type: text/html \n\n"
print """
<!DOCTYPE html >
<body>
<form action = "sayHi.py" method = "get">
<p>Your name?</p>
<input type = "text" name = "userName" /> <br>
Red<input type="checkbox" name="color" value="red">
Green<input type="checkbox" name="color" value="green">
<input type = "submit" />
</form>
</body>
</html>
"""
form = cgi.FieldStorage()
userName = form["userName"].value
userName = form.getfirst('userName', 'empty')
userName = cgi.escape(userName)
colors = form.getlist('color')
print "<h1>Hi there, %s!</h1>" % userName
print 'The colors list:'
for color in colors:
print '<p>', cgi.escape(color), '</p>'

On the cgi documentation page are these words:
The FieldStorage instance can be indexed like a Python dictionary. It allows membership testing with the in operator
One way to get what you want is to use the in operator, like so:
form = cgi.FieldStorage()
if "userName" in form:
print "<h1>Hi there, %s!</h1>" % cgi.escape(form["userName"].value)
From the same page:
The value attribute of the instance yields the string value of the field. The getvalue() method returns this string value directly; it also accepts an optional second argument as a default to return if the requested key is not present.
A second solution for you might be:
print "<h1>Hi there, %s!</h1>" % cgi.escape(form.getvalue("userName","Nobody"))

Related

HTML input of type time in flask - how to autocomplete minutes/seconds if missing

I'm using a form with a submit button that is processed through Flask in order to add a new task (a row) in a SQLite database called tasks.
Here is the HTML <div/> container with the respective block content for the Flask part:
<div class="container">
{% block content %}
<form name="task_form" method="post" action="">
{{ form.csrf_token }}
<input type="text" name="task_title" placeholder="Title..."/>
<input type="text" name="task_description" placeholder="Description..."/>
<input type="date" name="task_date_due" placeholder="Due date..."/>
<input type="time" name="task_clock_due" placeholder="Due date (clock)..." step="1"/>
<input type="submit" name="task_submit" value="Add task"/>
</form>
{% endblock %}
</div>
On the Python side I have the following function that processes the GET and POST requests for the specific page:
#app.route('/db', methods=['GET', 'POST'])
def db():
# Create form
form = TaskForm(request.form)
# Initialize DB connection
init_db_conn()
# Handle POST request
if request.method == 'POST':
# Get form data
title = request.form['task_title']
description = request.form['task_description']
date = request.form['task_date_due']
time = request.form['task_clock_due']
if title != '' and description != '' and date != '' and time != '':
str_dtime = date + ' ' + time
db_conn = get_db_conn()
create_task(db, title, description, str_dtime)
elif request.method == 'GET':
pass
db_conn = get_db_conn()
cur = db_conn.cursor()
cur.execute('SELECT * FROM tasks')
tasks = cur.fetchall()
tmp = render_template('db.html', form=form, tasks=tasks)
return tmp
I'm new to Flask, my HTML skills are pretty rusty so I might be missing something but whenever I submit the data from my form through the page, I haven't entered the full time stamp (I use separate date and time inputs to allow using the calendar popup and time formatted field; can be done in a better way but for now it's what it is), I get empty string.
Example:
If I have entered 08:00:-- PM I will get empty string
If I have entered 08:--:-- PM I will get empty string.
What I was expecting is to get an autocompletion of the minutes/seconds as long as the hour has been selected.
Example:
If I have entered 08:00:-- PM I will get 08:00:00 PM (internally depending on the format I have picked on the Python side it will be converted to 20:00:00)
If I have entered 08:--:-- PM I will get 08:00:00 PM (internally depending on the format I have picked on the Python side it will be converted to 20:00:00)
Is there an easy way to fix this behaviour or do I have to create a custom input field? I can probably add a default value or just the current time as value to prevent this but it just goes around the issue. In case the user deletes the default value to enter another one and forgets to fill all the info, the problem will occur again.
I don't think you can get it to auto-complete the missing values in the HTML, but you could always set the default to 00:00:00 for example, then if they only change the hour the seconds and minutes are still at zero. They could still delete the 0's but you could get around this using a validator which won't let them enter an invalid time:
<input type="time" name="task_clock_due" placeholder="Due date (clock)..." step="1", value="00:00:00"/>
<span class="validity"></span>

Django - Read and write from a plain text

I'm trying to read and then write from a plain text in Django.
Basically I want to open a file, get an specific word and then change it for whatever else.
Here's what I have:
def address_L1():
file = open("interfaces.txt","r")
content = file.read()
file.close()
address = re.findall('address\s(.*?)\s',open('interfaces.txt','r').read())
if address:
print address[0]
else:
print 'no Address found!'
return address[0]
Here I'm opening a file and search for the word next to address, which is 192.168.5.5 and works perfect.
def get_interfaces(request):
address = str(address_L1())
if 'address' in request.POST:
write_template(request)#This is for my writing function
return render(request, 'interfaces.html', {'address':address})
Here I'm passing to template what's in address I mean, 192.168.5.5 will be shown in template.
<form method="post" action="">{% csrf_token %}
<label for="your_name">Address: </label>
<input id="your_name" type="text" name="address" value="{{ address }}">
<br>
<input type="submit" class="btn btn-success btn-xs" value="Guardar Cambios">
</form>
Here is my html were I'm displaying my variable, There's an input Address that will show my 192.168.5.5 or whatever is in address variable.
Everything works ok until now.
Now I'm trying to write to my plain text.
def write_template(request):
if request.method == 'POST':
get_address = address_L1()
change_address_L1 = request.GET.get("address", None)#Doing something with my input field in template
filedata= None
with open('interfaces.txt', 'r') as f:
filedata = f.readlines()
filedata=filedata.replace(get_address , change_address_L1)
with open('interfaces.txt', 'wb') as f:
f.writelines(filedata)
return render(request, 'interfaces.html')
Here basically what I want to do is get what's in my input address and replace for whatever I enter, I mean when I run my code I ll see my input with 192.168.5.5 I want to delete that value and enter 192.168.0.0 and change my value. When I try so I get this error:
'list' object has no attribute 'replace'
How can I solve this? how can I successful write in my plain text properly?
What am I doing wrong? thanks in advance!!
As the error says, filedata is a list. That's because f.readlines() gives you a list, where each element is a line in the file.
If you want the whole thing as a single string, do f.read() instead.

Flask request.form["name"] returns just one token

Hello i dont know maybe it is a rookie question problem is this i have a button inside the html
<button class="btn" id="name" name="name" type="submit" value={{form.title}}>Button</button>
and i am trying to take the value from flask as seen below
if 'name' in request.form:
title = request.form["name"]
Problem is this request.form["name"] returns just one token .for example if the value is "John Doe" it just returns "John" and i need the full value
i tried
json_data = request.get_json(force=True)
title = json_data["name"]
but that didnt work either
Edit :As i debug the code more i see that request.form["name"] takes correct value but
`value={{form.title}}`
gives the value first token of the title
Enclose value with "{{form.title}}". You should get whole value as a string.

how to send response to html using cgi python script

I am trying to design and implement a basic calculator in HTML and Python(using CGI). Below given is a static HTML web page and it is being redirected to a python script (calci.py) where, I am able to calculate the sum but unable to append the resultant to the 'output' textbox.
calculator.html
<html>
<head>
<title>Calculator</title>
</head>
<body>
<form action="python_scripts/calci.py" method="post">
Input 1 : <input type="text" name="input1"/><br>
Input 2 : <input type="text" name="input2"/><br>
<input type="submit" value="+" title="add" /><br>
output : <input type="text" name="output"/><br>
</form>
</body>
</html>
calci.py
import cgi
form = cgi.FieldStorage()
input1 = form.getvalue('input1')
input2 = form.getvalue('input2')
output = str(int(input1)+int(input2))
#how to return the response to the html
#and append it to the textbox
Thanks
This is not the way Web applications work - not hat simply, at least.
If you want to rely only on the browser, and plain HTML for your application, each request has to send the whole html page as a string. You have to use Python's string formatting capabilities to put the resulting number in the correct place in the HTML form.
This way of working is typical of "Web 1.0" applications (as opposed to the "Web 2.0" term used about ten years ago).
Modern web applications use logic that runs on the client side, in Javascript code, to make an HTTP request to retrieve only the needed data - and them, this client-side logic would place your result in the proper place in the page, without reloading the page. This is what isgenerally known as "ajax". It is not that complex, but the html + javascript side of the application become much more complex.
I think one should really understand the "Web 1.0" way before doing it the "Ajax way". in your case, let's suppose your HTML containing the calculator form is in a file called "calc.html". Inside it, where the result should lie, put a markup that can be understood by Python's built-in native string formatting methods, like {result} -
<html>
<body>
...
calculator body
...
Answer: <input type="text" readonly="true" value={result} />
</body>
</html>
And rewrite your code like:
import cgi
form = cgi.FieldStorage()
input1 = form.getvalue('input1')
input2 = form.getvalue('input2')
result = int(input1)+int(input2)
html = open("calc.html".read())
header = "Content-Type: text/html; charset=UTF-8\n\n"
output = header + html.format(result=result)
print (output)
The CGI way is outdated, but is nice for learning: it relies on your whole program being run, and whatever it prints to the standard output to be redirected to the HTTP request as a response. That includes the HTTP Headers, which are included, in a minimal form, above.
(I will leave the complete implementation of a way for the raw '{result}' string not to show up in the inital calculator form as an exercise from where you are 0- the path is to get the initial calculator html template through a CGI script as well, instead of statically, (maybe the same) as well - and just populate "result" with "0" or an empty string)
you can transfer response with the help of java script.
use under print("window.location=url")

python mechanize handle two parameters with same name

I'm logging into a page where they oddly have a form input called login_email and two form inputs called login_password. I need to set the value of both but the straightforward call form['login_password'] throws an error:
File "/Library/Python/2.7/site-packages/mechanize/_form.py", line 3101, in find_control
return self._find_control(name, type, kind, id, label, predicate, nr)
File "/Library/Python/2.7/site-packages/mechanize/_form.py", line 3183, in _find_control
raise AmbiguityError("more than one control matching "+description)
mechanize._form.AmbiguityError: more than one control matching name 'login_password'
I just need to find a way to submit form['login_password'] = "Password" and form['login_password'] = "monkeybutler" at the same time. I'm not seeing a variable in the Browser object to change the POST data params.
Any suggestions?
Here's what I tried without success:
# Select the first (index zero) form
br.select_form(nr=0)
# Let's search
br.form['login_email'] = 'mommajane#gmail.com'
#my_fields = br.form.fields.select
#my_fields[0].login_password = "Password"
#my_fields[1].login_password = "123qwerty"
br.form['login_password']= ['Password','123qwerty']
br.submit()
If you are facing two fields with the same name, id and so on, you must use a little workaround, altough its not very clean
First I have defined a simple html file for that example since I did not know the URL you used:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
"http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<title>foo</title>
</head>
<body>
<h1>bar</h1>
<form action="input_text.htm">
<p>name:<br><input name="name" type="text" size="30" maxlength="30"></p>
<p>sec_name:<br><input name="sec_name" type="text" size="30" maxlength="40"></p>
<p>sec_name:<br><input name="sec_name" type="text" size="30" maxlength="40"></p>
</form>
</body>
</html>
Afterwards I was able to insert values into those fields quick and dirty by using this python code:
>>> import mechanize
>>> browser = mechanize.Browser()
>>> browser.open("file:///home/foo/index.html")
<response_seek_wrapper at 0x229a7e8 whose wrapped ...
>>> browser.select_form(nr=0)
>>> name = 'foo'
>>> for control in browser.form.controls:
... if control.name == 'sec_name':
... control.value = name
... name = 'bar'
...
>>> for control in browser.form.controls:
... print control
...
<TextControl(name=)>
<TextControl(sec_name=foo)>
<TextControl(sec_name=bar)>
>>>
It`s not nice but it works. Hope that helped.

Categories