sqlalchemy- three entities joined via one table - python

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.

Related

Is "user_id" a preset keyword in the Flask session library?

I'm keeping track of people registering for my site by using tables in a SQL database. I have a 'users' table in which there is a column, 'id'. I'm keeping track of people with this.
It seems that if I want to assign someone's id to a variable I have to do this inside flask:
user_id = session["user_id"]
Even though I don't have any variables called 'user_id' in my table. But, it is working. So, is 'user_id' some pre-made keyword that somehow knows the id of the user?
How does it know the right id? Is it looking inside my database to find the correct id for that user?
I tried using session["user_id"] and it actually gave the right number. But, I don't know how it works because I'm keeping track of peoples' ids manually.

Is there a way to standardize the business datatypes across all systems in organization?

Can we do a loosely coupled data access layer design in python?
Lets say,in a scenario i have an oracle table with column name ACTIVITY_ID with column datatype as Number(10). If this column is a foreign key in lot many tables,to hold the data of this column, can i create something like ACTID class (like a java object) and can be used across the code if i want to manipulate/hold the ACTIVITY_ID column data so that i could maintain consistency of business object columns. Is there any such possibility in python ?
Try Django
As I understand it, Python does not natively have any database functionality. There are many different libraries/frameworks/etc. that can be used to provide database functionality to Python. I recommend taking a look at Django. With Django, you create a class for each database table and Django hides a LOT of the details, including allowing using with multiple database engines such as MySQL and PostgreSQL. Django handles Foreign Key relationships very well. Every table normally has a primary key, by default an auto-incremented id field. If you add a field like activity = models.ForeignKey(Activity) then you now have a foreign key field activity_id in one table referencing the primary key field id in the Activity table. The Admin page will take care of cascading deletion of records if you delete an Activity record, and in general things "just work" the way you might expect them to.

Google App Engine, set entity id to null string

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.

Python IRC bot + SQLAlchemy - track users in multiple channels

I'm currently storing IRC users in a dictionary, using their nickname as the 'key' for easy retrieval. The users are retrieved from SQLAlchemy, so users['deepy'] is an SQLAlchemy object which I regularly sync with my database.
Now the problem I have is that on IRC, people can be in many channels and I'm just keeping track of one. I need a suggestion on how to improve this.
I've been thinking about doing pretty much the same, but also storing the channel's users (as a list) in a dictionary with the channel names as key, so like:
{ '#two': ['reference to user9', 'reference to user62'], '#one': ['reference to user1', 'reference to user2'] }
The references being to the users dictionary which contains the SQLAlchemy object.
Is that a sensible approach?
I am using Python 2.7, PostgreSQL, SQLAlchemy and Twisted's irc.ircclient.
I've found that it's best to store as few SQLALchemy objects as possible. Storing a ton of SQLAlchemy objects leads to having to worry about synchronization issues and uses up memory.
I would keep track of usernames or user ids instead of actual user objects:
{ '#two': ['bob1', 'tom2'], '#one': ['bob1', 'mary1'] }
Then whenever I needed information for a user I would fetch them from the database. If I had only a few users and needed to access them frequently then I would create a dictionary that mapped usernames to SQLAlchemy user objects.

Is there a way to set all db queries to only retrieve a given user's entries, or would each query throughout the app have to include "AND user..."?

I created an app that lets users input products and compare them. I am at the point where i need to consider scaling and multiple users, and I want to only show users the items that they've created (instead of the entire db, which may be an option at some point, but for now each user has to create their own lists).
Is there a canned/preferred way of making all queries throughout an app only return entries with the "author" field set to a certain user, the logged in user? Or does every query have to be updated with "AND author..." type filter? Is this what namespaces are for?
I'm using Python on Google App Engine.
I would suggest looking into namespaces, it is exactly the type of use-case they are well suited for.
One note, if you want to be able to query users all users' products, you may be better off adding an owner property and using query filters. You can't currently query across namespaces -- only within a single namespace at one time.

Categories

Resources