Get the ID in a child entity of NDB GAE Datastore - google-app-engine

I'm going in circles on getting the id of NDB Datastore.
I have setup the webapp2.RequestHandler to catch the email and get the ID. Basically my goal is to delete an entity, but if I pass the email address to get the ID of the entity, I'm stump, because it gives me results I was just getting. I used ID instead of key_name.
I tried finding the ID by querying via email, but it seems like using query does not have a method attribute to find the id.
def get(self,email):
user = users.get_current_user()
if user:
user_key = ndb.Key('UserPrefs',user.email())
contacts = Contact.query(Contact.email==email,ancestor=user_key)
self.response.write(contacts.id) # there is no attribute such as Contact.id
I tried to find the ID by getting the key, but when I displayed the key, it showed me whatever value I have in the email variable
def get(self,email):
user = users.get_current_user()
if user:
user_key = ndb.Key('UserPrefs',user.email())
contact_key = ndb.Key('Contact',email,parent=user_key)
self.response.write(contact_key.id())
Real Question: So, given that I do not have the ID, how do I find the correct ID inside an entity if I saved my entities via id and not key_name?
Here are the mixture of codes that I'm trying out.
def get(self,email):
user = users.get_current_user()
if user:
user_key = ndb.Key('UserPrefs',user.email())
contact_key = ndb.Key('Contact',email,parent=user_key)
contacts = Contact.query(Contact.email==email,ancestor=user_key)
contact = contacts.get()
contact_key.delete()
# self.response.write(contact.name) # this works
self.response.write(contact_key.id()) # this does not work because I do not have the entity id, and I'd like to get it blindfolded. Is there a way?
Here is my Model for Contact.
class Contact(ndb.Model):
name = ndb.StringProperty()
phone = ndb.StringProperty()
email = ndb.StringProperty()
dateCreated = ndb.DateTimeProperty(auto_now_add=True)
dateUpdated = ndb.DateTimeProperty(auto_now=True)

The docs state:
The identifier may be either a key "name" string assigned by the application or an integer numeric ID generated automatically by the Datastore.
Since you are defining the name property on your Contact class, this is used as the identifier. (You don't want that because in real world different users can have same names)
So if you want NDB to generate numeric IDs for your entities, rename the name property to something else, e.g. username.
Update: let's go step by step:
Problem with the first example is that you are trying to get id on the Query. Query class has no id property defined on it. You should call get() on it:
# get() or fetch() should be called on query to return some data
contacts = Contact.query(Contact.email==email,ancestor=user_key).get()
self.response.write(contacts.id) # there is no attribute such as Contact.id
Problem with the second piece of code is that you are just initialising a Key and providing email as id - the second param of constructor is the id and you are providing email as value. Hence you are getting the email out. Also, there is no database operation here.

Note: the identifiers, which are id, key, urlsafe, or value (for the query) should be passed from the HTTP Request by webapp2.RequestHandler from a parsed url or HTTP POST, GET, PUT, or DELETE.
If you do not have any identifiers or values passed from an HTTP request, it could be difficult to access the specific entity (or the record). So, it is important to take note to pass a form of identifier or value to access the specific entity (or the record in database terms).
So, you can do the following to get the id:
Access by value:
def get(self,email):
user = users.get_current_user()
if user:
user_key = ndb.Key('UserPrefs',user.email())
contacts = Contact.query(Contact.email==email,ancestor=user_key)
contact = contacts.get()
id = contact.key.id() # this access the entity id directly because you have the data.
self.response.write(id)
Access by urlsafe:
def get(self,urlString):
user = users.get_current_user()
if user:
contact_key = ndb.Key(urlsafe=urlString) #urlString refers to the key of contact
contact = contact_key.get()
id = contact.key.id() # this access the entity id directly because you have the data.
self.response.write(id)
Access by HTTP POST Request:
def post(self):
user = users.get_current_user()
if user:
user_key = ndb.Key('UserPrefs',user.email())
email = self.request.get('email')
contacts = Contact.query(Contact.email==email,ancestor=user_key)
contact = contacts.get()
id = contact.key.id() # this access the entity id directly because you have the data.
self.response.write(id)

Related

I need to get the user id from my users table in DynamoDB?

I'm using AWS Amplify on my react native app
I want to do something seemingly so simple, but i am a bit lost as to how to do it: I have a table with user information already in it. Here's the Schema:
type Users #model {
id: ID!
userName: String
firstname: String
weblink: String
email: String
mobileNum: String
.
.
.
}
//Here's my Query.js
export const getUsers = `query GetUsers($id: ID!) {
getUsers(id: $id) {
id
userName
firstname
weblink
email
.
.
.
}
}
`;
This table is populated in DynamoDB when i check my AWS console. What i need is to be able to get the id from the table using the userName (not vice versa). The id is generated when i createUser() and it's used throughout my app to get all my user's information. However when a user signs in on a new phone, this id isn't available anymore. So when they sign in via Cognito, i do know the userName and all i need to do is retrieve this id.
Normally i would do this, but obviously i want to do the reverse and use my unique userName to get the id:
const userData = await API.graphql(graphqlOperation(GetUsers, { id: usersId })); //usersId = "3b0dae-24j5-4401-95a6-11seyhaf1g131"
Any idea how i can get my users id?
Assuming that the userName is unique, create a Global Secondary Index with userName as the partition key. Project, at least, the id attribute into the index. Finally, search that index instead of the underlying table.
Alternatively, if you never need to lookup by id, consider making userName the partition key and id a regular attribute.

Peewee : How to update specific fields?

I'm using Peewee for working with database. I have a User tables with 3 fields: username, password and last_login. When a user login to the system i want to update last_login. I've use following lines of code:
from peewee import *
import datetime
class User(Model):
username = CharField(unique=True)
password = CharField()
last_login = DateTimeField(default=datetime.datetime.now())
class Meta:
database = MySQLDatabase('mydb', user='root', charset='123456')
u=User(username="user1", last_login=datetime.datetime.now())
u.save()
Although i haven't specified any value for password, it is overwritten after u.save() is called. How should i force peewee to only update last_login field?
Replace u.save() with:
u.save(only=[User.last_login])
As the API's documentation says:
only (list) – A list of fields to persist – when supplied, only the given fields will be persisted.
So you should specify a list of fields you want to be changed.
You can use the only argument when calling save(). http://docs.peewee-orm.com/en/latest/peewee/api.html#Model.save
When a user login to the system i want to update last_login. I've use following lines of code:
If you want to do this, you should do an atomic update, however:
User.update({User.last_login: datetime.datetime.now()}).where(User.username == 'whatever').execute()
The following code will demonstrate how to create, get and update a record in the database:
now = datetime.datetime.now()
# create a user
u = User.create(username="user1", password="bla", last_login=now)
# now `u` has your user, you can do: print u.username, u.password, u.last_login
# get an existing user from the db
u = User.get(User.username == "user1")
print u.username, u.password, u.last_login
sleep(1)
now = datetime.datetime.now()
# update an existing user
u = User.update(password="blabla", last_login=now).where(User.username == "user1")
u.execute()
If you want to save only modified fields, you may use the method below:
class User(Model):
username = CharField(unique=True)
password = CharField()
last_login = DateTimeField(default=datetime.datetime.now())
class Meta:
database = MySQLDatabase('mydb', user='root', charset='123456')
# This method saves only modefied fields
only_save_dirty = True
u=User(username="user1", last_login=datetime.datetime.now())
u.save()

What is the proper way to request this entity? Python and GQL

I'm trying to see if the username variable in the post function matches the username in the accountsArchive entity.
I think the problem is that user.username isn't the proper way to reference the username entity. Also, the query above may have a problem. What's the proper way to see if the two usernames match?
Python
class accountsArchive(db.Model):
# The username entity
username = db.StringProperty(required = True)
password = db.TextProperty(required = True)
email = db.StringProperty(required = True)
dateJoined = db.DateTimeProperty(auto_now_add = True)
class loginPage(Handler):
def post(self):
# The username variable
username = self.request.get("username")
password = self.request.get("password")
# The query
user = db.GqlQuery("SELECT * FROM accountsArchive WHERE
user.username = :name", name=username)
# This is how I tried to check if the two usernames matched
if username == user.username:
# Do stuff
You have a number of problems in your code.
Firstly
user = db.GqlQuery("SELECT * FROM accountsArchive WHERE
user.username = :name", name=username)
Is incorrect - you should go back and reread the docs https://cloud.google.com/appengine/docs/python/datastore/gqlreference?hl=en
This query should be
user = db.GqlQuery("SELECT * FROM accountsArchive WHERE
username = :name", name=username)
Next.
The result of this line of code is an instance of GqlQuery class not a user or as you might expect a list of users. See https://cloud.google.com/appengine/docs/python/datastore/gqlqueryclass?hl=en
You now have to fetch the results and/or iterate through them.
For instance
for u in user.run():
if u.username == username:
# then do something
However you have a problem. There is nothing in this that would limit the system a single unique user. So if you get more than one user with the same username what will you do.
Some comments.
You could use the username as the key of the accountsArchive which means you just use a get rather than a query.
Secondly if you are new to appengine and don't have an existing base of code, start out using ndb instead.

NDB projection of instance Key or ID

I'm using NDB on GoogleAppEngine and I want to retrieve a instance Key or ID by passing an e-mail into the query.
My Model looks something like this:
class Users(ndb.Model):
user_name = ndb.StringProperty(required=True)
user_email = ndb.StringProperty(required=True)
user_password = ndb.StringProperty(required=True)
#classmethod
def get_password_by_email(cls, email):
return Users.query(Users.user_email == email).get(projection=[Users.key, Users.user_password])
When running the code, I get the following error:
BadProjectionError: Projecting on unknown property __key__
How can I get an instance ID or Key by querying users through an e-mail in AppEngine's NDB (e.g. Login process)?
Thanks!
A projection query will always include the key as well as the fields you specify, so if keys_only isn't sufficient, then:
return Users.query(Users.user_email == email).get(projection=[Users.password])
If you only need Key you can try keys-only query:
Users.query(Users.user_email == email).get(keys_only=True)

How Can I Automatically Populate SQLAlchemy Database Fields? (Flask-SQLAlchemy)

I've got a simple User model, defined like so:
# models.py
from datetime import datetime
from myapp import db
class User(db.Model):
id = db.Column(db.Integer(), primary_key=True)
email = db.Column(db.String(100), unique=True)
password = db.Column(db.String(100))
date_updated = db.Column(db.DateTime())
def __init__(self, email, password, date_updated=None):
self.email = email
self.password = password
self.date_updated = datetime.utcnow()
When I create a new User object, my date_updated field gets set to the current time. What I'd like to do is make it so that whenever I save changes to my User object my date_updated field is set to the current time automatically.
I've scoured the documentation, but for the life of me I can't seem to find any references to this. I'm very new to SQLAlchemy, so I really have no prior experience to draw from.
Would love some feedback, thank you.
Just add server_default or default argument to the column fields:
created_on = db.Column(db.DateTime, server_default=db.func.now())
updated_on = db.Column(db.DateTime, server_default=db.func.now(), server_onupdate=db.func.now())
I prefer the {created,updated}_on column names. ;)
SQLAlchemy docs about column insert/update defaults.
[Edit]: Updated code to use server_default arguments in the code.
[Edit 2]: Replaced onupdate with server_onupdate arguments.
date_created = db.Column(db.DateTime, default=db.func.current_timestamp())
date_modified = db.Column(db.DateTime, default=db.func.current_timestamp(),
onupdate=db.func.current_timestamp())

Resources