ndb Singleton Pattern - python

I'm doing an online store in appengine, and I'm creating a model that will hold the settings of the store in the db, the code looks something like this:
class StoreSettings(ndb.Model):
name = ndb.StringProperty()
homepageTitle = ndb.StringProperty()
metaKeywords = ndb.StringProperty()
metaDescription = ndb.StringProperty()
timezone = ndb.IntegerProperty()
currency = ndb.StringProperty()
Is there an easy way to make the StoreSettings class to be a singleton?
Thanks

When you initialize your settings you can provide a key_name, then when you have to retrieve it you can use get_or_insert method. If it doesn't exist it will create it otherwise it will retrieve it.
settings_db = StoreSettings.get_or_insert(
'my_settings',
name='yourname'
....
)
Or if you create the object when your application starts then you can just get it by the key name
settigns_db = StoreSettings.get_by_id('my_settings')

Keep the same key? whenever you push an entity in the datastore, it needs a key.
If you create a second object with the same key, it ends up over-writing the previous entity.

Related

Query statement in get_by_id (ndb, GAE)

I'm using Google App Engine with webapp2 and Python.
I have a User model with a deleted field:
class User(ndb.Model):
first_name = ndb.StringProperty()
last_name = ndb.StringProperty()
email = ndb.StringProperty()
deleted = ndb.BooleanProperty(default=False)
I'd like to get a User object by calling User.get_by_id() but I would like to exclude objects that have deleted field True. Is it possible to do this with the normal get_by_id() function?
If not, could I override it?
Or should I create a custom class method, smth like get_by_id_2() that does a normal .get() query like this: User.query(User.key.id()==id, User.deleted==False).get()?
Would you reccomend something else instead?
A query is significantly slower than a get, and is subject to eventual consistency. You should probably use the normal get_by_id and check deleted afterwards. You certainly could wrap that up in a method:
#classmethod
def get_non_deleted(cls, id):
entity = cls.get_by_id(id)
if entity and not entity.deleted:
return entity

Foreign Key in NDB/Google App Engine

I am building a web app with Google Endpoints and the Datastore using NDB in Google App Engine. Each user that signs in has a set of "watched listings" that is just a repeated property in the expando model of NDB like this:
class user(ndb.Expando):
username = ndb.StringProperty()
email = ndb.StringProperty()
password = ndb.StringProperty()
overallRanking = ndb.IntegerProperty()
numRankings = ndb.IntegerProperty()
watchedListings = ndb.KeyProperty(modelListing,repeated=True)
As you can see, I am storing the key of modelListing entities. However, when I delete a modelListing, I want it to automatically delete the key for all of the users that have that key in their watchedListings object. This is similar to how SQL would handle a foreign key. Is there a way to do this without going through all the users in the database and searching for that key, deleting it, and executing a put()?
I did to try this feature yet. It looks like you can do the job using:
https://developers.google.com/appengine/docs/python/ndb/entities?hl=nl#hooks

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.

Google App Engine return object with reference set

Hi I am kind of trying to get the concept behind DataStore as a No-SQL database, what I am trying to fetch is a list of object wich have been "reference" by another. As this
class Person(db.Model):
name = db.StringProperty(required=True)
class Contact(db.Model):
name = db.StringProperty(required=True)
email = db.StringProperty()
trader = db.ReferenceProperty(Person)
This works fine and they get to be saved when I use person.put() without any problem. But when I try to retrieve it and encoded as json it nevers shows me the contact as a list in fact it totally ignores it.
persons_query = Person.all()
persons = persons_query.fetch(50)
data = json.encode(persons)
I would expect person to have a collection of Contact but it doesn't any ideas on how to solve this problem?
To make it clearer currently i am getting something like this:
[
{
name: "John Doe"
}
]
I would like to be
[
{
name: "John Doe"
contacts: [{name:"Alex", email:'alex#gmail.com'}]
}
]
Edit
Thanks all you were right I needed to fetch the collection of contacts there was only one issue for this is that when Contact was being encoded it recursively tried to encode the Trader object and this it's contact and so on.
So I got an obvious error recursive error, the solution to this was clearly to remove the trader object from the Contact when it's being encoded.
Make a custom toJson function in your class
class Person(db.Model):
name = db.StringProperty(required=True)
def toJson(self):
contact = self.contact_set #this is the default collection name for your class
d = {"name":self.name,"contact":contact}
return json.dumps(d)
class Contact(db.Model):
name = db.StringProperty(required=True)
email = db.StringProperty()
trader = db.ReferenceProperty(Person)
then you may do the ff:
persons_query = Person.all()
persons = persons_query.fetch(50)
data = person.toJson()
To fetch all the contacts you will need to write a custom json encoder, which fetches all of the reverse of the reference property.
ReferenceProperties automatically get a reverse query. From the docs "collection_name is the name of the property to give to the referenced model class. The value of the property is a Query for all entities that reference the entity. If no collection_name is set, then modelname_set (with the name of the referenced model in lowercase letters and _set added) is used."
So you would add a method to resolve the reverse reference set query.
class Person(db.Model):
name = db.StringProperty(required=True)
def contacts(self):
return self.contact_set.fetch(50) # should be smarter than that
Then use it in your custom json encoder.
If you want to find all the contacts that include a person you will need to issue a query for it.
contacts = Contact.all().filter("trader =", person)

AppEngine Python getting all references

My problem is simple. I have Model_A and Model_B:
class Lobby(db.Model):
name = db.StringProperty()
class UserModel(db.Model):
name = db.StringProperty()
lobby = db.ReferenceProperty(Lobby, collection_name="lobby")
Now I fetch a/all Lobby entities from the Storage, and I want to access the related users for each Lobby. I can not do that by calling lobby_entity.aUsers.
How is this achieved?
Using GQL:
lobbies = Lobby.all().fetch(10)
keys = [lobby.key() for lobby in lobbies]
q = aUser.gql('WHERE lobby IN :1', keys)
users = q.fetch(1000)
Note that this doesn't work well if you have a lot of lobbies; the IN query only supports up to 30 values. (https://developers.google.com/appengine/docs/python/datastore/gqlreference)
PS. Please don't start model class names with a lowercase letter. Check out PEP 8.

Categories

Resources