why is my key_name value not as i set it? - google-app-engine

First off, I'm relatively new to Google App Engine, so I'm probably doing something silly.
I want the username to be set as key in model User
class User(db.Model):
#username is key
password = db.StringProperty(required = True)
type = db.StringProperty(required = True)
approved = db.BooleanProperty(required = True)
To insert i do this
user = User(key_name = self.request.get('username'), password = password, type = type, approved = False)
user.put()
I believe that when you set key_name manually it should be exactly what you set it to be but when i query user modle
users = db.GqlQuery("SELECT * FROM User")
for(user in users):
self.response.write(user.key())
I got the output as agxkZXZ-dmhvc3RlbDNyEQsSBFVzZXIiB2JodXNoYW4M
Please someone help!!

To start with you should read the docs on the Key class https://developers.google.com/appengine/docs/python/datastore/keyclass and how keys a structured - https://developers.google.com/appengine/docs/python/datastore/#Python_Kinds_keys_and_identifiers
Any way to your problem, note that the output of self.response.write(user.key()) is giving you the string agxkZXZ-dmhvc3RlbDNyEQsSBFVzZXIiB2JodXNoYW4M which is correct behaviour.
This is a URL safe form of the key which encodes all artifacts that make up the key.
This means you can round trip
user.key() = db.Key(encoded=str(user.key())
This allows you to use keys as part of URL. Whether that's wise or not is another discussion.
If you want to just show the name you used as the key_name then the docs for the Key class show you that the method name() will return the name.
As in user.key().name() or you could use id_or_name method which does what the name implies.

Perhaps self.request.get('username') is returning Null or None, and that results in the Datastore generating a default entry. According to the Users Service documentation it might need users.get_current_user().nickname() instead. Check by logging the values.
As Tim says you retrieve the name from the key using user.key().name().

Related

ndb.KeyProperty value get() returns None

I'm storing the key to another entity in an ndb.KeyPropery attribute called teacher
class Section(ndb.Model):
name = ndb.StringProperty(required=True)
teacher = ndb.KeyProperty(required=True, kind=Staff)
students = ndb.IntegerProperty(repeated=True)
active = ndb.BooleanProperty(default=True)
I'm storing things there just fine, but when I retrieve a value it doesn't seem to fully behave like an ndb.Key
(in interactive console on dev server...)
from google.appengine.ext import ndb
import amt
from sections.model import Section
section = Section.query(Section.name == 'test').fetch()[0]
print(section.teacher)
print(type(section.teacher))
print(section.teacher.kind())
print(section.teacher.id())
print(section.teacher.get())
print(ndb.Key(section.teacher.kind(), int(section.teacher.id())).get())
gives...
Key('Staff', '5486563022602240')
<class 'google.appengine.ext.ndb.key.Key'>
Staff
5486563022602240
None
Kxxxxxxx, Mxxx
So why does section.teacher.get() return None and ndb.Key(section.teacher.kind(), int(section.teacher.id())).get() return my entity (__str__ is overridden to just print out a name...)
Notice the difference in the key Key('Staff', '5486563022602240') and your code that fetches ndb.Key(section.teacher.kind(), int(section.teacher.id()) these are different keys.
The first has a key_name defined (str) and your fetching successfully with an id (int).
Maybe you stored the wrong key in teacher the first time around.
How did you construct your original key ?

How to remove value from GAE NDB Property (type BlobKeyProperty)

It might be the most dumb question and my apologies for the same but I am confused
I have the following entity:
class Profile(ndb.Model):
name = ndb.StringProperty()
identifier = ndb.StringProperty()
pic = ndb.BlobKeyProperty() # stores the key to the profile picture blob
I want to delete the "pic" property value of the above entity so that it should look as fresh as if "pic" was never assigned any value. I do not intend to delete the complete entity. Is the below approach correct:
qry = Profile.query(Profile.identifier==identifier)
result_record_list = qry.fetch()
if result_record_list:
result_record_list[0].pic.delete() # or result_record_list[0].pic = none # or undefined or null
I am deleting the actual blob referred by this blob key separately
assign None to it and put it back to the datastore.
result_record_list[0].pic = None
result_record_list[0].put()
The datastore is an OO schemaless databse. So you can add and remove properties from the the Kind (ndb.Model) without the need of a schema update.
If you also want to cleanup the entities look at this anwser from Guido

Datastore: Is it possible to only save to memcache when using ndb API?

dear all
Currently I'm using ndb API to store some statistic information. Unfortunately, this becomes the major source of my cost. I'm thinking it should be much cheaper if I only save them to memcache. It doesn't matter if data is lost due to cache expire.
After read the manual, I assume _use_datastore class variable can be used to configure this behaviour:
class StaticModel(ndb.Model):
_use_datastore = False
userid = ndb.StringProperty()
created_at = ndb.DateTimeProperty(auto_now_add=True)
May I know if above statement is the right solution?
Cheers!
I think there are three ways to achieve what you want.
The first is to set _use_datastore = False on the NDB model class as per your question.
The second would be to pass use_datastore=False whenever you put / get / delete a StaticModel. An example would be:
model = StaticModel(userid="foo")
key = model.put(use_datastore=False)
n = key.get(use_datastore=False)
The third option would be to set a datastore policy in the NDB Context which returns false for any StaticModel keys. Something like:
context.set_datastore_policy(lambda key: True if key.kind() == 'StaticModel' else False)

Python - read with key in App Engine

I have a python program in Google App Engine
When finding an object in the datastore when I have the key as a string, how can I do a direct read. Below is my code which is performing a loop, not good.....
class Opportunity(db.Model):
customer = db.ReferenceProperty(Customer,collection_name='opportunitys')
BNusername = db.StringProperty()
opportunity_no = db.StringProperty()
# etc etc etc.....
#BnPresets holds the object key as a string
opportunitys = Opportunity.all()
opportunitys.filter('BNusername =',BnPresets.myusername)
for oprec in opportunitys:
if str(oprec.key()) == BnPresets.recordkey:
opportunity = oprec
# I have the object here and can process etc etc
You can instantiate db.Key from string by passing it directly to the constructor:
opportunity_key = db.Key(BnPresets.recordkey)
Once you have that, simply db.get to obtain the entity identified by this key:
opportunity = db.get(opportunity_key)
I guess (by looking at the query you use) that you also want to verify the username of the object you got:
if opportunity.BNusername == BnPresets.myusername
process_opportunity(opportunity)
That should be pretty much it. The bottom line is that you should use the key first - as it uniquely identifies your entity - rather than querying for some other property and iterating through results.

Google App Engine - Is this also a Put method? Or something else

Was wondering if I'm unconsciously using the Put method in my last line of code ( Please have a look). Thanks.
class User(db.Model):
name = db.StringProperty()
total_points = db.IntegerProperty()
points_activity_1 = db.IntegerProperty(default=100)
points_activity_2 = db.IntegerProperty(default=200)
def calculate_total_points(self):
self.total_points = self.points_activity_1 + self.points_activity_2
#initialize a user ( this is obviously a Put method )
User(key_name="key1",name="person1").put()
#get user by keyname
user = User.get_by_key_name("key1")
# QUESTION: is this also a Put method? It worked and updated my user entity's total points.
User.calculate_total_points(user)
While that method will certainly update the copy of the object that is in-memory, I do not see any reason to believe that the change will be persisted to the the datastore. Datastore write operations are costly, so they are not going to happen implicitly.
After running this code, use the datastore viewer to look at the copy of the object in the datastore. I think that you may find that it does not have the changed total_point value.

Resources