Passing an instance as a parameter for a foreign key reference - peewee

When I pass an instance of a model to a query for use as the fk ref, I have seen some syntax where the instance itself is suitable but in my repro it fails.
for example:
model_a = ModelA(name='bar')
model_a.save()
Model_b.get_or_create(name='foo', model_a_id=model_a)
# versus
Model_b.get_or_create(name='foo', model_a_id=model_a.get_id())
What base model feature enables the first syntax?
I am using peewee v2.7.4.

Have you tried just assigning the model instance to the foreign-key name?
Model_b.get_or_create(name='foo', model_a=model_a)
If all you have is an integer ID for model_a, the above should also work.

Related

How NamespaceManager and Query by key works together in objectify

I have two organisation in my datastore inside their own namespace. Lets say organisation1 present inside namespace1 and organisation2 present inside namespace2. I am retrieving organisation by its web-safe-key. lets say that web-safe-key of organisation1 is orgWebSafeKey1 and web-safe-key of organisation2 is orgWebSafeKey2. I am using following code to get an organisation:
NamespaceManager.set("namespace1");
Organisation organisation = (Organisation) ofy().load().key(Key.create(orgWebSafeKey1)).now();
above code works as I expected because organisation1 is present inside namespace1 and I am trying get that organisation in its namespace.
But if I just change the websafekey of the organisation then according to my expectaion below query should result "null" organisation because there is no organisation with key orgWebSafeKey2 inside namespace1. But practically it is giving me organisation2.
NamespaceManager.set("namespace1");
Organisation organisation = (Organisation) ofy().load().key(Key.create(orgWebSafeKey2)).now();
If the above query result is correct and expected according to objectify and datastore then can I assume that query by key works globally , across all the namespaces?
I also want confirmation that in this case Key.create(orgWebSafeKey2) will not change the namespace of the key? and query is running according to the namespace of the key not by NamespaceManager.set("namespace1")?
A Datastore Key contains the following components:
Project/App ID
Namespace
Entity Path (Ancestor Kind + ID/Name(zero or more), Final Entity Kind + ID/Name)
Since namespace is part of the key, lookup of an entity by Key always finds the right entity regardless of the namespace set by the NamespaceManager. In other words, a Key is a GUID that uniquely identifies an entity across all apps/projects.
Refer to the below link for more details/answers for your questions:
https://cloud.google.com/appengine/docs/java/multitenancy/multitenancy#Java_Using_namespaces_with_the_Datastore

auto increment field in Peewee

Is there a way to define autoincrement Field in peewee.
I understand we could define sequence but the need to create the sequence manually and not managed by create_tables deters me from using it. ( The build process is managed by create tables and I would prefer not to add manual steps )
import peewee
class TestModel(peewee.Model):
test_id = peewee.BigIntegerField(sequence='test_id_seq')
Alternate to the above code I would rather have. As most databases have serial field I dont see a point maintaining a sequence.
import peewee
class TestModel(peewee.Model):
test_id = peewee.AutoIncremenetIntField()
Either you can use PrimaryKeyField() as #wyatt mentioned in comment
or you can use Playhouse- Signal Support (peewee extensions)
from playhouse.signals import Model, pre_save
class MyModel(Model):
data = IntegerField()
#pre_save(sender=MyModel)
def on_save_handler(model_class, instance, created):
# find max value of temp_id in model
# increment it by one and assign it to model instance object
next_value = MyModel.select(fn.Max(MyModel.temp_id))[0].temp_id +1
instance.temp_id = next_value
The given answers here are outdated but this was still my first Google search result.
Peewee has a special field type for an auto incrementing primary key called AutoField:
The AutoField is used to identify an auto-incrementing integer primary
key. If you do not specify a primary key, Peewee will automatically
create an auto-incrementing primary key named “id”.
Take a look at the documentation. Example usage:
class Event(Model):
event_id = AutoField() # Event.event_id will be auto-incrementing PK.

Model Table CakePHP 3 using existing table

Hi need your help to understand some feature in CakePHP.
I have a SQL Table : user.
I generate with bake the Model : UserTable.
In the action home() of my UsersController, i have this :
$t_Results = TableRegistry::get('User')->findByLogin('jdupont')->execute()->fetchAll('assoc');
debug($t_Results);
The query is generated by Cake and this code works well.
My question are :
Must i create the function findByLogin inside the Model or not ?
Is my code correct ?
Thanks for the help ;)
Yes you can create a findByLogin in your model but you don't have to.
Your code works but doesn't respect conventions.
In CakePHP 3
SQL tables are singular lowercase,
Table files has upper first letter and plural suffixed by Table,
Controllers are plural first letter upper and suffixed by Controller.
If you follow these conventions in your controller you can do this:
$t_Results = $this->Users->findByLogin('jdupont')->execute()->fetchAll('assoc');
debug($t_Results);
You don't have to use ->execute(). Query objects are lazily evaluated, execute will be called when you will use the request.
One of the quickest ways for you to check if your code is correct is to actually run it and see if it returns what you expect.
findByLogin() is a Cake dynamic finder so you don't need to define this method as Cake dynamically does this for you. You can prefix any camel-cased column name with findBy to query a table using that column.
You can use it like this:-
$t_Results = $this->Users->findByLogin('jdupont')->first();

How to use ndb key with integer_id?

I see the document
https://developers.google.com/appengine/docs/python/ndb/keyclass#Key_integer_id
Returns the integer id in the last (kind, id) pair, or None if the key
has an string id or is incomplete.
see I think the id of a key can be a int ; so I write
r = ndb.Key(UserSession, int(id)).get()
if r:
return r.session
but the dev_server.py , will always raise
File "/home/bitcoin/down/google_appengine/google/appengine/datastore/datastore_stub_util.py", line 346, in CheckReference
raise datastore_errors.BadRequestError('missing key id/name')
BadRequestError: missing key id/name
I chanage the int(id) -> str(id)
seems right ;
so my question is , How to use ndb key with integer_id ?
the model is
class UserSession(ndb.Model):
session = ndb.BlobProperty()
The type of the id you use when reading the entity must match the type of the id you used when you wrote the entity. Normally, integer ids are assigned automatically when you write a new entity without specifying an id or key; you then get the id out of the key returned by entity.put(). It is generally not recommended to assign your own integer ids; when the app assigns the keys, the convention is that they should be strings.
There's an easier way to fetch:
UserSession.get_by_id(int(id))
https://developers.google.com/appengine/docs/python/ndb/modelclass#Model_get_by_id
If that doesn't work, I suspect that id is wrong or empty.
There must be something wrong with your variable 'id'.
Your code here should be no problem, and it's better to user long instead of int.
You can try your code on interactive console of development server with specific integer id.
It may be easier to identify your entities in the sessions with their keys instead of their ids. There really is no need to extract the ID from the key to identify the session (other than maybe saving a bit of memory. I think the way your thinking is based on a RDB. I learned that using the key actually makes entity/session identifications easier.
'id' is also a python builtin function. Maybe you are taking that by mistake.

ndb retrieving entity key by ID without parent

I want to get an entity key knowing entity ID and an ancestor.
ID is unique within entity group defined by the ancestor.
It seems to me that it's not possible using ndb interface. As I understand datastore it may be caused by the fact that this operation requires full index scan to perform.
The workaround I used is to create a computed property in the model, which will contain the id part of the key. I'm able now to do an ancestor query and get the key
class SomeModel(ndb.Model):
ID = ndb.ComputedProperty( lambda self: self.key.id() )
#classmethod
def id_to_key(cls, identifier, ancestor):
return cls.query(cls.ID == identifier,
ancestor = ancestor.key ).get( keys_only = True)
It seems to work, but are there any better solutions to this problem?
Update
It seems that for datastore the natural solution is to use full paths instead of identifiers. Initially I thought it'd be too burdensome. After reading dragonx answer I redesigned my application. To my suprise everything looks much simpler now. Additional benefits are that my entities will use less space and I won't need additional indexes.
I ran into this problem too. I think you do have the solution.
The better solution would be to stop using IDs to reference entities, and store either the actual key or a full path.
Internally, I use keys instead of IDs.
On my rest API, I used to do http://url/kind/id (where id looked like "123") to fetch an entity. I modified that to provide the complete ancestor path to the entity: http://url/kind/ancestor-ancestor-id (789-456-123), I'd then parse that string, generate a key, and then get by key.
Since you have full information about your ancestor and you know your id, you could directly create your key and get the entity, as follows:
my_key = ndb.Key(Ancestor, ancestor.key.id(), SomeModel, id)
entity = my_key.get()
This way you avoid making a query that costs more than a get operation both in terms of money and speed.
Hope this helps.
I want to make a little addition to dargonx's answer.
In my application on front-end I use string representation of keys:
str(instance.key())
When I need to make some changes with instence even if it is a descendant I use only string representation of its key. For example I have key_str -- argument from request to delete instance':
instance = Kind.get(key_str)
instance.delete()
My solution is using urlsafe to get item without worry about parent id:
pk = ndb.Key(Product, 1234)
usafe = LocationItem.get_by_id(5678, parent=pk).key.urlsafe()
# now can get by urlsafe
item = ndb.Key(urlsafe=usafe)
print item

Resources