I have a rather silly question.
I am trying an app and have two forms on it:
Enter a zip code (submit button)
or
Login if you already have a user id. (submit button)
Now in my code (python using web.py framework) i have two def POST(self) but which one will the first form and the second login form call?
I am super confused. Now my friend tells me html cannot have two different forms.
Here is the code and the form is incomplete - i am just trying to get the methods running well before I start grabbing more data and building a db schema.
import web
from web import form
render = web.template.render('templates/')
urls = (
'/', 'index'
)
myform = form.Form(
form.Textbox("Zip Code",
form.regexp('^\d{5}$', 'Not a zip code'),
description='Enter a 5 digit zip code',
maxlength = '5'),
)
myloginform = form.Form(
form.Textbox("Username",
form.regexp('^[^<>\s\#]+(\#[^<>\s\#]+(\.[^<>\s\#]+)+)$', 'Invalid username'),
description='Enter your username'),
)
class index:
def __init__(self): ** i still dont know wtf this does..
pass
def GET(self):
form = myform()
myloginform1 = myloginform()
return render.index(form,myloginform1)
def POST(self):
form = myform()
if not form.validates():
return render.index(form)
else:
return "The zip code you are located is: %s" % (form['Zip Code'].value)
def POST(self):
myloginform1 = myloginform()
if not myloginform1.validates():
return render.index(myloginform1)
else:
return "Welcome %s" % (myloginform1['Username'].value)
class testfunc:
def GET(self):
return "Test function returning!"
if __name__ == "__main__":
app = web.application(urls, globals())
app.run()
The index.html is below
$def with (form, myloginform1)
<html>
<head><title>8reps Welcome.. </title></head>
<body>
<h3>Hi</h3>
<p> Lets find some results in your area.. </p>
<form name="main" method="post">
$if not form.valid: <p class="error">Try again...</p>
$:form.render()
<input type="submit" /> </form>
<p> Already registered? Login as a user..</p>
<form name="login" method="post">
$if not myloginform1.valid: <p class="error">Try again..</p>
$:myloginform1.render()
<input type="submit" />Login</form>
</form>
</body>
</html>
Thank you!!
you may have as many forms on the page as you want, the only issue is how you will handle them.
there are 2 options:
two separate backends e.g. /login and /zip to handle POSTs from forms - in the form tag you will need to add action attribute to direct POSTs properly
single /index where you can handle both forms, but then you need to recognize which form was posted, e.g. by presence of some named field (you can use submit input with the same name but different values:
<input name="submit" type="submit" value="Zip" />
and for the second form:
<input name="submit" type="submit" value="Login" />
then you will know which form was posted by checking value of sent "submit" field.
for sure, you can't have 2 methods wit the same name in class definition.
Related
Trying to write a simple app that:
Presents an html form to get to get input data (a greeting and a name).
Displays the data in the browser, and then (here is the part I cannot figure out)
Saves the input form data to a simple .txt file
Here is the python code:
import web
urls = (
'/hello', 'Index'
)
app = web.application(urls, globals())
render = web.template.render('templates/', base='layout')
class Index(object):
def GET(self):
return render.hello_form() # returns form to browser
def POST(self): # gets name and greeting data back
form = web.input(name="Nobody", greet="Hello")
greeting = "%s ... %s" % (form.greet, form.name)
return render.index(greeting = greeting) #displays index.html
with open ('projects/forms/ninja.txt)', 'w') as out_file:
out_file.write(form.getValue("greet"))
out_file.write(form.getValue("name"))
if __name__ == "__main__":
app.run()
Here is the hmtl form:
<h1>this is hello_form</h1>
<form action="/hello" method="POST">
A Greeting: <br>
<input type="text" name="greet">
<br/>
Your Name: <br>
<input type="text" name="name">
<br/>
<input type="submit">
</form>
I have searched other answers, including this one:
how to store html form data into file
But I cannot seem to find the information to get this going.
You're performing a POST request on /hello with this line.
<form action="/hello">
However, you haven't defined a controller for this route. As a result, nothing happens.
Either make a POST on /Index or create a handler for /hello
Also, I would highly recommend a framework for this. Something small, like Flask.
I have a python file and an html file that interact with each other through the jinja2 environment in a manner similar to the one in this tutorial.
The following code controls the interaction between the html file and the python file:
class MainPage(webapp2.RequestHandler):
def get(self):
submission_query = Submission.query().order(-Submission.score)
submissions = submission_query.fetch(10)
template_values = {
'Submission' : Submission,
'submissions' : submissions,
}
template = JINJA_ENVIRONMENT.get_template('index.html')
self.response.write(template.render(template_values))
app = webapp2.WSGIApplication([
('/', MainPage),
('/create', CreateSubmmission),
('/voteup', VoteUp),
], debug=True)
I have a ndb model as follows:
class Submission(ndb.Model):
username = ndb.StringProperty()
placename = ndb.StringProperty()
link = ndb.StringProperty()
score = ndb.IntegerProperty()
I have an html form to create a new Submission as follows:
<form action="/create" method="post">
add a new location: <br>
your name:<div><textarea name="username" rows="2" cols="60"></textarea></div>
placename:<div><textarea name="placename" rows="2" cols="60"></textarea></div>
url:<div><textarea name="link" rows="2" cols="60"></textarea></div>
<div><input type="submit" value="Post"></div>
</form>
Using this request handler:
class CreateSubmmission(webapp2.RequestHandler):
def post(self):
submission = Submission()
submission.username = self.request.get('username')
submission.placename = self.request.get('placename')
submission.link = self.request.get('link')
submission.score = 0
submission.put()
self.redirect('/')
I have a section in my html which prints out each Submission along with a button for upvoting it:
{% for Submission in submissions %}
<p>
{{Submission.username}} posted:
<strong>{{Submission.placename}}</strong> <br>
score:{{Submission.score}}<br>
<!--Vote up button-->
<form action="/voteup?submission={{Submission}}" method="post">
<div><input type="submit" value="voteup"></div>
</form>
</p><br><br>
{% endfor %}
The upvoting is handled by the following python class:
class VoteUp(webapp2.RequestHandler):
def post(self):
submission = self.request.get('Submission')
submission_key = submission.put()
the_submission = submission_key.get()
the_submission.score +=1
the_submission.put()
self.redirect('/')
When pressing the button, the value of the respective Submission's score attribute should increase by one.
The code is implemented on the website sunlit-hook-91816.appspot.com. As can be seen on that site, pressing the upvote button generates the following error:
File "/base/data/home/apps/s~sunlit-hook-91816/1.383863233180213164/guestbook.py", line 52, in post
submission_key = submission.put()
AttributeError: 'str' object has no attribute 'put'
It appears that the VoteUp class is somehow unable to modify the value of Submission.score.
I am using the information found here but I can't figure out how to correctly apply it this problem. Can anyone tell me of a way to make the VoteUp class modify the Submission.score?
You're using the Submission object like it can be passed along between html/python code but it can't, you must add a reference in the form and dereference it back in you server.
Do this in the vote form:
<form action="/voteup?submission={{Submission.key.urlsafe()}}" method="post">
<div><input type="submit" value="voteup"></div>
</form>
We're getting the key of the submission in a format safe for http transport, so it can arrive back to the server unaltered.
Now when processing the vote, we can recreate the key and get the correct object:
class VoteUp(webapp2.RequestHandler):
def post(self):
submission = self.request.get('submission')
submission_key = ndb.Key(urlsafe=submission)
the_submission = submission_key.get()
the_submission.score +=1
the_submission.put()
self.redirect('/')
As you can see we're just recreating the key based on the formatted string we printed in the form.
Another way you could do this to make it even better is to use an extra input in the form:
<form action="/voteup" method="post">
<input name="submission" type="hidden" value="{{Submission.key.urlsafe()}}">
<div><input type="submit" value="voteup"></div>
</form>
Your code will work the same way, but I find it easier to read and maintain.
I am using a flask framework, and can't seem to delete rows from the database. The code below gives a 405 error: "The method is not allowed for the requested URL." Any ideas?
In the py:
#app.route('/delete/<postID>', methods=['POST'])
def delete_entry():
if not session.get('logged_in'):
abort(401)
g.db.execute('delete from entries WHERE id = ?', [postID])
flash('Entry was deleted')
return redirect(url_for('show_entries', post=post))
In the html:
<h3>delete</h3>
Clicking <a href...>delete</a> will issue a GET request, and your delete_entry method only responds to POST.
You need to either 1. replace the link with a form & submit button or 2. have the link submit a hidden form with JavaScript.
Here's how to do 1:
<form action="/delete/{{ entry.id }}" method="post">
<input type="submit" value="Delete />
</form>
Here's how to do 2 (with jQuery):
$(document).ready(function() {
$("a.delete").click(function() {
var form = $('<form action="/delete/' + this.dataset.id + '" method="post"></form>');
form.submit();
});
});
...
Delete
One thing you should not do is make your delete_entry method respond to GET. GETs are meant to be idempotent (are safe to run repeatedly and don't perform destructive actions). Here's a question with some more details.
Alternatively, change POST to DELETE to get you going.
#app.route('/delete/<postID>', methods=['DELETE'])
Ideally, you should use HTTP DELETE method.
I used flaskr as a base for my Flask project (as it looks like you did as well).
In the .py:
#app.route('/delete', methods=['POST'])
def delete_entry():
if not session.get('logged_in'):
abort(401)
g.db.execute('delete from entries where id = ?', [request.form['entry_id']])
g.db.commit()
flash('Entry deleted')
return redirect(url_for('show_entries'))
In the HTML:
<form action="{{ url_for('delete_entry') }}" method=post class=delete-entry>
<input type="hidden" name="entry_id" value="{{ entry.id }}">
<input type="submit" value="Delete" />
</form>
I wanted a button, but you could easily use a link with the solution here.
A simple <a href= link in HTML submits a GET request, but your route allows only PUT requests.
<a> does not support PUT requests.
You have to submit the request with a form and/or with JavaScript code.
(See Make a link use POST instead of GET.)
I am creating a web based application with python where the user enters a search query and data is returned. I used bottle to provide the web framework for this. Openshift is then used to post online. It is a simple post form and the search criteria is then used in the next section using this:
#route('/')
def search():
return '''
<h1 align="center">Twitter Sentiment Analysis</h1>
<p align="center">Enter what you would like to search in the search box below</p>
<form action="/result" method="post" align="center">
Search: <input name="search" type="text" />
<input value="Search" type="submit" />
</form>
'''
#route('/result', method='POST')
def result():
search = request.forms.get('search')
return 'it worked'
When using bottle and tested it, it worked fine, but when I try to deploy it to OpenShift, I get a name error, "global variable 'request' is not defined" when in testing it worked perfectly with just bottle before deploying to openshift, does anyone know why this may be?
It seems like you haven't imported the request or route to namespace:
from bottle import get, post, request # or route
#get('/login') # or #route('/login')
def login():
return '''
<form action="/login" method="post">
Username: <input name="username" type="text" />
...
'''
#post('/login') # or #route('/login', method='POST')
def do_login():
user = request.forms.get('username')
pass = request.forms.get('password')
...
This is becoming very frustrating, like all of my Django form endeavors have been thus far...
I have a search bar form that is supposed to send the user to a url '/project/search/<query>/' and the url works fine if I type in a url but my form is not mapping correctly. I am implementing this first in the search results page, which will still have a search bar, and whenever I type in a value to the search bar I get redirected to '/project/search/'. Where have I gone wrong? I have spent a solid two days on this to no avail.
I am really struggling with this and I have no idea what I am doing wrong. I wish I had at least an error or something to fix but this is just not working.
Here is my form class and view:
from django import forms
class SearchForm(forms.Form):
search_string = forms.CharField(initial='Search Article Text',max_length=100)
def search(request, search_query):
form = SearchForm()
context = RequestContext(request)
search_string = search_query.replace('_',' ')
search_terms = search_query.split('_')
search_results = Article.objects.all()
for term in search_terms:
search_results = search_results.filter(article__icontains=term)
context_dict = {
'search_string':search_string,
'search_results':search_results,
'form':form,
}
if request.method == 'POST':
form = SearchForm(request.POST)
context_dict['form'] = form
if form.is_valid():
search_string = form.cleaned_data['search_string']
search_query = search_string.replace(' ','_')
###return HttpResponseRedirect(reverse('search', args=(search_query,)))
search_url = '/project/search/' + search_query + '/'
return HttpResponseRedirect(search_url)
return render_to_response('search.html', context_dict, context)
The html:
<form action='/beacon/search/' class="navbar-form navbar-right" method='POST'>
<div class="form-group">
{% csrf_token %}
{{ form.search_string }}
</div>
<input type='submit' value='Submit' class='btn btn-default'/>
</form>
I don't really understand your question. You're getting redirected because that's what you've told the view to do: you explicitly return an HttpResponseRedirect. If you don't want to redirect, don't do that.
Ok after troubleshooting for probably 5 or so days I have realized what my issue was (I also had a little help from the Django Users Google group).
I am answering this in case anybody also has my problem in the future btw. I'm obviously not an expert on the forms part of Django.
This all had to do with the actual HTML writeup I had. In my form tag the action was to '/project/search/' which just redirected me to that URL because django thought /project/search/ was different than project/search/query . Therefore all I needed to do for this part was change the action to refer to any URL that would validate my search view- so I picked /project/search/search_query/ but anything after /project/search/ would have worked.
My second issue was with my input. I needed to include a name in my input -'search_string'- so my search view would understand what values the form itself was carrying.
Therefore my html in the end looks like:
<form action='/beacon/search/search_query/' class="navbar-form navbar-right" method='POST'>
<div class="form-group">
{% csrf_token %}
<input type="text" name='search_string' class="form-control" placeholder="Search Article Text"/>
</div>
<!--<button type="submit" class="btn btn-default" value='Submit'>Submit</button>-->
<input type='submit' value='Submit' class='btn btn-default'/>
</form>
Credit to Branko Majic to helping my on Dj Users Group as well. Seriously.