Unable to query from entities loaded onto the app engine datastore - python

I am a newbie to python. I am not able to query from the entities- UserDetails and PhoneBook I loaded to the app engine datastore. I have written this UI below based on the youtube video by Brett on "Developing and Deploying applications on GAE" -- shoutout application. Well I just tried to do some reverse engineering to query from the datastore but failed in every step.
#!/usr/bin/env python
import wsgiref.handlers
from google.appengine.ext import db
from google.appengine.ext import webapp
from google.appengine.ext.webapp import template
import models
class showPhoneBook(db.Model):
""" property to store user_name from UI to persist for the session """
user_name = db.StringProperty(required=True)
class MyHandler(webapp.RequestHandler):
def get(self):
## Query to get the user_id using user_name retrieved from UI ##
p = UserDetails.all().filter('user_name = ', user_name)
result1 = p.get()
for itr1 in result1:
userId = itr.user_id
## Query to get the phone book contacts using user_id retrieved ##
q = PhoneBook.all().filter('user_id = ', userId)
values = {
'phoneBookValues': q
}
self.request.out.write(
template.render('phonebook.html', values))
def post(self):
phoneBookuser = showPhoneBook(
user_name = self.request.get('username'))
phoneBookuser.put()
self.redirect('/')
def main():
app = webapp.WSGIApplication([
(r'.*',MyHandler)], debug=True)
wsgiref.handlers.CGIHandler().run(app)
if __name__ == "__main__":
main()
This is my models.py file where I've defined my UserDetails and PhoneBook classes,
#!/usr/bin/env python
from google.appengine.ext import db
#Table structure of User Details table
class UserDetails(db.Model):
user_id = db.IntegerProperty(required = True)
user_name = db.StringProperty(required = True)
mobile_number = db.PhoneNumberProperty(required = True)
#Table structure of Phone Book table
class PhoneBook(db.Model):
contact_id = db.IntegerProperty(required=True)
user_id = db.IntegerProperty(required=True)
contact_name = db.StringProperty(required=True)
contact_number = db.PhoneNumberProperty(required=True)
Here are the problems I am facing,
1) I am not able to call user_name (retrieved from UI-- phoneBookuser = showPhoneBook(user_name = self.request.get('username'))) in get(self) method for querying UserDetails to to get the corresponding user_name.
2) The code is not able to recognize UserDetails and PhoneBook classes when importing from models.py file.
3) I tried to define UserDetails and PhoneBook classes in the main.py file itself, them I get the error at result1 = p.get() saying BadValueError: Unsupported type for property : <class 'google.appengine.ext.db.PropertiedClass'>
I have been struggling since 2 weeks to get through the mess I am into but in vain. Please help me out in straightening out my code('coz I feel what I've written is a error-prone code all the way).

I recommend that you read the Python documentation of GAE found here.
Some comments:
To use your models found in models.py, you either need to use the prefix models. (e.g. models.UserDetails) or import them using
from models import *
in MyHandler.get() you don't lookup the username get parameter
To fetch values corresponding to a query, you do p.fetch(1) not p.get()
You should also read Reference properties in GAE as well. I recommend you having your models as:
class UserDetails(db.Model):
user_name = db.StringProperty(required = True)
mobile_number = db.PhoneNumberProperty(required = True)
#Table structure of Phone Book table
class PhoneBook(db.Model):
user = db.ReferenceProperty(UserDetails)
contact_name = db.StringProperty(required=True)
contact_number = db.PhoneNumberProperty(required=True)
Then your MyHandler.get() code will look like:
def get(self):
## Query to get the user_id using user_name retrieved from UI ##
user_name = self.request.get('username')
p = UserDetails.all().filter('user_name = ', user_name)
user = p.fetch(1)[0]
values = {
'phoneBookValues': user.phonebook_set
}
self.response.out.write(template.render('phonebook.html', values))
(Needless to say, you need to handle the case where the username is not found in the database)
I don't quite understand the point of showPhoneBook model.

Your "session variable" being stored to the datastore isn't going to follow your redirect; you'd have to fetch it from the datastore in your get() handler, although without setting a session ID in a cookie or something this isn't going to implement sessions at all, but rather allow anyone getting / to use whatever value was send with a POST request whether it was sent by them or someone else. Why use the redirect at all; responding to a POST request should be done in the post() method, not through a redirect to a GET method.

Related

Flask with SQLite and peewee returns only 20 results/rows

I have been developing a flask based app for my college event. I have used an SQLite database along with Peewee and it's playhouse extensions. There is a particular page where I need to show all the entries from a database table.
# The playhouse.flask_utils.FlaskDB object accepts database URL configuration.
DATABASE = 'sqliteext:///%s' % os.path.join(APP_DIR, 'blog.db')
DEBUG = False
# Create a Flask WSGI app and configure it using values from the module.
app = Flask(__name__)
app.config.from_object(__name__)
app.config['UPLOAD_FOLDER'] = UPLOAD_FOLDER
# FlaskDB is a wrapper for a peewee database that sets up pre/post-request
# hooks for managing database connections.
flask_db = FlaskDB(app)
# The `database` is the actual peewee database, as opposed to flask_db which is
# the wrapper.
database = flask_db.database
There is an Entry class, with save and a query function
class Entry(flask_db.Model):
title = CharField()
slug = CharField(unique=True)
content = TextField()
tags = TextField()
published = BooleanField(index=True)
is_highlight = BooleanField(index=True)
category = TextField()
date = TextField()
time = TextField()
contact = TextField()
fee = TextField()
image = TextField()
timestamp = DateTimeField(default=datetime.datetime.now, index=True)
#property
def html_content(self):
"""
Generate HTML representation of the markdown-formatted blog entry,
and also convert any media URLs into rich media objects such as video
players or images.
"""
hilite = CodeHiliteExtension(linenums=False, css_class='highlight')
extras = ExtraExtension()
markdown_content = markdown(self.content, extensions=[hilite, extras])
oembed_content = parse_html(
markdown_content,
oembed_providers,
urlize_all=True,
maxwidth=app.config['SITE_WIDTH'])
return Markup(oembed_content)
def save(self, *args, **kwargs):
# Generate a URL-friendly representation of the entry's title.
if not self.slug:
self.slug = re.sub('[^\w]+', '-', self.title.lower()).strip('-')
ret = super(Entry, self).save(*args, **kwargs)
# Store search content.
return ret
#classmethod
def public(cls):
return Entry.select().where(Entry.published == True)
And the function that renders the page is
#app.route('/events')
def events():
query = Entry.public()
return object_list(
'list.html',
query,
check_bounds=False)
The query when run over the command line using sqlite3 for ubuntu returns all 26 entries, however in the app, it returns only 20 of them. I verified by deleting one of the entries from the table, and it's place was taken by one of the rows not visible earlier. I looked upon multiple sites and documentations from both peewee and sqlite and haven't found a solution yet. I even tried changing pragma statements like Page Size. I am of the opinion that changing the run-time limits of the DB can help me, but I haven't found a way to change or modify that. Is there anyway to fix it. Or is migration to MariaDB gonna solve it. If so is that the only solution.
I simply had to use 'paginate_by = my-number' in the object list.

peewee 'no such table' error

I am trying to put data into a database using flask and peewee, and I have come across the following error: peewee.OperationalError: no such table: post
My models.py file is below:
from peewee import *
import datetime
db = SqliteDatabase('posts.db') #create database to interact with
#create a class for blogposts
class Post(Model):
id = PrimaryKeyField()
date = DateTimeField(default = datetime.datetime.now)
title = CharField()
text = TextField()
class Meta:
database = db
def initialize_db():
db.connect()
db.create_tables([Post], safe = True)
db.close()
I have Googled this, and for most people the lack of 'db.create_tables()' seems to be the problem. Obviously, it's in my code, so I am really not sure where the error is coming from. Some advice would be much appreciated. The problem seems to arise specifically when I try to populate the 'text' field using another .py file.
I adapted your code into the following snippet and it works for me:
from peewee import *
import datetime
db = SqliteDatabase('posts.db') #create database to interact with
#create a class for blogposts
class Post(Model):
id = PrimaryKeyField()
date = DateTimeField(default = datetime.datetime.now)
title = CharField()
text = TextField()
class Meta:
database = db
def initialize_db():
db.connect()
db.create_tables([Post], safe = True)
db.close()
initialize_db() #if db tables are not created, create them
post = Post.create(id=4, title="Some title", text="some text1") #add a new row
post.save() #persist it to db, not necessarily needed
You'll need to call the create method when creating a new Post (i.e. a new row in your database). Other than that, initialize_db() seems to work just fine.
If you are unable to perform any writes on the database, make sure you have write access in the directory where you are trying to do that (in this case, it would be your working directory)

How to save an embedded object in GAE?

I'm trying to save a datastore entity reference within another:
class Save(webapp2.RequestHandler):
def get(self):
order = Order(parent=ndb.Key('Orders', 'default_orders'))
order.special_request = self.request.get('specialRequirement')
order.product_type = self.request.get('productType')
customer = Customer(parent=ndb.Key('Customer', 'default_customers'))
customer.name = self.request.get('customerName')
customer.email = self.request.get('email')
customer.put()
order.customer = customer
order.put()
The Customer class is simply:
from google.appengine.ext import ndb
class Customer(ndb.Model):
name = ndb.StringProperty()
email = ndb.StringProperty()
Whilst I've done similar with Rails and mongodb before, I'm not sure what this is called in GAE and am having a hard time searching for examples.
Ok, the following seems to have been my oversight, simply passing the key as:
oder.customer = customer.key
I now have a usable reference to the embedded object and both are being saved correctly.

create unique profile page for each user python

I am using google app engine in python with a Jinja2 template engine.
This may be a silly solution but I have a list of a few thousand users and right now they can only access their own profile pages and have to be logged in to do it. I would like to give every user a unique URL for their profile page and I am wondering how to do it. I am not sure if this would work but could something like this be feasible?
class ProfilePage
userlist = GQL query to return all users in the system
user = users.get_by_id()
for user in userlist:
id = user.federated_id
posts = GQL query to return all posts by that user
self.render('/profile/id', posts=posts)
app = webapp2.WSGIApplication([('/', MainPage),
('/profile/([0-9]+)', ProfilePage),])
My HTML for the profile page just displays the user's name and then displays all of their recent posts.
Update:
So here is my current code but I am just getting a 404 error:
class ProfilePage(webapp2.RequestHandler):
def get(self, profile_id):
user = User.get_by_id(profile_id)
#profile_id = some unique field
if user:
#Get all posts for that user and render....
theid = user.theid
personalposts = db.GqlQuery("select * from Post where theid =:1 order by created desc limit 30", theid)
else:
personalposts = None
global visits
logout = users.create_logout_url(self.request.uri)
currentuser = users.get_current_user()
self.render('profile.html', user = currentuser, visits = visits, logout=logout, personalposts=personalposts)
How can I test it out I tried just entering www.url.com/profile/https://www.google.com/accounts/o8/id?id=AItOawlILoSKGNwU5RuTiRtXug1l8raLEv5-mZg
Update:
The ID I was retrieving was not their OpenID URL but rather a app specific id that each user is given and thus that is the correct to use
An easy way to do this would be to assign a unique URL identifier to each user (or use their key name), that way you can query the user by their ID or do a query based on a unique URL identifier property. You can also use their federated_id if you wanted.
Example:
class User(ndb.Model):
unique_identifier = ndb.StringProperty()
...
class ProfilePage(webapp2.RequestHandler):
def get(self, profile_id):
#profile_id = key name of user
user = User.get_by_id(profile_id)
#profile_id = some unique field
#user = User.query(User.unique_identifier == profile_id).get()
if user:
#Get all posts for that user and render....
app = webapp2.WSGIApplication([('/', MainPage),
('/profile/<profile_id>', ProfilePage),])

How do I parse the JSON array when trying to load facebook friends into Google App Engine facebook example?

I am just starting out on an idea of a Google App engine app that interacts with Facebook. All my coding experience is number crunching in Matlab, which is so high level, a lot of real coders haven't even heard of it. I am attempting to extend the example provided by facebook here. So far, the only thing I've tried to add is reading in a list of the user's friends. I've put comments ahead of the lines I added in my version of the code below. The code succeeds in loading in the user from facebook. I can access the various user properties and display them. However, the friends property that I tried to add is always a blank list. I think the difference is that things like name and id are JSON strings that can be handled like Python strings but graph.get_connections returns an array of JSON objects as the list of friends. I think I should be turning this JSON array into a python dictionary but I don't know how. Of course, I may be completely wrong about that.
I would really appreciate a tip as to how I can get the user's list of friends into a python list of some kind that I can manipulate.
Thanks,
Dessie
#!/usr/bin/env python
#
# Copyright 2010 Facebook
#
"""A barebones AppEngine application that uses Facebook for login."""
FACEBOOK_APP_ID = "my_facebook_app_id"
FACEBOOK_APP_SECRET = "my_facebook_app_secret"
import facebook
import os.path
import wsgiref.handlers
import logging
import platform
from google.appengine.ext import db
from google.appengine.ext import webapp
from google.appengine.ext.webapp import util
from google.appengine.ext.webapp import template
class User(db.Model):
id = db.StringProperty(required=True)
created = db.DateTimeProperty(auto_now_add=True)
updated = db.DateTimeProperty(auto_now=True)
name = db.StringProperty(required=True)
profile_url = db.StringProperty(required=True)
access_token = db.StringProperty(required=True)
#Following line added by me
friends = db.StringListProperty()
class BaseHandler(webapp.RequestHandler):
"""Provides access to the active Facebook user in self.current_user
The property is lazy-loaded on first access, using the cookie saved
by the Facebook JavaScript SDK to determine the user ID of the active
user. See http://developers.facebook.com/docs/authentication/ for
more information.
"""
#property
def current_user(self):
if not hasattr(self, "_current_user"):
self._current_user = None
cookie = facebook.get_user_from_cookie(
self.request.cookies, FACEBOOK_APP_ID, FACEBOOK_APP_SECRET)
if cookie:
# Store a local instance of the user data so we don't need
# a round-trip to Facebook on every request
user = User.get_by_key_name(cookie["uid"])
if not user:
graph = facebook.GraphAPI(cookie["access_token"])
profile = graph.get_object("me")
id=str(profile["id"]
#Following 2 lines added by me
fs=graph.get_connections("me","friends")
logging.info(fs)
user = User(key_name=str(profile["id"]),
id=str(profile["id"]),
name=profile["name"],
profile_url=profile["link"],
access_token=cookie["access_token"],
#Following line added by me
friends=fs)
user.put()
elif user.access_token != cookie["access_token"]:
user.access_token = cookie["access_token"]
user.put()
self._current_user = user
return self._current_user
class HomeHandler(BaseHandler):
def get(self):
#Following line added by me
logging.info(self.current_user.friends)
path = os.path.join(os.path.dirname(__file__), "example.html")
args = dict(current_user=self.current_user,
facebook_app_id=FACEBOOK_APP_ID)
self.response.out.write(template.render(path, args))
def main():
util.run_wsgi_app(webapp.WSGIApplication([(r"/", HomeHandler)]))
if __name__ == "__main__":
main()
I think I should be turning this JSON array into a python dictionary but I don't know how.
simplejson is included in app-engine, in django's utils package.
from django.utils import simplejson as json
def your_method(ars):
# do what ever you are doing...
dict_of_friends = json.loads(json_string)
Having trouble with commenting tool, the time limit is throwing me off. Robert's answer seems right but it didn't work in my script. I finally got it to work with a different approach
import re
import urllib2
#after I created the user
url = "https://graph.facebook.com/" + user.id + "/friends?access_token=" + user.access_token
response = urllib2.urlopen(url)
fb_response = response.read()
x = re.findall(r'"\d+"',fb_response)
friend_list = [a.strip('"') for a in x]
user.friends = friend_list
user.put()
You don't have to convert explicitly from json at facebook python library.
just start from fs["data"], for example if you want to count the number of friends.
fs=graph.get_connections("me","friends")
friends_count = len(fs["data"])

Categories

Resources