Web Form with Web.py on PythonAnywhere - python

I'm trying to make a simple web script using the PythonAnywhere.com's web.py platform.
My intention is to create a simples Form which gets the data of textboxes and is able to work with them just like we do with PHP and so.
This is my main script:
import web
from web import form
import MySQLdb
render = web.template.render('/home/user/templates/')
conn = MySQLdb.connect("mysql.server","user","*********","userdb")
curs = conn.cursor()
curs.execute('''create table if not exists Dados (
id int not null auto_increment primary key,
nome varchar(200),
item1 varchar(50),
item2 varchar(50),
item3 varchar(50),
item4 varchar(50),
item5 varchar(50));
''')
urls = (
'/', 'index'
)
formula = form.Form(
form.Textbox('Nome', id='nome'),
form.Textbox('Item 1', id='it1'),
form.Textbox('Item 2', id='it2'),
form.Textbox('Item 3', id='it3'),
form.Textbox('Item 4', id='it4'),
form.Textbox('Item 5', id='it5'),
)
class index:
def GET(self):
form = formula()
return render.formtest(form)
def POST(self):
form = formula()
return render.finaliza(form['Nome'].value)
# comment out these two lines if you want to use another framework
app = web.application(urls, globals())
application = app.wsgifunc()
Then I have two templates in HTML, this one stores the Form:
$def with (form)
<form name="main" method="post">
$:form.render()
<input type="submit" name="send" id="envia" value="Ok" /> </form>
And this should give the result after the POST:
$def with (nome)
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Untitled Document</title>
</head>
<body>
Congratulations $:nome !
</body>
</html>
Everything works fine until a press the Ok button.
It shows the right template but doesn't show the $nome variable.
You can check this behavior on this link:
http://jonathan_hepp.pythonanywhere.com/
I'm beginning on web.py and PythonAnywhere so there must be something I'm doing wrong but I can't find it out.
Could you please help me out?
Thanks.
EDIT:
I've just find out now that if I pass the textbox value as a string the result is different.
The result page says "Congratulations None!"
That makes me think that actually the POST is not recieving the value I'm typing in the textbox. So the code seems to be ok but somehow I didn't make it right so it cannot reach the value in the form's input.
Still not working.
SOLVED:
Ok. I realized that the form.Form() option doesn't really create and html form output.
Actually when you look at the source code of the formtest page you see that what I supposed was the form appears as a simple .
So I just made the form into the formtest template directly in html an now it works pretty well.
Just a dumb mistake, but if somebody else comes throught it, just do the same.
Thank you all.

It seems like the variable in the finaliza template should actually be "Nome". So:
Congratulations $:Nome !
Might do the trick. Remember to restart your web app on the Web tab of PythonAnywhere after making changes or you won't see them.

I am using the same web.py framework. when I try to access it via localhost and URL after is /templates/tutorial.html
then I can see "send" button but with these $ signs
$def with (form, text)
$:form.render()
$text
Here is tutorial.html
$def with (form, text)
<head>
<title>Python and AJAX tutorial for beginners with webpy and jQuery</title>
<link rel="stylesheet" type="text/css" href="/static/tutorial.css" />
<script type="text/javascript" src="/static/jquery.js"></script>
<script type="text/javascript">
jQuery(document).ready(function() {
jQuery(".button").click(function() {
var input_string = $$("input#textfield").val();
jQuery.ajax({
type: "POST",
data: {textfield : input_string},
success: function(data) {
jQuery('#foo').html(data).hide().fadeIn(1500);
},
});
return false;
});
});
</script>
</head>
<body>
<br>
<form class="form" method="post">
$:form.render()
<input class="button" type="submit" value="send"/>
</form>
<br><br>
<span id="foo">$text</span>
</body>
How I can get the values of these variables ?
$def with (form, text)
$:form.render()
$text

Related

posting input data from html to python script with ajax

I am wanting to POST a user inputted data in an html file to a Python script with AJAX and have the Python script return it so that it shows up in a specific div in the html file.
HTML
<!DOCTYPE HTML>
<html>
<head>
<title>AJAX Test</title>
<script src="http://code.jquery.com/jquery-3.3.1.js"></script>
<script>
function test()
{
var message = $('input[name=message]').val();
$.ajax({
url: "/cgi-bin/hello.py",
type: "POST",
data: {"text" : message},
success: function(response){
$("#div").html(response);
}
});
};
</script>
</head>
<body>
<form>
Enter Message: <input type="text" name="message">
<input type="submit" value="submit" onclick="test()">
</form>
<div id="div">Default Message</div>
</body>
</html>
Python
#!/home/user/virtualenv/test/3.5/bin/python
import cgi, cgitb
cgitb.enable()
data = cgi.FieldStorage()
print "Content-Type: text/html\n"
print data
When I type a message into the input box and press the submit button, nothing happens. I am new to this so I feel like I am probably not understanding how this works. Any help would be appreciated!
Edit: Console is showing Uncaught TypeError: $.ajax is not a function
Edit 2: The first problem was due to using the slim version of jquery. After fixing that, nothing is happening on the page when I input and click submit.
The problem was that the form was submitting when I clicked the button. The solution was to change the input type to <button value="Submit" onclick="test()">.
The next problem was that python was returning FieldStorage(None, None, [MiniFieldStorage('text', 'blahblah')]). The solution was to access the value by using print (data["text"].value)

Django new session for each browser tab

I have a problem with Django session and i have no idea how to solve it. Basically i store some data in the session dictionary in one view function, and calculate some thing in a second function using the values from the first view. Now if someone opens up two tabs, fills in the data in one and submits it, fills the second tab and submits it, the session dictionary will be the same for both tabs. I hope i phrase myself right.
Simple explanation:
def a(request):
request.session["q"] = request.POST.get('q')
def b(request):
while True:
print(request.session["q"])
So lest assume function a is rendering an index page, and getting a value from there. On a button push in this index page function b is called. Now if i open two tabs, input 1 in to the index page and submit i ll see a lot of 1 in the terminal. Now i open up another tab, input 2, submit, the printing will change.
What i would like to do is to keep separate sessions (separate information to come in and go out) from my server to the user on different tabs of a browser.
I am sorry if i phrase myself wrong, this is the first time i am trying to work with web servers.
EDIT:
As i mentioned in the comments the answer is currently not working, and i think it is just a syntax error, however i dont know where i gone wrong.
My template:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2//EN">
{% load staticfiles %}
<HTML>
<HEAD>
<LINK rel="stylesheet" type="text/css" href="{% static 'style7.css' %}"/>
<link rel="shortcut icon" type="image/png" href="{% static 'favicon.ico' %}"/>
<script src="http://cdn.bokeh.org/bokeh/release/bokeh-0.12.13.min.js"></script>
<link rel="stylesheet" href="http://cdn.bokeh.org/bokeh/release/bokeh-0.12.13.min.css">
<script type="application/javascript">function makeid() {
var text = "";
var possible = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
for (var i = 0; i < 5; i++)
text += possible.charAt(Math.floor(Math.random() * possible.length));
return text;
}
document.getElementById("session").value = makeid();</script>
</HEAD>
<BODY>
....
....
<form action="{% url 'raw' %}" method="post" style="float: left;">{% csrf_token %}<input type="hidden" name="session" id="session"><input type="submit" value="Download text"/></form>
....
My view function:
def plot(request):
print(request.POST.get("session"))
....
However in the terminal see nothing printed, thus i think the variable is an empty string.
i don't know what app you are making but lets say i want to save the username as session.
1. we need to create a script that create a random code and assign it to and hidden input
function makeid() {
var text = "";
var possible = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
for (var i = 0; i < 5; i++)
text += possible.charAt(Math.floor(Math.random() * possible.length));
return text;
}
window.onload = function() {
document.getElementById("session").value = makeid();
}
2. in the form that you take the data from user add a new hidden input
<form>
...
<input type="hidden" name="session" id="session">
</form>
3. now when the user submit the form to a view we need to do this in the view
def someview(request):
session_id = request.GET.get('session')
username = request.GET.get('username') # or any data...
request.session['username_%s' % session_id] = username
# now lets say you want to redirect the user to the next page...
# you have to send the 'session_id' to it and always send to
# the next view then in that view retrieve his name like this
# ``name = request.session['username_%s' % session_id] ``
# the session_id from the old view
so the urls should be like this:
/first-step/?session=somecode.
/second-step/?session=somecode
if you have more fields you have to save them in session and retrieve them as i did, hope it helps you, i know its complex!
bye :)

web.py and how to use section blocks

I use web.py Templator for my project and using the render('templates', base="") I combine a base layout with a page specific layout (simplified).
view.py
render = web.template.render('templates',base='layout')
return render.index()
shared layout file
layout.html
$def with (content)
<html>
<head>
<title>$content.title</title>
</head>
<body>
$:content
</body>
</html>
page specific template
index.html
$def with (values)
$var title: Hello Kitty
<p>Hello $values, how are you doin?</p>
The solution I'm looking for is how to achieve the following
login.html
$def with (values)
$var title: Enter credentials
<form>
<p><input type="text" name="user_name"></p>
<p><input type="password" name="user_pwd"></p>
<p><button type="submit">Open the gates</button></p>
</form>
$block_begin
<script>
// When the form is submitted, check the required fields and inform user
// if any data is missing or looks weird
</script>
$block_end
</body>
</html>
My question is, how do I add the script to the login.html template but not the index.html template? I'm not interested in having to add all JS logic to all pages, I would like to add this $block_begin/$block_end so that it appears at the bottom of the layout.html like this
layout.html
$def with (content)
<html>
<head>
<title>$content.title</title>
</head>
<body>
$:content
$block_begin
$block_end
</body>
</html>
The $block_begin/$block_end was just something I came up with to better explain myself.
Just to be clear, template -> defwith sections is a grammar, not an example. To use templates, check http://webpy.org/docs/0.3/templetor for examples.
At a high level, you create templates similar to
=== templates/index.html ===
$def with(values)
$var title: Hello Kitty
<p>Hello $values, how are you doin?</p>
=== templates/layout.html ===
$def with(content)
<html>
<head>
<title>$content.title</title>
</head>
<body>
$:content
</body>
</html>
Then in your python you render the template, passing in any parameters specified in the template. ("values" in this example.) The named template (index.html) is render using the base (layout.html), and as you've discovered, content contains the rendered internal bit (the results of index) and is inserted into the base template, layout.
You're asking how to get some script into login.html, but not in index.html & that's easy: just add the javascript code into the login.html template.
=== login.html ===
$def with (values)
$var title: Enter credentials
<form>
...
</form>
<script>
window.addEventListener('load', function () {
// whatever javascript you want to execute on load.
// If using jQuery, you'll have to use $$('form') or jQuery('form') rather
// than $('form'), as dollar signs are special within the template.
});
</script>
Something more clever? Use content more fully. Anything you define using $var in your template gets put into $content in the base layout.
If you want to include login.js only when your login.html page is rendered, you could simple create a new content attribute. In login.html:
$var extra_js: js/login.js
Then, in your layout file conditionally load the value at the bottom (where we like to load scripts).
=== templates/layout.html ===
...
<body>
$:content
$if content.get('extra_js', None):
<script type="text/javascript" src="$content.extra_js"></script>
</body>
</html>
You can make your layout.html more and more powerful, parameterizing meta data, scripts, css files, etc. Just like you did with $content.title, and let your individual template files drive different parts of the overall layout.

How can I get an html for to run a python script on submit?

I have an html form and I want to use python to send the information from the form to an sqlite database file. Right now I am trying to do it with cgi. I don't need anything fancy. Here is my code:
html:
<!DOCTYPE HTML>
<html>
<head>
<title>Sample page to test fill_web_form.py</title>
</head>
<body>
<p1><strong>SAMPLE PAGE TO TEST FILL_WEB_FORM.PY</strong></p1>
<!--test form-->
<form action="send_form_to_db.py" method="post">
Form to be tested:<br>
<input type="text" name="test_form"/>
<input type="submit" value="Submit"/>
</form>
</body>
</html>
python:
# send_form_to_db.py
# sends data from html form to database
# import statements
import cgi
import sqlite3
cgitb.enable()
form = cg.FieldStorage()
data = form.getvalue('test-form')
conn = sqlite3.connect('sample.db')
conn.execute("INSERT INTO test_table [test_column] VALUES (data)")
conn.commit()
conn.close()
When I run this the web browser doesn't run the python code, it just displays it as text.
Right now I'm just trying to do this in the simplest way possible without implementing things like Django.
Minor detail: change form = cg.FieldStorage() to form = cgi.FieldStorage().
Note: i in cgi.

Python, Flask: TypeError: 'NoneType' object has no attribute '__getitem__' for filled form

I have looked through previous questions involving the same error, but have not managed to find a working solution for my problem. I have a form in my html code (as part of a single-page-application) that I wish to submit to my python server through ajax.
the form in details.html:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>A Title</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0">`
<link href= {{ url_for("static",filename="css/bootstrap.min.css") }} rel="stylesheet" media="screen">
</head>
<body>
<div>
<form method="post">
<label for="address">Address</label>
<input class="form-control" type="text" name="address">
<label for="postalcode">Postal Code</label>
<input class="form-control" type="text" name="postalcode"><br>
<label for="city">City</label>
<input class="form-control" type="text" name="city">
<label for="country">Country</label>
<input class="form-control" type="text" id="country_indicator" placeholder="Country" name="country">
<button id="submitForm" type="submit">Submit</button>
</form>
</div>
<script src="//code.jquery.com/jquery-1.11.2.min.js"></script>
<script src={{ url_for("static", filename="js/bootstrap.min.js") }}></script>
<script src={{ url_for("static", filename="js/details.js") }}></script>
</body>
</html>
If I remove 'method="post"' from the html form, the page empties the forms and reloads, but with it I get the above mentioned error, even when the form is fully filled out. My guess is that something between the form and the JS is not working as the request.json always returns NoneType objects.
details.js:
$(document).ready(function() {
$("#submitForm").click(function(){
var address = $("#address").val();
var postalcode = $("#postalcode").val();
var city = $("#city").val();
var country = $("#country").val();
console.log(address);
var details = {
"address" : address,
"postalcode" : postalcode,
"city" : city,
"country" : country
}
console.log(details.city);
$.ajax({
type: "POST",
url: "/details",
data: JSON.stringify(details, null, '\t'),
contentType: 'application/json;charset=UTF-8',
success: function(result) {
console.log(result)
}
})
})
})
Note: I added the console.log for troubleshooting, but no text appears in the js-console, which is why I believe the problem appears already before this point.
the relevant app.route in my .py file: I am not yet using the values from details.js, I just wish to see that something is actually sent. This is why I only return "ok" for now.
#app.route('/details', methods=['GET', 'POST'])
def details():
if request.method == "POST":
print(request.json['address']) # . TypeError: 'NoneType' object has no attribute '__getitem__' - crash appears here.
return "ok")
return render_template("details.html")
So because of some problem in the previous steps, the object sent to the .py file is NoneType I assume. I am very new to python and JS, so any pointers would be greatly appreciated. Thank you in advance!
Edit: I also encountered "uncaught ReferenceError: $ is not defined" now from the javascript console, but moving the jquery- to the head solved that problem
Doh! The data isn't being sent to the server properly! I've rewritten some of your code below. I hope you don't mind, but the form will now submit with ordinary post variables instead of JSON.
#app.route('/details', methods=['GET', 'POST'])
def details():
# This is our new method, notice it's a bit streamlined.
if request.method == "POST":
# We can get the post data using request.form.get(). The first variable is the name="" attribute in HTML, and the second is the default value if it wasn't found in the data.
return "The address was %s" % request.form.get('address', 'not provided! :O')
return render_template("base.html")
Now for the Javascript!
$(document).ready(function() {
$("#submitForm").click(function(e){
// Prevent the HTML page from submitting the form since we're doing this by AJAX. This would cause duplications and other issues.
e.preventDefault();
// Get a FormData object from the page
var data = new FormData($('form')[0]);
// You don't HAVE to send your data by JSON, and in this instance it will be easier not to
$.ajax({
type: "POST",
url: "/details",
data: data,
processData: false,
contentType: false,
success: function(result) {
console.log(result)
}
})
})
})
Hope this helps! Don't forget to mark the answer as solved if this fixes it for you. :)

Categories

Resources