How to enter item into Google AppEngine Datastore? - python

I want to check if an email is in my database in Appengine, and if not: then enter it into the datastore.
I am new to python.
Why is this simple code not working? (Also If there is a better way/more efficient way to write this, please tell me)
(I get the error: BadArgumentError: Unused positional arguments [1])
class EmailAdd(webapp.RequestHandler):
def get(self):
query = db.GqlQuery("SELECT * FROM EmailDatabase WHERE emailaddress=':1'", self.request.get('emailaddress'))
result = query.get()
if result is None:
newemail = EmailDatabase()
newemail.emailaddress = self.request.get('emailaddress')
newemail.put()
And for reference, this is my db class:
class EmailDatabase(db.Model):
emailaddress = db.StringProperty()
date = db.DateTimeProperty(auto_now_add=True)

You don't need to use quotes when binding a parameter to the query:
query = db.GqlQuery("SELECT * FROM EmailDatabase WHERE emailaddress = :1", self.request.get('emailaddress'))
Otherwise it will read it as a string and actually only return objects that have :1 as their emailaddress value.
Also, make sure you validate the user input (self.request.get('emailaddress')) before inserting it into the query.

Related

How to populate a dropdown box with a database query instead of a list in flask

this could be a very easy question but as I novice I have to ask here sorry as I have not found the answer so far after a lot of playing with it.
I'm using flask with a python list of food types to allow users to input a food item into a form and have this verified with validators to make sure the item is in the list. The inputted food items from the form then gets stored in a db table.
I wish to replace this list approach with a sql query from a db of pre defined food types, whilst using the SQLAlchemy as this is used elsewhere in the app.
A simplified version of the code is as follows: -
#db connection is already setup and working OK in another part of the app
DB_URL = 'postgresql+psycopg2://{user}:{pw}#{url}:{port}/{db}'.format(user=POSTGRES_USER, pw=POSTGRES_PW, url=POSTGRES_URL, port=POSTGRES_PORT, db=POSTGRES_DB)
app.config['SQLALCHEMY_DATABASE_URI'] = DB_URL
db = SQLAlchemy(app)
#example of the list
eaten = ['bread', 'crackers', 'ham', 'bacon']
#where the 'food_word' variable gets defined from an input and validated
food_word_1 = StringField('add the food type you have eaten here:', validators=[Optional(), AnyOf(eaten)])
I've tried replacing the list with eaten = db.execute('SELECT food_name FROM food_type') (table & column) with no luck.
I'm not sure if I need to create some kind of class/methods in the model.py for this Select/GET operation or even use something like pandas (which I also have in the app) to do this job.
Any guidance appreciated!
thanks, md
SQLAlchemy is an Object Relational Mapper. It helps to interact with the database without SQL query. It is an abstraction to the database. So you should not write SQL query here. Rather you have to create an inherited class from db.Model. Like below.
class FoodType(db.Model):
id = db.Column(db.Integer, primary_key=True)
food_name = db.Column(db.String(120), unique=True, nullable=False)
def __repr__(self):
return '<User %r>' % self.food_name
Then for fetching data, you have to call the query function,
db.query.all()
# or
db.query.filter_by()
The result will be a single list.
If you using postgres directly, without SQLAlchemy, then SQL query will be like,
>>> conn = psycopg2.connect(DATABASE_URL)
>>> cur = conn.cursor()
>>> cur.execute('SELECT food_name FROM food_type')
>>> cur.fetchall()
[['bread'], ['crackers'], ['ham'], ['bacon']]
If you want to convert as a single list,
eaten = [i[0] for i in db.fetchall()]

Overwritting Data in App Engine

I have a function that gets an image from a form, and put's it into the database along with the username. So, here is my database:
class Imagedb(db.Model):
name = db.StringProperty(required = True)
image = db.BlobProperty()
And here is the code that writes to the database:
class Change_Profile_Image(MainHandler):
def get(self):
if self.user:
self.render('change_profile_image.html', username = self.user.name, firstname=self.user.first_name)
else:
self.render('change_profile_image.html')
def post(self):
imagedb = Imagedb(name = self.user.name)
imageupl = self.request.get("img")
imagedb.image = db.Blob(imageupl)
imagedb.put()
self.redirect('/profile')
Any who, it works awesome. Except for one thing. What i'm trying to accomplish is only storing ONE profile picture. What ends up happening is this:
Say I am the user admin. Ill upload a display pic, that pic shows in the profile. Ill upload another one, that one shows. Cool, except for the fact that I have 2 objects in my database that have the name = admin attribute. I would like to edit this...
def post(self):
imagedb = Imagedb(name = self.user.name)
imageupl = self.request.get("img")
imagedb.image = db.Blob(imageupl)
imagedb.put()
self.redirect('/profile')
so that I can post images to the database, but if one exists, it is overwritten. Could anyone help me with this please? I'm relatively new to python and app engine.
If something is unclear, please let me know.
You want to set the key of the Imagedb entity to "name". Essentially, you don't need the name field, but you'll instantiate it like
imagedb = Imagedb(key_name = self.user.name)
The key is a required field on all entities. By using your user name as the key it means every time you refere to a given key, it's the same entity.

How to query datastore when using ReferenceProperty?

I am trying to understand the 1-to-many relationships in datastore; but I fail to understand how query and update the record of a user when the model includes ReferenceProperty. Say I have this model:
class User(db.Model):
userEmail = db.StringProperty()
userScore = db.IntegerProperty(default=0)
class Comment(db.Model):
user = db.ReferenceProperty(User, collection_name="comments")
comment = db.StringProperty()
class Venue(db.Model):
user = db.ReferenceProperty(User, collection_name="venues")
venue = db.StringProperty()
If I understand correctly, the same user, uniquely identified by userEmail can have many comments and may be associated with many venues (restaurants etc.)
Now, let's say the user az#example.com is already in the database and he submits a new entry.
Based on this answer I do something like:
q = User.all()
q.filter("userEmail =", az#example.com)
results = q.fetch(1)
newEntry = results[0]
But I am not clear what this does! What I want to do is to update comment and venue fields which are under class Comment and class Venue.
Can you help me understand how this works? Thanks.
The snippet you posted is doing this (see comments):
q = User.all() # prepare User table for querying
q.filter("userEmail =", "az#example.com") # apply filter, email lookup
- this is a simple where clause
results = q.fetch(1) # execute the query, apply limit 1
the_user = results[0] # the results is a list of objects, grab the first one
After this code the_user will be an object that corresponds to the user record with email "az#example.com". Seing you've set up your reference properties, you can access its comments and venues with the_user.comments and the_user.venues. Some venue of these can be modified, say like this:
some_venue = the_user.venues[0] # the first from the list
some_venue.venue = 'At DC. square'
db.put(some_venue) # the entry will be updated
I suggest that you make a general sweep of the gae documentation that has very good examples, you will find it very helpful:
http://code.google.com/appengine/docs/python/overview.html
** UPDATE **: For adding new venue to user, simply create new venue and assign the queried user object as the venue's user attribute:
new_venue = Venue(venue='Jeferson memorial', user=the_user) # careful with the quoting
db.put(new_venue)
To get all Comments for a given user, filter the user property using the key of the user:
comments = Comment.all().filter("user =", user.key()).fetch(50)
So you could first lookup the user by the email, and then search comments or venues using its key.

Datastore query outputting for Django form instance

I'm using google appengine and Django. I'm using de djangoforms module and wanted to specify the form instance with the information that comes from the query below.
userquery = db.GqlQuery("SELECT * FROM User WHERE googleaccount = :1", users.get_current_user())
form = forms.AccountForm(data=request.POST or None,instance=?????)
I've found a snippet in a sample app that does this trick, but I can't modify it to work with the query I need.
gift = User.get(db.Key.from_path(User.kind(), int(gift_id)))
if gift is None:
return http.HttpResponseNotFound('No gift exists with that key (%r)' %
gift_id)
form = RegisterForm(data=request.POST or None, instance=gift)
Could anyone help me?
If you know the userquery will only have one User object in it (or if you only care about the first one if there are duplicates), you can modify your code like so:
userquery = db.GqlQuery("SELECT * FROM User WHERE googleaccount = :1", users.get_current_user())
user = userquery.get() # Gets the first User instance from the query, or None
form = forms.AccountForm(data=request.POST or None, instance=user)

Unable to query from entities loaded onto the app engine datastore

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.

Categories

Resources