Overwrite in datastore using python for GAE - Guestbook Example - python

I want to do something very similar to the Guestbook example GAE provides in Python.
But instead allowing one user to sign multiple times, I want each submission to overwrite any preexisting one by the current user.
I'm having trouble figuring out how to edit this example to make that work.
import cgi
import datetime
import urllib
import wsgiref.handlers
from google.appengine.ext import db
from google.appengine.api import users
from google.appengine.ext import webapp
from google.appengine.ext.webapp.util import run_wsgi_app
class Greeting(db.Model):
"""Models an individual Guestbook entry with an author, content, and date."""
author = db.StringProperty()
content = db.StringProperty(multiline=True)
date = db.DateTimeProperty(auto_now_add=True)
def guestbook_key(guestbook_name=None):
"""Constructs a Datastore key for a Guestbook entity with guestbook_name."""
return db.Key.from_path('Guestbook', guestbook_name or 'default_guestbook')
class MainPage(webapp.RequestHandler):
def get(self):
self.response.out.write('<html><body>')
guestbook_name=self.request.get('guestbook_name')
# Ancestor Queries, as shown here, are strongly consistent with the High
# Replication Datastore. Queries that span entity groups are eventually
# consistent. If we omitted the ancestor from this query there would be a
# slight chance that Greeting that had just been written would not show up
# in a query.
greetings = db.GqlQuery("SELECT * "
"FROM Greeting "
"WHERE ANCESTOR IS :1 "
"ORDER BY date DESC LIMIT 10",
guestbook_key(guestbook_name))
for greeting in greetings:
if greeting.author:
self.response.out.write(
'<b>%s</b> wrote:' % greeting.author)
else:
self.response.out.write('An anonymous person wrote:')
self.response.out.write('<blockquote>%s</blockquote>' %
cgi.escape(greeting.content))
self.response.out.write("""
<form action="/sign?%s" method="post">
<div><textarea name="content" rows="3" cols="60"></textarea></div>
<div><input type="submit" value="Sign Guestbook"></div>
</form>
<hr>
<form>Guestbook name: <input value="%s" name="guestbook_name">
<input type="submit" value="switch"></form>
</body>
</html>""" % (urllib.urlencode({'guestbook_name': guestbook_name}),
cgi.escape(guestbook_name)))
class Guestbook(webapp.RequestHandler):
def post(self):
# We set the same parent key on the 'Greeting' to ensure each greeting is in
# the same entity group. Queries across the single entity group will be
# consistent. However, the write rate to a single entity group should
# be limited to ~1/second.
guestbook_name = self.request.get('guestbook_name')
greeting = Greeting(parent=guestbook_key(guestbook_name))
if users.get_current_user():
greeting.author = users.get_current_user().nickname()
greeting.content = self.request.get('content')
greeting.put()
self.redirect('/?' + urllib.urlencode({'guestbook_name': guestbook_name}))
application = webapp.WSGIApplication([
('/', MainPage),
('/sign', Guestbook)
], debug=True)
def main():
run_wsgi_app(application)
if __name__ == '__main__':
main()

The easiest way to do this is to modify the post method of the Guestbook class, so that it checks for an existing post from the current user and updates it, if it exists.
class Guestbook(webapp.RequestHandler):
def post(self):
guestbook_name = self.request.get('guestbook_name')
user = users.get_current_user()
nickname = None
if user:
nickname = user.nickname()
greeting = Greeting.gql('WHERE author = :1 AND ANCESTOR IS :2',
nickname, guestbook_key(guestbook_name)).get()
if not greeting:
greeting = Greeting(parent=guestbook_key(guestbook_name))
greeting.author = nickname
greeting.content = self.request.get('content')
greeting.put()
self.redirect('/?' + urllib.urlencode({'guestbook_name': guestbook_name}))

Related

Flask 405 Method Not Allowed

after click subimit button I have problem like in title, the problem start showing when I separated routes from app to views, when I go to localhost:5000/register/ all is good but when I fill the form and click submit then I have problem 405
app.py
from flask import Flask,render_template,request,redirect,abort
app = Flask(__name__)
import views
app.add_url_rule('/', view_func=views.index)
app.add_url_rule('/login/', view_func=views.login)
app.add_url_rule('/register/', view_func=views.register)
if __name__ == '__main__':
app.run(debug=True)
views.py
from flask import Flask,render_template,request,redirect,abort
app = Flask(__name__)
#app.route('/register/', methods=["GET","POST"])
def register():
if request.method == "POST":
req = request.form
email = req.get("email")
password = req["password"]
phonenumber = request.form["phonenumber"]
if email == "" or password == "" or phonenumber=="":
feedback="Please fill the form"
alert = "fail"
else:
feedback="Account created!"
alert = "good"
return render_template('register.html',feedback=feedback,alert=alert)
return render_template('register.html')
#app.route('/')
def index():
print("CIAO")
return render_template('base.html')
and form
<form class="" method="POST" action="{{ url_for('register') }}">
<input type="email" name="email" placeholder="Email">
<input type="password" name="password" placeholder="password" minlength="8">
<input type="tel" name="phonenumber" placeholder="Numer Telefonu" minlength="8" maxlength="9">
<input type="submit" name="submit">
</form>
Flask is not finding the POST method handler for the /register/ endpoint. You're mixing add_url_rule and #route. You just need the former if you want pluggable views.
I would recommend using the MethodView approach here. Have a separate class for each template and define the get() and post() methods within that.
app.py:
from flask import Flask
from views import Register, Login, Index
app = Flask(__name__)
app.add_url_rule('/', view_func=Index.as_view("index"))
app.add_url_rule('/login/', view_func=Login.as_view("login"))
app.add_url_rule('/register/', view_func=Register.as_view("register"))
if __name__ == '__main__':
app.run(debug=True)
views.py:
from flask import Flask,render_template,request,redirect,abort
from flask.views import MethodView
class Register(MethodView):
def get(self):
return render_template('register.html')
def post(self):
req = request.form
email = req.get("email")
password = req["password"]
phonenumber = request.form["phonenumber"]
if email == "" or password == "" or phonenumber == "":
feedback = "Please fill the form"
alert = "fail"
else:
feedback = "Account created!"
alert = "good"
return render_template('register.html', feedback=feedback, alert=alert)
class Index(MethodView):
def get(self):
print("CIAO")
return render_template('index.html')
class Login(MethodView):
def get(self):
return render_template('login.html')

Upload Video to GAE Blobstore and Get Input While Uploading

I am am using Google App Engine in Python and I want users to be able to upload a video, which is functioning properly by following their basic example but then I want to be able to get the user to add additional information about the video, like the title and category and a summary while it is uploading. Is there any way I can make the upload asynchronous so that the user doesn't have to wait the whole time the video is uploading?
I know about the create_upload_url_async() method but that doesn't do what I am trying.
Right now I have the following which uploads and serves but I want to make an intermediate step where the user can add the info preferably on the same screen as the UploadHandler while it is uploading.
class VideoHandler(BlogHandler):
def get(self):
user = self.get_user()
upload_url = blobstore.create_upload_url('/uploadingvideo')
self.render('videohandler.html', user=user, upload_url=upload_url)
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.redirect('/serve/%s' % blob_info.key())
class ServeHandler(blobstore_handlers.BlobstoreDownloadHandler):
def get(self, blob_key):
blob_key = str(urllib.unquote(blob_key))
if not blobstore.get(blob_key):
self.error(404)
else:
self.send_blob(blobstore.BlobInfo.get(blob_key))
I'd be glad to provide more information if you need it.
this has been troubling me alot too clifgray. the solution is to build your form around the blob form.
Here's google's example on how to submit data to the blob store.
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.redirect('/serve/%s' % blob_info.key())
Just remove the self redirect bit at the bottom of the code and add some code to handle your form.
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]
greeting = Greeting()
if users.get_current_user():
greeting.author = users.get_current_user()
greeting.video = str(blob_info.key())
greeting.content = self.request.get('content')
greeting.put()
Your form in your django template should look something like this:
form action="{{ upload_url }}" enctype="multipart/form-data" method="post">
textarea name="content" placeholder="write something about this video.." tabindex="1" rows="2" cols="40"></textarea>
input name="file" type="file" >
input name="submit" type="submit" value="Submit" />
/form>
There you have it. hope this helps

Tie a Blob to a Datastore entity

I have been banging my head against the wall on this one, for some reason I am having trouble tying the different aspects of Google App Engine together to make this work.
Basically I want to let a user upload a photo to the Blobstore, which I have working in the below code, and then I want to put the BlobKey into a list which will be stored in a database entity. So here is my code to upload the image and where in here can I get the BlobKey so that I can store it?
class MainHandler(BlogHandler):
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>""")
#there is a lot more code in here where I get all the following info but it isn't relevant
location_db = Location(
description=description,
submitter=submitter,
user_id=user_id,
title=title,
locationtype = locationtype)
#This is what I would like to do but I don't know where to get thr BlobKey
location_db.blobRefs.append(BlobKey)
location_db.put()
for b in blobstore.BlobInfo.all():
self.response.out.write('<li>' + str(b.filename) + '')
class UploadHandler(blobstore_handlers.BlobstoreUploadHandler):
def post(self):
upload_files = self.get_uploads('file')
blob_info = upload_files[0]
self.redirect('/main')
class ServeHandler(blobstore_handlers.BlobstoreDownloadHandler):
def get(self, blob_key):
blob_key = str(urllib.unquote(blob_key))
if not blobstore.get(blob_key):
self.error(404)
else:
self.send_blob(blobstore.BlobInfo.get(blob_key), save_as=True)
Here:
blob_info = upload_files[0]
self.redirect('/serve/%s' % blob_info.key())
I think it's that
blob_info.key()
you are missing. Grab that, stuff it into your list. Docs also note:
In this handler, you can store the blob key with the rest of your application's data model. The blob key itself remains accessible from the blob info entity in the datastore.
https://developers.google.com/appengine/docs/python/blobstore/overview#Serving_a_Blob

Displaying images form datastore

I am just testing out displaying images on GAE, I have this little .py
import cgi
import wsgiref.handlers
from google.appengine.api import users
from google.appengine.api import images
from google.appengine.ext import db
from google.appengine.ext import webapp
class ImgUpload(db.Model):
project_name = db.StringProperty()
project_description = db.StringProperty(multiline=True)
img_name = db.StringProperty()
img_img = db.BlobProperty()
date = db.DateTimeProperty(auto_now_add=True)
class UploadPage(webapp.RequestHandler):
def get(self):
self.response.out.write("""<html><body>
<form action="/upload" enctype="multipart/form-data" method="post">
<div><label>Project Name</label></div>
<div><textarea name="title" rows="2" columns "60"></textarea></div>
<div><label>Despcription:</label></div>
<div><textarea name="content" rows="3" cols="60"></textarea></div>
<div><label>Image Name</label></div>
<div><textarea name="imgname" row="1" cols="60"></textarea></div>
<div><label>Image</label></div>
<div><input type="file" name="img"/></div>
<div><input type="submit" value="Upload" /></div>
</form>
</body>
</html>""")
def post(self):
images = ImgUpload()
project_name = self.request.get('title')
project_description = self.request.get('content')
img_img = self.request.get('img')
img_name = self.request.get('imgname')
images.img_img = db.Blob(img_img)
images.project_name = project_name
images.project_description = project_description
images.img_name = img_name
images.put()
self.redirect('/upload')
class DisplayPage(webapp.RequestHandler):
def get(self):
display = db.GqlQuery("SELECT * "
"FROM display "
"WHERE ANCESTOR IS :1 "
"ORDER BY date DESC LIMIT 5"
)
for record in display:
self.response.out.write('<b>%s</> is the Name' % record.project_name)
def main():
application = webapp.WSGIApplication(
[('/', UploadPage),
('/display', DisplayPage)
],
debug=True)
wsgiref.handlers.CGIHandler().run(application)
if __name__=="__main__":
main()
When I run this, I get a KindError: No implementation for kind 'display'. Is this an issue pertaining to lack of a DB key, I know they data is in the store, I can see it in the admin, and I can't see any naming issue (at least off the top of my head, there could be thousands for all that I know). What exactly is causing this error to pop? Thank you in advance for your advice.
In your GQL you are selecting from the "display" kind. You don't have a display kind defined, you have a "ImgUpload" kind defined. Using the object interface to query will help you avoid this type of problem.
I also don't see a parameter being passed to the query for it to filter on, so you're going to get another error there.

Storing a string from a textbox to the Google App Engine Datastore

Is it possible to create a textbox in HTML, type a string into it, click a "save" button, store that information onto a GAE datastore model and have the text stay displayed in the textbox and saved in the datastore?
The HTML is on a separate file, just rendered through my main.py file using
class MainPage(webapp.RequestHandler):
def get(self):
template_values = {}
path = os.path.join(os.path.dirname(__file__), 'index.html')
self.response.out.write(template.render(path, template_values))
What I tried for my problem is this:
class equipmentBox(db.Model):
equipCode = db.StringProperty()
class equipmentBoxGet(webapp.RequestHandler):
def post(self):
I think this will help, i have modified default guestbook app for you. Usual way of doing is having html files separately and using templates to render it. Here everything is just embedded into the controller itself
import cgi
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 import db
class EquipmentBox(db.Model):
equipCode = db.StringProperty()
class MainPage(webapp.RequestHandler):
def get(self):
self.response.out.write('<html><body>')
equips = db.GqlQuery("SELECT * FROM EquipmentBox")
for equip in equips:
self.response.out.write('<blockquote>%s</blockquote>' %
cgi.escape(equip.equipCode))
# Write the submission form and the footer of the page
self.response.out.write("""
<form action="/post" method="post">
<div><input type="text" name="equip_code" /></div>
<div><input type="submit" value="post equipcode"></div>
</form>
</body>
</html>""")
class EquipBox(webapp.RequestHandler):
def post(self):
equip = EquipmentBox()
equip.equipCode = self.request.get('equip_code')
equip.put()
self.redirect('/')
application = webapp.WSGIApplication(
[('/', MainPage),
('/post', EquipBox)],
debug=True)
def main():
run_wsgi_app(application)
if __name__ == "__main__":
main()
The best way to build this sort of interface, where the user "saves" data on the page without the page changing, is to use AJAX calls.
While a full explanation of how AJAX works is probably beyond the scope of an answer here, the basic idea is that you have a Javascript onclick event attached to your Save button, which sends the contents of your textbox via a POST request to the server. See the link above for a tutorial.

Categories