How to check the existance of single Entity? Google App Engine, Python - python

Sorry for noobster question again.
But I'm trying to do some very easy stuff here, and I don't know how. Documentation gives me hints which do not work, or apply.
I recieve a POST request and grab a variable out of it. It says "name".
I have to search all over my entities Object (for example) and find out if there's one that has the same name. Is there's none, I must create a new Entity with this name. Easy it may look, but I keep Failing.
Would really appreciate any help.
My code currently is this one:
objects_qry = Object.query(Object.name == data["name"])
if (not objects_qry ):
obj = Object()
obj .name = data["name"]
obj .put()
class Object(ndb.Model):
name = ndb.StringProperty()

Using a query to perform this operation is really inefficient.
In addition your code is possibly unreliable, if name doesn't exist and you have two requests at the same time for name you could end up with two records. And you can't tell because your query only returns the first entity with the name property equal to some value.
Because you expect only one entity for name a query is expensive and inefficient.
So you have two choices you can use get_or_insert or just do a get, and if you have now value create a new entity.
Any way here is a couple of code samples using the name as part of the key.
name = data['name']
entity = Object.get_or_insert(name)
or
entity = Object.get_by_id(name)
if not entity:
entity = Object(id=name)
entity.put()

Calling .query just creates a query object, it doesn't execute it, so trying to evaluate is as a boolean is wrong. Query object have methods, fetch and get that, respectively, return a list of matching entities, or just one entity.
So your code could be re-written:
objects_qry = Object.query(Object.name == data["name"])
existing_object = objects_qry.get()
if not existing_object:
obj = Object()
obj.name = data["name"]
obj.put()
That said, Tim's point in the comments about using the ID instead of a property makes sense if you really care about names being unique - the code above wouldn't stop two simultaneous requests from creating entities with the same name.

Related

Using GQL to get all new results since the previous result

I'm pretty useless when it comes to queries, I'm wondering what's the correct structure for this problem.
Clients are sent data including the key of the object, they use the key to tell the server what was the most recent object they downloaded.
I want to get all objects since that point, the objects have an automatic date attribute.
Additionally, I want to be able to give the 15 (or so) most recent objects to new users who may request using a specific 'new user' key or something similar.
Using the Python2.7 runtime, never used GQL before,
Any help is greatly appreciated.
The Model Class is this:
class Message(db.Model):
user = db.StringProperty()
content = db.TextProperty()
colour = db.StringProperty()
room = db.StringProperty()
date = db.DateTimeProperty(auto_now_add=True)
If it is a db.Key object or a string representation of a key using the db (as opposed to the ndb) API:
last_message = Message.get(lastkey)
If you have the key in another representation, such as the key name:
last_message = Message.get_by_key_name(lastkey)
If you have the key as the numeric ID of the object:
last_message = Message.get_by_id(int(lastkey))
Then, you can get the messages since that last message as follows:
messages_since_last_message = Message.all().filter('date >', last_message.date).order('date')
#OR GQL:
messages_since_last_message = Message.gql("WHERE date > :1 ORDER BY date ASC", last_message.date)
You should maybe use the >= comparator only because there may be multiple messages that arrive at the same exact time, and then filter out all messages that are in the list up to and including the last key you are looking for (this actually depends on your use case and how closely message could be written). Additionally, with the High Replication datastore, there is eventual consistency, so your query is not guaranteed to accurately reflect the datastore unless you use ancestor queries, in which case you limit your entity group to ~1 write per second, which again, depending on your use case, could be a non-issue. The Entity Group here reflects the parent model and all of its children ancestors. The group of ancestors resides on a single entity group.

Is it possible to have an entity kind with no property?

I would like to keep a list of 'things' in Datastore. No other information other than their names are required for these 'things', and these names must be unique, i.e. they can be thought as key_name for an entity. In this case, I don't need any explicit property/field for the entity kind (since the name of a 'thing' can be kept inside key_name of an entity). Is this possible? How? The alternative is to replicate this piece of information by having a dedicated field/property for name.
class EntityKindWithNoProperty(db.Model):
name = db.StringProperty()
I feel like this approach is duplication of information. What do you think?
This works
class Empty(ndb.Model):
pass
e = Empty(id="somestring")
e.put()
For uniqueness you can potentially generate the IDs in advance then consume them one by one with numeric keys. Or, depending on your use model, get_or_insert.
Have you considered having a single entity with a list property?
class ThingSingleton(db.Model):
things = db.StringListProperty()
The best approach to use would depend on your query patterns and the expected cardinality of things.

How can I create a new model entity, and then read it immediately after?

My question is, what is the best way to create a new model entity, and then read it immediately after. For example,
class LeftModel(ndb.Model):
name = ndb.StringProperty(default = "John")
date = ndb.DateTimeProperty(auto_now_add=True)
class RightModel(ndb.Model):
left_model = ndb.KeyProperty(kind=LeftModel)
interesting_fact = ndb.StringProperty(default = "Nothing")
def do_this(self):
# Create a new model entity
new_left = LeftModel()
new_left.name = "George"
new_left.put()
# Retrieve the entity just created
current_left = LeftModel.query().filter(LeftModel.name == "George").get()
# Create a new entity which references the entity just created and retrieved
new_right = RightModel()
new_right.left_model = current_left.key
new_right.interesting_fact = "Something"
new_right.put()
This quite often throws an exception like:
AttributeError: 'NoneType' object has no attribute 'key'
I.e. the retrieval of the new LeftModel entity was unsuccessful. I've faced this problem a few times with appengine and my solution has always been a little hacky. Usually I just put everything in a try except or a while loop until the entity is successfully retrieved. How can I ensure that the model entity is always retrieved without running the risks of infinite loops (in the case of the while loop) or messing up my code (in the case of the try except statements)?
Why are you trying to fetch the object via a query immediately after you have performed the put().
You should use the new_left you just created and immediately assign it to the new_right as in new_right.left_model = current_left.key
The reason you can not query immediately is because HRD uses an eventual consistency model, which means you result of the put will be visible eventualy. If you want a consistent result then you must perform ancestor queries and this implies an ancestor in the key on creation. Given you are creating a tree this is probably not practical. Have a read about Structuring Data for Strong Consistency https://developers.google.com/appengine/docs/python/datastore/structuring_for_strong_consistency
I don't see any reason why you just don't use the entity you just created without the additional query.

Model relationship to html template

I've been struggling for this issue for a few hours - I know there's probably a simple solution that I'm overlooking.
I have a one to many relationship with my models.
I have need to return all rows of one object with the rows for the related object.
In a sense I have this:
object
object
object_relationship.property
object_relationship.property
object
object_relationship.property
object
Now - I can run through all of these fine, but I run into an issue when I want to send these back to the html template.
I can send the object back - but how do I send the object_relationship back in the order that I have it above?
Does this make sense?
You might not need to worry too much about this, acutally... look at these models:
class Venue(base.NamedEntity, HasPerformances, HasUrl, HasLocation):
city = db.ReferenceProperty(City, collection_name='venues')
url = db.StringProperty(required=True, validator=validators.validate_url)
location = db.GeoPtProperty()
class Performance(base.Entity):
show = db.ReferenceProperty(Show, collection_name='performances', required=True)
utc_date_time = db.DateTimeProperty(required=True)
venue = db.ReferenceProperty(Venue, collection_name='performances', required=True)
In a case like this, nothing stops you from using venue.performances from either code or templates and treating it as a list. The API will automatically fire queries as needed to fetch the actual objects. The same thing goes for performance.venue.
The only problem here is performance - you've got a variant of the n+1 problem to deal with. There are workarounds, though, like this article by Nick Johnson. I'd suggest reading the API code too... it makes for interesting reading how the property get is captured and dereferenced.
My first suggestion is to denormalize the data if you are going to do many reports like that. For example, maybe you could include object.name on the object_relationship entity.
That said, you could send a list of dicts to your template, so maybe something like:
data = []
for entity in your_query:
children = [{'name': child.name} for child in entity.object_relation]
data.append({'name': object.name,
'children': children,
...
})
Then pass the data list to your template, and process it.
Please note, this will perform very badly. It will execute another query for every one of the items in your first query. Use Appstats to profile your app.

App Engine, Cross reference between two entities

i will like to have two types of entities referring to each other.
but python dont know about name of second entity class in the body of first yet.
so how shall i code.
class Business(db.Model):
bus_contact_info_ = db.ReferenceProperty(reference_class=Business_Info)
class Business_Info (db.Model):
my_business_ = db.ReferenceProperty(reference_class=Business)
if you advice to use reference in only one and use the implicitly created property
(which is a query object) in other.
then i question the CPU quota penalty of using query vs directly using get() on key
Pleas advise how to write this code in python
Queries are a little slower, and so they do use a bit more resources. ReferenceProperty does not require reference_class. So you could always define Business like:
class Business(db.Model):
bus_contact_info_ = db.ReferenceProperty()
There may also be better options for your datastructure too. Check out the modelling relationships article for some ideas.
Is this a one-to-one mapping? If this is a one-to-one mapping, you may be better off denormalizing your data.
Does it ever change? If not (and it is one-to-one), perhaps you could use entity groups and structure your data so that you could just directly use the keys / key names. You might be able to do this by making BusinessInfo a child of Business, then always use 'i' as the key_name. For example:
business = Business().put()
business_info = BusinessInfo(key_name='i', parent=business).put()
# Get business_info from business:
business_info = db.get(db.Key.from_path('BusinessInfo', 'i', parent=business))
# Get business from business_info:
business = db.get(business_info.parent())

Categories