I'm thinking to create a property which store the key or the ID of the other entity as a reference to the entity.
I want to know two things.
1. Which data should the property store, the key or the ID?
2. What should the type of the property be? maybe StringProperty?
The Datastore has a special property type for this: ReferenceProperty. There are two ways to use it.
One:
someothermodel = db.ReferenceProperty()
Two:
someotherspecificmodel = db.ReferenceProperty(SomeModel)
In example 2, only models with the type of SomeModel can be assigned, in example one, any model can be assigned.
The value type of ReferenceProperty is db.Key.
Related
How can we access a property value within a #classmethod? For example:
class Account(polymodel.PolyModel):
someprop = ndb.StringProperty(required=True)
#classmethod
def get_or_create_someprop(cls):
if not cls.someprop:
# create someprop
else:
return cls.someprop
In this example code above, I am trying create someprop if it doesn’t exist, or return it if it already exists. I assumed that the above code would achieve this. However, the first step I need to do is access the someprop value from within the classmethod. Using cls.someprop does not actually return the value of someprop but instead returns StringProperty('state').
I have tried to use this and self which are undefined.
So, is it possible to access a property value of an entity using a classmethod? If so, how?
In general you cannot do this from a class method because a property belongs to an object, i.e. an instance of the class (the class is just the object generator). In other words you need the self argument to refer to the object and its properties.
In your particular case the class is an entity model (the blueprint for creating entities), not an entity and you can only refer to a property of an entity itself.
But you should be able to achieve what you seek simply by not declaring it a class method - then it becomes a method of the object/entity and in that case you can reference the entity's property via self instead of cls: self.someprop.
I'd make the check a bit more specific, though, to cover the case in which the property has a value like 0 or an empty string which is interpreted by python as False in a logical check: if self.someprop is None instead of if not self.someprop.
I'm using eloquent relationships.
When I call $carcollection = $owner->cars()->get(); I have a collection to work with. So let's say that I have, for this particular owner, retrieved three cars. The collection is a collection of three arrays. Each array describes the car.
This is all working fine.
Now I want to add more attributes to the array, without breaking the collection. The additional attributes will come from a different source, in fact another model (e.g. servicehistory)
Either I retrieve the other model and then try merge() them, or I try manipulate the arrays within the collection without breaking the collection.
All this activity is taking place in my controller.
Is one way better than another, or is there a totally different approach I could use.... perhaps this logic belongs in the model themselves? Looking for some pointers :).
Just to be specific, if you do $owner->cars()->get(); you have a collection of Car Models, not array.
That have been said, you can totally load another relation on you Car model, using
$carcollection = $owner->cars()->with('servicehistory')->get();
$carcollection->first()->servicehistory;
You can try to use the transform method of the collection.
$cars = $owner->cars()->get();
$allServiceHistory = $this->getAllService();
$cars->transform(function($car) use($allServiceHistory) {
// you can do whatever you want here
$car->someAttribute = $allServiceHistory->find(...):
// or
$car->otherAttribute = ServiceHistoryModel::whereCarId($car->getKey())->get();
});
And this way, the $cars collection will be mutated to whatever you want.
Of course, it would be wiser to lazy load the data instead of falling into an n+1 queries situation.
I have a SportsCentre class which contains an array of Employee objects.
Which is the right way to show that an attribute's data type is an array of objects?
I have found two different versions online:
the first one uses the ArrayList<> keyword:
SportsCentre
- listOfRegistered : ArrayList<Employee>
getRegisteredList() : ArrayList<Employee>
the second one uses square brackets []:
SportsCentre
- listOfRegistered : Employee[0..*]
getRegisteredList() : Employee[0..*]
Both are correct, but the second one, when multiplicity is set to more than one, is used more naturally, and it is not necessary to define the collection class as it is shown in the first picture of your example.
Simply said, multiplicity defines how many instances of a specific type can be stored by attribute. This set of instances can be ordered, or duplicates in it may be allowed. Parameters of multiplicity elements have an impact on the type of collection which should be used, Set, Vector, Array, etc.
But, if you need precise info about this issue, read UML Superstructure. Search for Property and Multiplicity Element. here is the UML website
I pass an NDB Key() with a parent to a deferred function. In this function I retrieve the entity again. But I cannot use the passed key to get the entity directly. I have to change the key order pairing in the ndb.Key().
deferred.defer(my_deferred.a_function, entity.key)
The entity.key() looks like :
Key('Parents', 'my_parent', 'Childs', 'my_child') # the first pair is the parent?
my_deferred.py :
def a_function(key) :
entity = ndb.Key(key) # the pass entity.key does not work !!!!!
Giving exception : ValueError: Key() must have an even number of positional arguments.
entity = ndb.Key('Childs', key.id(), parent = key.parent()).get() # this one works fine
I do not understand why the entity.key() method does not give me a key, which I can use directly? Or is there another way to get the entity, without "changing" the key. And I do not understand the ValueError excpetion.
Update : Thanks to Gregory
entity = key.get() # works fine
first, answering your code specific question, passing the key properly, it is not a callable:
deferred.defer(my_deferred.a_function, entity.key)
next, on the actual design of the code itself, there are some things that need tweaking.
the deferred api serializes your code, so there really is no need to re-query entity from the datastore. if you insist on this though, passing the entity.key to the deferred method, it's already an instance of ndb.Key, so there's no need to construct a new Key object.
I can't test this right now, but what about:
entity = ndb.Key(*key.flat())
The Key constructor accepts a few different kinds of input, and since flat() Returns a tuple of flattened kind and id values (kind1, id1, kind2, id2, ...)., unpacking the tuple should pass in the necessary inputs . Per the same link, this should also work:
entity = ndb.Key(pairs=key.pairs())
I have this code to find all the nodes where property branches is empty.
nobranches=TreeNode.all()
for tree in nobranches:
if tree.branches==[]:
I wanted to find a better, more efficient way to do this. A meathod where I don't have to retrieve all the TreeNodes. I have tried TreeNode.all().filter(branches=[]) but this gives me a message, "BadValueError('Filtering on lists is not supported'" . How can I do something like TreeNode.gql('WHERE branches=:1', []).fetch(100). I tried this, but I get a "BadValueError: May not use the empty list as a property value; property is []". Is there any other efficient way?
BTW, Here is what TreeNode looks Like
class TreeNode(db.Model):
name = db.StringProperty()
branches =db.ListProperty(db.Key)
You can't do this with a filter: as Saxon says, there's no index row matching what you want to retrieve, and so no way to retrieve it.
One simple alternative is to store another property that contains the number of elements in the list, and filter on that. aetycoon is a library that contains computed properties that may help with that:
class TreeNode(db.Model):
name = db.StringProperty()
branches = db.ListProperty(db.Key)
branch_count = aetycoon.DerivedProperty(lambda self: len(self.branches))
The documentation on how indexes are stored says:
For multi-valued properties, such as ListProperty and StringListProperty, each value has its own index row, so using multi-valued properties does result in more indexing overhead.
So for each item in your list property, there is a row in the index.
My expectation would be that if there are no items in the list property, then there would be no rows in the index. So it wouldn't be possible to use the index to retrieve entities with an empty list.
One solution would be to add another property (eg hasbranches = db.BooleanProperty()), which you maintain when you add or remove branches. Then you will be able to filter for hasbranches = False.