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.
Related
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.
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.
I am starting an App Engine application.
I started defining some simple models I will need.
I want to write tests for my application (that would be the first time I've done that).
I cannot see what I should be testing for.
I already looked to how to do this (https://developers.google.com/appengine/docs/python/tools/localunittesting), but I just don't know what to test...
Here is my code so far:
class User(db.Model):
email = db.EmailProperty()
name = db.StringProperty()
class Service(db.Model):
name = db.StringProperty(required=True)
class UserService(db.Model):
user_id = db.ReferenceProperty(User,
required=True,
collection_name='user_services')
service_id = db.ReferenceProperty(Service,
required=True)
access_token = db.StringProperty(required=True)
refresh_token = db.StringProperty(required=True)
class LocalServer(db.Model):
authentication_token = db.StringProperty(required=True)
class Task(db.Model):
user_service_id = db.Reference(UserService,
required=True,
collection_name='tasks')
local_server_id = db.ReferenceProperty(LocalServer,
required=True,
collection_name='tasks')
creation_date = db.DateTimeProperty(auto_now_add=True,
required=True)
completion_date = db.DateTimeProperty(required=True)
number_of_files = db.IntegerProperty(required=True)
status = db.StringProperty(required=True,
choices=('created', 'validated', 'in_progress', 'done'))
Quoting Wikipedia:
Intuitively, one can view a unit as the smallest testable part of an application.
Now, I don't know exactly what your application is supposed to do, but in general you don't have to test each specific class/model. What does this mean? Well, you don't need to test a feature like this: "what happens when I add two users, and then I want to filter them by a specific name?". You don't have to test it, because in that case you would test a GAE function, .filter(). Now, why should you test it? :) Google pays its developers for that!
But what if you write a "filter" method? What if you customize the filter() method? Then you must test them.
I suggest you to read this answer. The question is about Django models, but actually it is valid for every framework or programming language.
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)
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.