Hierarchical multi-tenant architecture with Django and Postgresql using separate schemas
up vote
3
down vote
favorite
I have a django app has clients and multiple users that are linked to those clients, and I want to migrate the system to hierarchical multi-tenant architecture.
Hierarchical Part
Clients can include other clients recursively. For instance, Client A includes Client B and Client C. If a user Client A logs in the system, user will see Client B and Client C's data. If a user of Client B logs in the system, user will see only Client B's data.
Multi-Tenant Part
I want to store all clients' data in separate schemas. But there is some data that is not relevant to clients, so I want to store that data in "public" schema.
When I research Building Multi Tenant Applications with Django, I saw this part:
def set_tenant_schema_for_request(request):
schema = tenant_schema_from_request(request)
with connection.cursor() as cursor:
cursor.execute(f"SET search_path to {schema}")
However, to apply my hierarchical example that I've mentioned above, I must reach multiple schemas at the same time. Can I do that or are there any other ways to implement my architecture?
django postgresql database-design architecture multi-tenant
add a comment |
up vote
3
down vote
favorite
I have a django app has clients and multiple users that are linked to those clients, and I want to migrate the system to hierarchical multi-tenant architecture.
Hierarchical Part
Clients can include other clients recursively. For instance, Client A includes Client B and Client C. If a user Client A logs in the system, user will see Client B and Client C's data. If a user of Client B logs in the system, user will see only Client B's data.
Multi-Tenant Part
I want to store all clients' data in separate schemas. But there is some data that is not relevant to clients, so I want to store that data in "public" schema.
When I research Building Multi Tenant Applications with Django, I saw this part:
def set_tenant_schema_for_request(request):
schema = tenant_schema_from_request(request)
with connection.cursor() as cursor:
cursor.execute(f"SET search_path to {schema}")
However, to apply my hierarchical example that I've mentioned above, I must reach multiple schemas at the same time. Can I do that or are there any other ways to implement my architecture?
django postgresql database-design architecture multi-tenant
add a comment |
up vote
3
down vote
favorite
up vote
3
down vote
favorite
I have a django app has clients and multiple users that are linked to those clients, and I want to migrate the system to hierarchical multi-tenant architecture.
Hierarchical Part
Clients can include other clients recursively. For instance, Client A includes Client B and Client C. If a user Client A logs in the system, user will see Client B and Client C's data. If a user of Client B logs in the system, user will see only Client B's data.
Multi-Tenant Part
I want to store all clients' data in separate schemas. But there is some data that is not relevant to clients, so I want to store that data in "public" schema.
When I research Building Multi Tenant Applications with Django, I saw this part:
def set_tenant_schema_for_request(request):
schema = tenant_schema_from_request(request)
with connection.cursor() as cursor:
cursor.execute(f"SET search_path to {schema}")
However, to apply my hierarchical example that I've mentioned above, I must reach multiple schemas at the same time. Can I do that or are there any other ways to implement my architecture?
django postgresql database-design architecture multi-tenant
I have a django app has clients and multiple users that are linked to those clients, and I want to migrate the system to hierarchical multi-tenant architecture.
Hierarchical Part
Clients can include other clients recursively. For instance, Client A includes Client B and Client C. If a user Client A logs in the system, user will see Client B and Client C's data. If a user of Client B logs in the system, user will see only Client B's data.
Multi-Tenant Part
I want to store all clients' data in separate schemas. But there is some data that is not relevant to clients, so I want to store that data in "public" schema.
When I research Building Multi Tenant Applications with Django, I saw this part:
def set_tenant_schema_for_request(request):
schema = tenant_schema_from_request(request)
with connection.cursor() as cursor:
cursor.execute(f"SET search_path to {schema}")
However, to apply my hierarchical example that I've mentioned above, I must reach multiple schemas at the same time. Can I do that or are there any other ways to implement my architecture?
django postgresql database-design architecture multi-tenant
django postgresql database-design architecture multi-tenant
edited Nov 8 at 12:21
asked Nov 8 at 11:29
goktugbc
347
347
add a comment |
add a comment |
1 Answer
1
active
oldest
votes
up vote
1
down vote
accepted
You can list multiple schemas in the PostgreSQL search path. If the same table appears in several schemas only rows from the first schema in the search path will be returned. There's no automatic combining of rows from tables in different schemas. So that's probably not what you want.
You could rearchitect your application so that every query selects data from tables in different schemas and then use union clauses to join those results together. While that would provide the right results, it should be clear that structuring all of your queries this way will complicate the application greatly and makes it also not a good plan.
If you want the ability to see the data from several clients at once, a multi-tenant architecture with isolated schemas is not the right way to go. Having eliminated the alternatives, I think only one approach remains. You have to use shared schema multi-tenancy with rows from different clients in the same tables.
Having a shared schema means that there's less separation of data from different clients, but it provides a simple way to show data from multiple clients at once in cases where that's what's required. The normal approach to implementation is to add terms to the where clauses of your queries to ensure that only data that should be visible for the logged-in user is returned.
Another possibility you might consider would be to use row-level security within the database. With that approach each client would have their own Postgres user account with a policy that restricts access to only the rows that are applicable to them. That pushes some responsibility for ensuring correct security from the application layer to the database layer, which has pros and cons. A benefit is that security needs to be implemented only once at the database, as opposed to throughout the data access parts of the application. A possible drawback is that it may be more work for the database to do.
https://www.postgresql.org/docs/11/ddl-rowsecurity.html
add a comment |
1 Answer
1
active
oldest
votes
1 Answer
1
active
oldest
votes
active
oldest
votes
active
oldest
votes
up vote
1
down vote
accepted
You can list multiple schemas in the PostgreSQL search path. If the same table appears in several schemas only rows from the first schema in the search path will be returned. There's no automatic combining of rows from tables in different schemas. So that's probably not what you want.
You could rearchitect your application so that every query selects data from tables in different schemas and then use union clauses to join those results together. While that would provide the right results, it should be clear that structuring all of your queries this way will complicate the application greatly and makes it also not a good plan.
If you want the ability to see the data from several clients at once, a multi-tenant architecture with isolated schemas is not the right way to go. Having eliminated the alternatives, I think only one approach remains. You have to use shared schema multi-tenancy with rows from different clients in the same tables.
Having a shared schema means that there's less separation of data from different clients, but it provides a simple way to show data from multiple clients at once in cases where that's what's required. The normal approach to implementation is to add terms to the where clauses of your queries to ensure that only data that should be visible for the logged-in user is returned.
Another possibility you might consider would be to use row-level security within the database. With that approach each client would have their own Postgres user account with a policy that restricts access to only the rows that are applicable to them. That pushes some responsibility for ensuring correct security from the application layer to the database layer, which has pros and cons. A benefit is that security needs to be implemented only once at the database, as opposed to throughout the data access parts of the application. A possible drawback is that it may be more work for the database to do.
https://www.postgresql.org/docs/11/ddl-rowsecurity.html
add a comment |
up vote
1
down vote
accepted
You can list multiple schemas in the PostgreSQL search path. If the same table appears in several schemas only rows from the first schema in the search path will be returned. There's no automatic combining of rows from tables in different schemas. So that's probably not what you want.
You could rearchitect your application so that every query selects data from tables in different schemas and then use union clauses to join those results together. While that would provide the right results, it should be clear that structuring all of your queries this way will complicate the application greatly and makes it also not a good plan.
If you want the ability to see the data from several clients at once, a multi-tenant architecture with isolated schemas is not the right way to go. Having eliminated the alternatives, I think only one approach remains. You have to use shared schema multi-tenancy with rows from different clients in the same tables.
Having a shared schema means that there's less separation of data from different clients, but it provides a simple way to show data from multiple clients at once in cases where that's what's required. The normal approach to implementation is to add terms to the where clauses of your queries to ensure that only data that should be visible for the logged-in user is returned.
Another possibility you might consider would be to use row-level security within the database. With that approach each client would have their own Postgres user account with a policy that restricts access to only the rows that are applicable to them. That pushes some responsibility for ensuring correct security from the application layer to the database layer, which has pros and cons. A benefit is that security needs to be implemented only once at the database, as opposed to throughout the data access parts of the application. A possible drawback is that it may be more work for the database to do.
https://www.postgresql.org/docs/11/ddl-rowsecurity.html
add a comment |
up vote
1
down vote
accepted
up vote
1
down vote
accepted
You can list multiple schemas in the PostgreSQL search path. If the same table appears in several schemas only rows from the first schema in the search path will be returned. There's no automatic combining of rows from tables in different schemas. So that's probably not what you want.
You could rearchitect your application so that every query selects data from tables in different schemas and then use union clauses to join those results together. While that would provide the right results, it should be clear that structuring all of your queries this way will complicate the application greatly and makes it also not a good plan.
If you want the ability to see the data from several clients at once, a multi-tenant architecture with isolated schemas is not the right way to go. Having eliminated the alternatives, I think only one approach remains. You have to use shared schema multi-tenancy with rows from different clients in the same tables.
Having a shared schema means that there's less separation of data from different clients, but it provides a simple way to show data from multiple clients at once in cases where that's what's required. The normal approach to implementation is to add terms to the where clauses of your queries to ensure that only data that should be visible for the logged-in user is returned.
Another possibility you might consider would be to use row-level security within the database. With that approach each client would have their own Postgres user account with a policy that restricts access to only the rows that are applicable to them. That pushes some responsibility for ensuring correct security from the application layer to the database layer, which has pros and cons. A benefit is that security needs to be implemented only once at the database, as opposed to throughout the data access parts of the application. A possible drawback is that it may be more work for the database to do.
https://www.postgresql.org/docs/11/ddl-rowsecurity.html
You can list multiple schemas in the PostgreSQL search path. If the same table appears in several schemas only rows from the first schema in the search path will be returned. There's no automatic combining of rows from tables in different schemas. So that's probably not what you want.
You could rearchitect your application so that every query selects data from tables in different schemas and then use union clauses to join those results together. While that would provide the right results, it should be clear that structuring all of your queries this way will complicate the application greatly and makes it also not a good plan.
If you want the ability to see the data from several clients at once, a multi-tenant architecture with isolated schemas is not the right way to go. Having eliminated the alternatives, I think only one approach remains. You have to use shared schema multi-tenancy with rows from different clients in the same tables.
Having a shared schema means that there's less separation of data from different clients, but it provides a simple way to show data from multiple clients at once in cases where that's what's required. The normal approach to implementation is to add terms to the where clauses of your queries to ensure that only data that should be visible for the logged-in user is returned.
Another possibility you might consider would be to use row-level security within the database. With that approach each client would have their own Postgres user account with a policy that restricts access to only the rows that are applicable to them. That pushes some responsibility for ensuring correct security from the application layer to the database layer, which has pros and cons. A benefit is that security needs to be implemented only once at the database, as opposed to throughout the data access parts of the application. A possible drawback is that it may be more work for the database to do.
https://www.postgresql.org/docs/11/ddl-rowsecurity.html
answered Nov 9 at 3:32
Oliver Crow
456
456
add a comment |
add a comment |
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53206853%2fhierarchical-multi-tenant-architecture-with-django-and-postgresql-using-separate%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown