I have a Django app which has a single-account model. We are converting this to be multi-account, so almost every model will have a ForeignKey(Account)
.
What is the easiest way to make sure that each Account
(each account is in its own subdomain) can only access its own data? We have a middleware that populates the subdomain, and the current account on each request.
We can do this the hard way, by adding a filter(...., account = request.account)
in all of our views. This is not desirable as,
filter(...., account = request.account)
will be added to all of the queries, making this non-dry, repetative and error-prone.- Bigger risk is if there is a missing filter, anywhere it is security risk.
Wow, I'm having the exact same problem. Here's the best answer I got:
Django: How would one organize this big model / manager / design mess?
Are you using
django.contrib.auth
?If you are, just make Account a
ForeignKey(User, unique=true)
and point all your models at Userie.
ForeignKey(User)
Also, Take a look at the django Auth Docs
edit: I think I understand your concern a little better now...
Instead of doing
just do:
This snippet might put you in the right direction. I believe row level permissions are on the todo list for 1.2 also, not 100% sure on that one though.
I don't think there is any clear winner, especially if you consider that not all queries will need to be filtered by account. Also consider the old
threadlocals
trick is considered unreliable which means the only way to do automatic insertion of filter parameters would be with middleware I guess... but that also seems unreliable and complex to me.I also haven't come up with a good way to make a query manager that can help here, but it might be possible.
So, I think the best solution for a "multi-tenant" database is just to make sure all your queries are filtered by account. You can do this with:
Debug mode middleware such as Middleware: Record ownership screener
In your tests check the sql generated by any tests and verify the account field is in the query. You could also include "other account" data in your test fixtures that your test would make sure do not show up in any query results.
Making sure all queries are checked for the filter during code review
Certainly not pretty, but the best I've been able to do so far.
Is there some huge reason why you can't just write a function that automatically inserts the session account into the query and takes all your other parameters as arguments?