Python ndb Datastore put list to Datastore - python

I am trying to populate a Datastore with my older course notes so that in future I can add notes like a comments board or guestbook.
I can't seem to get the previous notes in the Datastore and have been trolling over GAE documentation and searching the web to no avail.
Here is my code:
import time
import cgi
import os
import jinja2
import webapp2
from google.appengine.ext import ndb
jinja_env = jinja2.Environment(loader = jinja2.FileSystemLoader(template_dir), autoescape = True)
dataEntery = [[1, 4, 'Networks','''
<p>A network is a group of entities that can communicate, even </p>'''],
[2, 4, 'Measuring Networks','''
<p>The two main ways of measuring a network are;</p>
'''], etc]
class CourseData(ndb.Model):
id_index = ndb.IntegerProperty()
stage_number = ndb.IntegerProperty()
note_title = ndb.StringProperty(indexed=False)
note_content = ndb.StringProperty(indexed=False)
for a in dataEntery:
newEntry = CourseData(id_index=a[0], stage_number=a[1], note_title=a[2], note_content=a[3])
newEntry.put()
time.sleep(.2)
class MainHandler(webapp2.RequestHandler):
def get(self):
self.response.out.write('''
<!DOCTYPE HTML>
<html>
<head>
<title>Lee's Notes</title>
<link href="../styles.css" rel="stylesheet" type="text/css">
</head>
<body>
<h1 class="opener">Lee's Notes on Intro to Programming</h1>
''')
query = CourseData.query(stage_number == 4).fetch()
self.response.out.write('<article id="note%s"><h2>%s</h2>' % cgi.escape(query.note_title), cgi.escape(query.note_title))
self.response.out.write('%s</article>' % cgi.escape(query.note_content))
app = webapp2.WSGIApplication([
('/', MainHandler)], debug=True)

First thing to note is that the appengine datastore is eventually consistent. Read this article: https://cloud.google.com/appengine/docs/python/datastore/structuring_for_strong_consistency?hl=en
For you're case you don't really need a query. Make a good index and then retrieval is a lot easier with a key.get(). Note, this is assuming you don't want to use id_index...
for a in dataEntery:
entityKey = ndb.Key(CourseData._get_kind(), stage_number=a[1])
newEntry = CourseData(key=entityKey, id_index=a[0], stage_number=a[1], note_title=a[2], note_content=a[3])
newEntry.put()
Retrieval then becomes:
entity_key = CourseData.build_key(4)

Related

Python using Google App Engine. Upload file feature that stores files in the GAE datastore

I found code for a guestbook storing text in a datastore. I've been looking all morning to find how would i modify my code to upload a file instead of reading from the textfield. and displaying the file details after displaying it. I would appreciate any help? or maybe there's an answer already out there i just haven't found it.
Here's my code so far:
import cgi
import datetime
import urllib
import wsgiref.handlers
from google.appengine.ext import db
from google.appengine.api import users
import webapp2
class Greeting(db.Model):
author = db.UserProperty()
content = db.StringProperty(multiline=True)
date = db.DateTimeProperty(auto_now_add=True)
def upload_key(upload_name=None):
return db.Key.from_path('Upload', upload_name or 'default_upload')
class MainPage(webapp2.RequestHandler):
def get(self):
self.response.out.write('<html><body>')
upload_name=self.request.get('upload_name')
greetings = db.GqlQuery("SELECT * "
"FROM Greeting "
"WHERE ANCESTOR IS :1 "
"ORDER BY date DESC LIMIT 10",
upload_key(upload_name))
for greeting in greetings:
if greeting.author:
self.response.out.write(
'<b>%s</b> wrote:' % greeting.author.nickname())
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="Upload a File"></div>
</form>
<hr>
<form>Name: <input value="%s" name="upload_name">
<input type="submit" value="switch user"></form>
</body>
</html>""" % (urllib.urlencode({'upload_name': upload_name}),
cgi.escape(upload_name)))
class Upload(webapp2.RequestHandler):
def post(self):
upload_name = self.request.get('upload_name')
greeting = Greeting(parent=upload_key(upload_name))
if users.get_current_user():
greeting.author = users.get_current_user()
greeting.content = self.request.get('content')
greeting.put()
self.redirect('/?' + urllib.urlencode({'upload_name': upload_name}))
APP = webapp2.WSGIApplication([
('/', MainPage),
('/sign', Upload)
], debug=True)
def main():
APP.RUN()
if __name__ == '__main__':
main()
There's two basic approaches. The traditional approach, and the approach you'll find the most samples for, is the Blobstore API. The new approach is Google Cloud Storage. The advantages of the Blobstore is that there are more existing samples, but the advantage of GCS is that the same code can work outside the context of App Engine.
APPROACH 1 - BLOBSTORE API - EASIER *
Here are the official Blobstore docs with samples.
Here's a similar Stack Overflow question.
APPROACH - GOOGLE CLOUD STORAGE API - BETTER
For Google Cloud Storage, the official client library is gcloud-python. Since this is not part of the App Engine SDK, you will generally "vendor" it (include it directly in your project) before you deploy the App Engine app using pip -t flag, and modififying an appengine_config.py file. See the instructions for that in "Installing a library". The short version of the story is that you do
mkdir lib
pip install gcloud-python -t lib
then add an appengine_config.py with the follow lines:
from google.appengine.ext import vendor
# Third-party libraries are stored in "lib", vendoring will make
# sure that they are importable by the application.
vendor.add('lib')
Finally, we walk through using this API in a Python app in this tutorial

Google App Engine: 404 Resource not found

I am trying to build a basic blog model using Google App Engine in Python. However, something's wrong with my code I suppose, and I am getting a 404 error when I try to display all the posted blog entries on a single page. Here's the 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)
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))
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(name = name, content = content, parent = post_key())
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):
po = Blogger.get_by_id(int(post_id))
if po:
self.render("perma.html", po = po)
else:
self.response.write("404 Error")
app = webapp2.WSGIApplication([('/', MainPage),
('/blog', BlogHandler),
('/blog/submit', SubmitHandler),
('/blog/([0-9]+)', DisplayPost)], debug=True)
After posting my content, it gets redirected to a permalink. However, this is the error I am getting on submitting my post:
404 Not Found
The resource could not be found
Here's the frontblog.html source code, in case that would help:
<!DOCTYPE html>
<html>
<head>
<title>CS 253 Blog</title>
</head>
<body>
<a href="/blog">
CS 253 Blog
</a>
<div id="content">
{% block content %}
{%for post in posts%}
{{post.render() | safe}}
<br></br>
{%endfor%}
{% endblock %}
</div>
</body>
</html>
So basically, I am not being redirected to the permalink page. What seems to be the problem?
When you create your post, you're giving it a parent (not sure why). But when you get it, you do so by the ID only, and don't take into account the parent ID. In the datastore, a key is actually a path consisting of all the parent kinds and IDs/names and then those of the current entity, and to get an object you need to pass the full path.
Possible solutions here:
Drop the parent key, since it isn't doing anything here as you're always setting it to the same value;
Use it when you get the object: Blogger.get_by_id(post_id, parent=parent_key()) - obviously this only works if the parent is always the same;
Use the full stringified key in the path, rather than just the ID, and do Blogger.get(key) - you'll also need to change the route regex to accept alphanumeric chars, eg '/blog/(\w+)', and change the redirect to '/blog/%s' % a.key().

What are the "imports" for GAE OAuth2.0?

I'm following this tutorial to learn how to get OAuth2.0 login onto my site, and I'm having some problems. My site is registered on GAE and I have my client ID. I also pip installed google-api-python-client. However, I don't know what to import into my project. I have two pages in my application. One that handles authorization and one that actually has the page.
authorize.py
import cgi, webapp2
from google.appengine.api import users
LOGIN_PAGE_HTML="""\
<html>
<body>
<input type="submit" method="post" action="/AuthorizeUser"/>
</body>
</html>
"""
class LoginPage(webapp2.RequestHandler):
def get(self):
self.response.write(LOGIN_PAGE_HTML)
class AuthorizeUser(webapp2.RequestHandler):
def post(self):
state = ''.join(random.choice(string.ascii_uppercase + string.digits)for x in xrange(32))
session['state'] = state
response = make_response('/LandingPage',
CLIENT_ID='MY ID',
STATE=state
APPLICATION_NAME='Summit Tech Help'))
if request.args.get('state','') != session['state']:
response = make_response(json.dumps('Invalid state parameter.'), 401)
response.headers['Content-Type'] = 'application/json'
return response
application = webapp2.WSGIApplication([
('/',LoginPage),
('/AuthorizeUser',AuthorizeUser),
], debug=True)
landing.py
import cgi, webapp2
from google.appengine.api import mail
LANDING_PAGE_HTML="""\
<html>
<body>
<p>test</p>
</body>
</html>
"""
class LandingPage(webapp2.RequestHandler):
def get(self):
self.response.write(LANDING_PAGE_HTML)
application = webapp2.WSGIApplication([
('LandingPage',LandingPage),
],debug=True)
My app.yaml has '-url: /.*' set to script:authorize.application
Any help would be much appreciated!
~Carpetfizz
to use a 3rd party module you need to import it in your app, if that's what you meant to ask,
also do check this link to use external libraries in gae.
You can check this example app for using Oauth2.0 in GAE

HTML output problems

I am writing a website with python and jinja2 in google app engine. My html page is showing this on the page:
Status: 200
Content-Type: text/html;
charset=utf-8
Cache-Control: no-cache
Content-Length: 432
Any idea where this problem is coming from? Also, why is {{ initial_city }} not displaying the results?
My main.py script is:
from google.appengine.ext import db
from google.appengine.api import memcache
from models import Deal
import os
import webapp2
import jinja2
#databasestuff
deal = Deal(title='Hello',
description='Deal info here',
city='New York')
deal.put()
print deal
jinja_environment = jinja2.Environment(autoescape=True,
loader=jinja2.FileSystemLoader(os.path.join(os.path.dirname(__file__), 'templates')))
class MainPage(webapp2.RequestHandler):
def get(self):
template = jinja_environment.get_template('index.html')
self.response.out.write(template.render())
class DealHandler(webapp2.RequestHandler):
def get(self):
def get_deals(choose_city, update=False):
key = str(choose_city)
all_deals = memcache.get(key)
return all_deals
choose_city = self.request.get('c')
try:
initial_city = str(choose_city)
choose_city = initial_city
except ValueError:
initial_city = 0
choose_city = initial_city
template = jinja_environment.get_template('deal.html')
self.response.out.write(template.render())
class ContentHandler(webapp2.RequestHandler):
def get(self):
template = jinja_environment.get_template('content.html')
self.response.out.write(template.render())
app = webapp2.WSGIApplication([('/', MainPage),
('/deal', DealHandler),
('/content', ContentHandler)],
debug=True)
My html page:
<!DOCTYPE html>
<html>
<head>
<title>
Deallzz: Chosen City: {{ initial_city }}
</title>
</head>
...
To display initial_city, pass the variable to the template using the render method:
self.response.out.write(template.render(initial_city = initial_city))
Its the "print deal" that is causing the problem. Its being output before any response.write
This is just the headers of the HTML page. You should provide more informations/code of what you are trying now.

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