Ex.
Entity(id='', parent=user_key)
When I try to create an entity with the null string as the id, Google App Engine interprets it as having no id, and defaults to an automatically generated integer id.
I've also tried creating the key beforehand, and passing it in.
key = ndb.Key('User', user_key.id(), 'Entity', '')
Entity(key=key)
The same issue occurs.
Is there any way to work around this behavior and use the null string as the entities id?
Edit:
Since everyone seems to be wondering why I would want to do this. Imagine a situation like stackoverflow where a user can upvote and downvote a question. You want the user to only have one vote per question. So it's natural to manually set the id of the vote entity to the key of the question. Combined with a user parent, this ensures that there is one per user per question. The twist here is that I have a special case where a user can have one of this entity that belongs to nothing other than the user. The matter is further complicated by the fact that the key for the entity that it usually belongs to is tied to a user submitted string. So, if I use anything but the null string for this special case, there is a security issue where the special case could collide with another entity.
If you want to ensure that there is only one entity of this kind per parent entity, set the ID to 1:
Entity(id=1, parent=user_key)
Id must be unique, so using null is not a good idea, because you'll be able to store only one entity. Id must be not null, or it will be automatically generated.
Related
I have the following entities, each of which is a table in my database:
User
Application
Role
I have another table called "user_app_role" which looks like this:
table user_app_role(
user_id int not null ,
application_id int not null,
role_id int not null,
primary key(user_id, application_id, role_id)
)
where user_id, application_id, and role_id are all foreign keys on the user, application, and role tables.
An entry in that table indicates that the user has a particular role within a particular application, so a row might return 1, 1, 1 indicating that user 1 has role 1 within application 1. similarly, 1, 2, 1 would mean that user 1 also has role 2 within application 1.
I have sqlalchemy mappings defined for User, Application, and Role. What I would like is for the User object to somehow have a list of Application objects and for each Application object, that object would contain a list of Role objects.
From reading the documentation for sqlalchemy, it appears this type of relationship is impossible to map and I have found only a few other questions on stackoverflow where this has been asked, none of which have an answer. This seems like a relatively normal 3NF database relationship (I have 4 of them in my whole data model), is it possible to somehow set this up in sqlalchemy? I could do this whole thing in pure SQL in about 10 minutes but I don't want to throw away all the other useful feature of SqlAlchemy but if I can't make this somehow work, then my application will not be able to ship.
Also, PLEASE DO NOT suggest that just I alter my data model or denormalize the database or otherwise mess with that in any way. Answers of that nature will not help me. I'm happy to change my object model or add additional objects if I need to somehow magically map this one table to 2 objects or something weird like that but I am not able to change the data model.
Ok as far as I can determine, creating an actual mapping for this scenario is impossible in SqlAlchemy so here is my workaround:
class UserAppRole(Base):
__tablename__ = 'userapprole'
user_id = Column(stuff, ForeignKey(users.id))
role_id = Column(otherstuff, ForeignKey(roles.id))
app_id = Column(morestuff, ForeignKey(apps.id))
I've decided that in my application's domain, a User has roles with applications, so the relationship for this new object is going to be on the User:
class User(Base):
__tablename__ = 'users'
approles = relationship(UserAppRole, backref=backref('app_user_role', uselist=True))
# other columns, relationships, etc.
This works well, because when I load a user I want to know what applications they have access to in any way and I want to know what roles they have for those applications. In my domain, a Role is a thing and an Application is also a thing, and there are relatively few of those things and they tend not to change (although that isn't a requirement for this solution). What's important is that I can load Application and Role objects by their ID, which conveniently enough I now have in my approles list in my User object.
To bind this all together, the last thing I do is use a repository to handle persistence for my User objects. When I load a User, SqlAlchemy will populate the approles list with ID's. I can then manually load the applications and roles and build a dictionary for applications with a list of roles. Now when I add a role for a user to an application, I need to pass in the Application object (which knows what roles are valid) and a Role object (which may or may not be valid for that application). Both of those will have ID's, so it's pretty trivial for me to update the dictionary and/or approles list to contain what I want. In the unlikely event that I attempt to write to the DB with a role id or app id that doesn't exist, then the constraints in my database will reject the insert/update and I'll get an exception.
It's not my ideal solution, but it works quite well for the two situations that I'm encountering this. If anyone has a better solution though, please post it. I feel like composite adjacency lists ought to be useful for this scenario but the current SqlAlchemy documentation seems to indicate that these have to be for self-referencing tables and I haven't found a way to make this work for this particular scenario.
I have this special case, where a customer requires a specific (legacy) format of booking numbers, the first one starts with the current year:
2015-12345
So basically every year I would have to start from 0
The other one is starting with a foreign-key:
7-123
So the first document created by every the user gets number 1, and so on.
Unfortunately there will be long lists starting with this booking number, so fetching all the records and calculating the booking number is not really an option. I have also thought about overriding the save() method, reading and auto-incrementing manually, but what about simultaneous inserts?
The best and most reliable way to do this is with a sql trigger That would completely eliminate the worries about simultaneous inserts. But overriding the save method is also perfectly workable.
Explicitly declare a primary key field and choose integer for it. In your save method if the primary key is None that means you are saving a new record, query the database to determine what should be the new primary key, asign it and save. Wherever you call your save method you would need to have a atomic transaction and retry the save if it fails.
BTW, you are starting for 0 each year. That's obviously going to be leading to conflicts. So you will have to prefix your primary key with the year and strip it out at the time you display it. (believe me you don't want to mess with composite primary keys in django)
I want to save Entries in my database such that I can delete them later. To identify them, i put the key attribute in my class Entry in models.py as shown below:
class Entry(models.Model):
name = models.CharField(max_length=200)
key = models.IntegerField(unique=True,default=0)
Every time I start the server, I will find the biggest key that is in Entry.objects.all().
Every time I create the first new Entry after starting the server, I want to take the key I found in the very beginning, increase it by 1 and then set this as the key for my new Entry. For every subsequent Entry, I will just take the key of the previous element, increase it by 1 and. set it as the key for my new Entry
However, before I do this, I want to know what Django considers as unique. For example, if i added three entries initially with keys 1, 2 and 3, and then I delete the last element with key 3. If I then restart the server, the biggest key I will find is 2 and the next Entry I will add will have key 2+1 which is equal to 3 again.
Is this key unique?
It was entered before but I deleted that element right? So is uniqueness determined by whatever I entered in the past or just depending on the elements currently in the database?
Also, does Django keep a track of all the instances of Entry that I added, so that it would somehow know if I added an Entry with key 3 before?
Note that my data is stored in a file called db.sqlite3
Thank you.
Seems like you are looking for something that already exists; models have an id field by default which is unique and monotonic (newer entries have bigger id).
None of this has anything to do with Django at all. This is pure database stuff: unique constraints are handled exclusively by the database, in your case SQLite, although the functionality is exactly the same for other DBs as well.
Of course, a unique constraint only takes into account rows that actually exist: what would be the point otherwise?
There are other things to bear in mind with your proposal as well. In particular, there is the issue of race conditions: if you do a query to get the maximum key value, and then create a new row with key+1, you run the risk of another user in the meantime adding their own row at key+1. Much better, as Iris and ryanageles suggest, to use the built-in primary key which is already automatically defined as the id field.
try to add primary_key=True in your key field.
I think I read something about a function appengine has that can tell whether an ID / key you want to use for an entity is available, or if there was a function to get an available ID to choose. App engine team said also that we should set the ID when the entity is created and not change it. But in practice we can just copy everything to a new entity with the new ID?
Thanks!
Update
I think the function I'm looking for is allocateIDs from the docs:
http://code.google.com/appengine/docs/python/datastore/functions.html
To reserve one or more IDs, use allocate_ids(). To check whether an ID is already taken, just construct a Key for it using Key.from_path(kind, id) and try to db.get() it. Also note that IDs for keys with a parent are taken from separate pools and are only unique among keys with the same parent.
On the page describing transactions, a use case is presented where the entity in question, a SalesAccount is updated, or if the account doesn't exist, it is created instead. The technique is to just try to load the entity with the given key; and if it returns nothing, create it. It's important to do this inside a transaction to avoid the situation where two users are both racing for the same key, and both see that it doesn't exist (and both try to create it).
I'm building a facebook app, and my users table's keyName is set to the Uid of the facebook user. I found this to be efficient because I can use db.Key.from_path() to efficiently query the datastore for a particular user instead of doing a query (where uid = x, limit = 1). This is actually my first time using key names.
But when I did this in the sdk, the key().id() is set to None. Is there a way have an id as well?
I'd like an id for use as a primary key is because it's shorter and an integer which makes it faster when I'm storing users in a listProperty (i.e a seperate Buddies entity with a list of friends the user has in the app).
I hope this makes sense :)
thanks a ton!
No. An entity's Key is composed of the application ID, the Kind, the path of the parent entity (if any) and either a key name or an auto-generated ID. It's not possible to have both. The entire Key is the "primary key".