In my application, I have a form, and when I submit the entered data, the page should be redirected to another link, which has it's own handler.
Here's the python code for the same:
import os
import webapp2
import jinja2
from google.appengine.ext import db
import urllib2
import re
template_dir = os.path.join(os.path.dirname(__file__), 'templates')
jinja_env = jinja2.Environment(loader = jinja2.FileSystemLoader(template_dir), autoescape=True)
class Handler(webapp2.RequestHandler):
def write(self, *a, **kw):
self.response.out.write(*a, **kw)
def render_str(self, template, **params):
t = jinja_env.get_template(template)
return t.render(params)
def render(self, template, **kw):
self.write(self.render_str(template, **kw))
class MainPage(Handler):
def get(self):
self.render("formrss.html")
def post(self):
x = self.request.get("rssquery")
if x:
self.redirect("/extract")
class ExtractFeeds(Handler):
def get(self):
self.write("ok")
app = webapp2.WSGIApplication([('/', MainPage),
('/extract', ExtractFeeds)], debug=True)
formrss.html
<html>
<head>
<title>Live Quora Feed</title>
</head>
<body>
<form>
Search:<input type = "text" name = "rssquery"><br>
<input type = "submit">
</form>
</body>
</html>
Now, when I submit the form data, instead of redirecting to the /extract link and displaying 'ok', the form page gets reloaded and the url is of the form '/?rssquery=(entered_data)'.
I can't seem to figure out what the problem could be here.
You are not using post on your form!
<form method="POST">
Search:<input type = "text" name = "rssquery"><br>
<input type = "submit">
</form>
This handler
def post(self):
x = self.request.get("rssquery")
if x:
self.redirect("/extract")
is bound to the post and with no post happening it was running the GET
Related
I am attempted to redirect in the post method every time i hit submit (which adds more "art" to the database) but I have to refresh afterwards to get the new entry to show up instead. I have included my main.py code and the html below. How can I fix this so I don't have to manually refresh after every submission. (this is from the udacity web development course).
import os
import webapp2
import jinja2
from google.appengine.ext import db
template_dir = os.path.join(os.path.dirname(__file__), 'templates')
jinja_env = jinja2.Environment(loader = jinja2.FileSystemLoader(template_dir),
autoescape = True)
class Handler(webapp2.RequestHandler):
def write(self, *a, **kw):
self.response.out.write(*a, **kw)
def render_str(self, template, **params):
t = jinja_env.get_template(template)
return t.render(params)
def render(self, template, **kw):
self.write(self.render_str(template, **kw))
class Art(db.Model):
title = db.StringProperty(required = True)
art = db.TextProperty(required = True)
created = db.DateTimeProperty(auto_now_add = True)
class MainPage(Handler):
def render_front(self, title="", art="", error=""):
arts = db.GqlQuery("select * from Art order by created desc")
self.render("front.html", title = title, art = art, error = error, arts = arts)
def get(self):
self.render_front()
def post(self):
title = self.request.get("title")
art = self.request.get("art")
if title and art:
a = Art(title=title, art=art)
a.put()
self.redirect("/")
else:
error = "we need both a title and some artwork!"
self.render_front(error=error, title=title,art=art)
app = webapp2.WSGIApplication([
('/', MainPage),
], debug=True)
html:
<form method="post">
<label>
<div>title</div>
<input type="text" name="title" value="{{title}}">
</label>
<label>
<div>art</div>
<textarea name="art">{{art}}</textarea>
<label>
<div class="error">{{error}}</div>
<input type="submit">
</form>
<hr>
{% for art in arts %}
<div class="art">
<div class="art-title">{{art.title}}</div>
<pre class="art-body">{{art.art}}</pre>
</div>
{% endfor %}
</body>
Your redirect is working fine. The reason the new entity doesn't show up is because of eventual consistency with the GAE datastore. When you put an entity, it can take a little time before it is available to be queried.
There are workarounds, but they depend on the particular application. For example, you can store a list of keys since getting by key will always work or you could use memcache.
I'm trying to scrape links from a RSS page from Quora, which I have been successful in doing so. However, I want those links to appear as hyperlinks in my application, instead of simply appearing as plain text.
Here's the application so far:
http://deploymentapp.appspot.com/
Here's the main python code:
import os
import webapp2
import jinja2
from google.appengine.ext import db
import urllib2
import re
template_dir = os.path.join(os.path.dirname(__file__), 'templates')
jinja_env = jinja2.Environment(loader = jinja2.FileSystemLoader(template_dir), autoescape=True)
class Handler(webapp2.RequestHandler):
def write(self, *a, **kw):
self.response.out.write(*a, **kw)
def render_str(self, template, **params):
t = jinja_env.get_template(template)
return t.render(params)
def render(self, template, **kw):
self.write(self.render_str(template, **kw))
class MainPage(Handler):
def get(self):
content = urllib2.urlopen('http://www.quora.com/Python-programming-language-1/rss').read()
allTitles = re.compile('<title>(.*?)</title>')
allLinks = re.compile('<link>(.*?)</link>')
list = re.findall(allTitles,content)
linklist = re.findall(allLinks,content)
self.render('frontrss.html', list = list, linklist = linklist)
app = webapp2.WSGIApplication([('/', MainPage)], debug=True)
here's the HTML source code:
<h1>Quora Live Feed</h1><br><br><br>
{% extends "rssbase.html" %}
{% block content %}
{% for e in range(1, 19) %}
{{ (list[e]) }} <br>
{{ (linklist[e]) }}
<br><br>
{% endfor %}
{% endblock %}
So basically, I don't know how to make the links appear as hyperlinks when scraped from an outside source code in Jinja2 template.
This is just basic HTML: you put the link inside the href attribute of an a tag:
{{ list[e] }}
I am trying to build a simple blog application to use the skills that I learned from Udacity so far. However, I am having trouble retrieving data from the database and displaying it for the user. Now, my blog has a permalink which displays the post that was just being submitted by the user, and also the main blog page which will display the latest 10 posts in descending order. But when I submit a post, the post is stored in the database successfully, and I am being redirected to a permalink. However, all I get is a blank page instead of the post that I just submitted.
Also, when I go back to my main blog page, I see this instead of all the posts being submitted by the user:
Here's the main python code:
import os
import re
import webapp2
import jinja2
from string import letters
from google.appengine.ext import db
template_dir = os.path.join(os.path.dirname(__file__), 'templates')
jinja_env = jinja2.Environment(loader = jinja2.FileSystemLoader(template_dir), autoescape=True)
def render_str(template, **params):
t = jinja_env.get_template(template)
return t.render(params)
class Handler(webapp2.RequestHandler):
def write(self, *a, **kw):
self.response.out.write(*a, **kw)
def render_str(self, template, **params):
return render_str(template, **params)
def render(self, template, **kw):
self.write(self.render_str(template, **kw))
def render_post(response, post):
response.out.write('<b>' + post.subject + '</b><br>')
response.out.write(post.content)
def post_key(name = "dad"):
return db.Key.from_path('blog', name)
class Blogger(db.Model):
name = db.StringProperty()
content = db.TextProperty()
created = db.DateTimeProperty(auto_now_add = True)
def render(self):
self._render_text = self.content.replace('\n', '<br>')
return render_str("post.html", p = self)
class MainPage(Handler):
def get(self):
self.response.write("Visit our blog")
class BlogHandler(Handler):
def get(self):
posts = db.GqlQuery("SELECT * FROM Blogger order by created desc")
self.render("frontblog.html", posts = posts)
class SubmitHandler(Handler):
def get(self):
self.render("temp.html")
def post(self):
name = self.request.get("name")
content = self.request.get("content")
if name and content:
a = Blogger(parent = post_key(), name = name, content = content)
a.put()
self.redirect('/blog/%s' % str(a.key().id()))
else:
error = "Fill in both the columns!"
self.render("temp.html", name = name, content = content, error = error)
class DisplayPost(Handler):
def get(self, post_id):
post_id = self.request.get("post_id")
if post_id:
po = Blogger.get_by_id(int(post_id), parent = post_key())
if po:
self.render("perma.html", po = po)
self.response.write("No")
app = webapp2.WSGIApplication([('/', MainPage),
('/blog', BlogHandler),
('/blog/submit', SubmitHandler),
(r'/blog/<post_id:([0-9]+)>', DisplayPost)], debug=True)
Here's the HTML code for the base of all the HTML pages:
<!DOCTYPE html>
<html>
<head>
<link type="text/css" rel="stylesheet" href="/static/main.css" />
<title>CS 253 Blog</title>
</head>
<body>
<a href="/blog" class="main-title">
CS 253 Blog
</a>
<div id="content">
{% block content %}
{% endblock %}
</div>
</body>
</html>
Here's the HTML code for the permalink page:
{% extends "base.html" %}
{% block content %}
{{po.render() | safe}}
{% endblock %}
HTML code for the front of the blog:
{% extends "base.html" %}
{% block content %}
{% for p in posts %}
{{ p.render() | safe }}
<br><br>
{% endfor %}
{% endblock %}
I have been struggling with this for over two days now. I see no bugs in the logs either. What seems to be the problem?
EDIT:
Edited the source code based on the answers below. However, I still get a 404 error.
You are creating your Blogger entity with a parent key that you are not specifying when you are trying to retrieve your post in your DisplayPost.
An entity's key is composed of multiple parts. It's Kind ("Blogger"), it's ID (int(post_id)), and also it's ancestor, or parent.
Because you create your entity with:
a = Blogger(parent = post_key(), name = name, content = content)
You need to specify the same parent when calling get_by_id() (see the get_by_id() docs).
Your solution will be to change
po = Blogger.get_by_id(int(post_id))
to
po = Blogger.get_by_id(int(post_id), parent=post_key())
Later, if you change the name of the blog (looking at the code for post_key()), then you'll need to carry that as an argument to the post display mechanism. (You might use a subdomain as the 'name' of the blog for example).
Here is the previous answer that addressed issues with the regex URL mapping:
In your WSGIApplication definition, you have ('/blog/([0-9]+)', DisplayPost)], debug=True).
You are missing the r before the url string to identify the string as a regular expression:
(r'/blog/([0-9]+), ....
You also have the option to be more verbose with parameter naming:
(r'/blog/<post_id:([0-9]+)>, ....
Reference: http://webapp-improved.appspot.com/guide/routing.html
I am reading about the Blobstore in Google App Engine. The code below is from the sample documentation. After the user selects a file to upload and clicks Submit, how do I get the key into a javascript variable? I can show it on a page, but I only want to keep it for later use. Obviously, I am new to Web programming.
#!/usr/bin/env python
#
import os
import urllib
from google.appengine.ext import blobstore
from google.appengine.ext import webapp
from google.appengine.ext.webapp import blobstore_handlers
from google.appengine.ext.webapp.util import run_wsgi_app
class MainHandler(webapp.RequestHandler):
def get(self):
upload_url = blobstore.create_upload_url('/upload')
self.response.out.write('<html><body>')
self.response.out.write('<form action="%s" method="POST" enctype="multipart/form-data">' % upload_url)
self.response.out.write("""Upload File: <input type="file" name="file"><br> <input type="submit"
name="submit" value="Submit"> </form></body></html>""")
class UploadHandler(blobstore_handlers.BlobstoreUploadHandler):
def post(self):
upload_files = self.get_uploads('file') # 'file' is file upload field in the form
blob_info = upload_files[0]
self.response.out.write('<html><body>')
self.response.out.write(str(blob_info.key()))
self.response.out.write('</body><html>')
def main():
application = webapp.WSGIApplication(
[('/', MainHandler),
('/upload', UploadHandler),
], debug=True)
run_wsgi_app(application)
if __name__ == '__main__':
main()
You could do something like this:
self.response.out.write("""
<html>
<script>
var blobKey = "%s";
</script>
<body>
...
</body>
</html>""" % (blob_info.key(),)
Using the below code, my template loads fine until I submit the from, then I get the following error:
e = AttributeError("'ToDo' object has no attribute 'response'",)
Why doesn't my ToDo object not have a response attribute? It works the first time it's called.
import cgi
import os
from google.appengine.api import users
from google.appengine.ext import webapp
from google.appengine.ext.webapp.util import run_wsgi_app
from google.appengine.ext.webapp import template
from google.appengine.ext import db
class Task(db.Model):
description = db.StringProperty(required=True)
complete = db.BooleanProperty()
class ToDo(webapp.RequestHandler):
def get(self):
todo_query = Task.all()
todos = todo_query.fetch(10)
template_values = { 'todos': todos }
self.renderPage('index.html', template_values)
def renderPage(self, filename, values):
path = os.path.join(os.path.dirname(__file__), filename)
self.response.out.write(template.render(path, values))
class UpdateList(webapp.RequestHandler):
def post(self):
todo = ToDo()
todo.description = self.request.get('description')
todo.put()
self.redirect('/')
application = webapp.WSGIApplication(
[('/', ToDo),
('/add', UpdateList)],
debug=True)
def main():
run_wsgi_app(application)
if __name__ == "__main__":
main()
Here's the template code so far, I'm just listing the descriptions for now.
<!doctype html public "-//w3c//dtd html 4.0 transitional//en">
<html>
<head>
<title>ToDo tutorial</title>
</head>
<body>
<div>
{% for todo in todos %}
<em>{{ todo.description|escape }}</em>
{% endfor %}
</div>
<h3>Add item</h3>
<form action="/add" method="post">
<label for="description">Description:</label>
<input type="text" id="description" name="description" />
<input type="submit" value="Add Item" />
</form>
</body>
</html>
why do you do what you do in post? it should be:
def post(self):
task = Task() # not ToDo()
task.description = self.request.get('description')
task.put()
self.redirect('/')
put called on a subclass of webapp.RequestHandler will try to handle PUT request, according to docs.