bernardopires / django-tenant-schemas

Tenant support for Django using PostgreSQL schemas.
https://django-tenant-schemas.readthedocs.org/en/latest/
MIT License
1.46k stars 423 forks source link

Save to other tenant #439

Closed facconi closed 7 years ago

facconi commented 7 years ago

Is it possible to save data to another tenant?

I'd like to register user from the public tenant, and save them on their tenant.

I have read all the documentation and the example, but found no solution.

Thank you!

ishehata commented 7 years ago

what do you mean by save them to their tenant ?

facconi commented 7 years ago

I'll try to explain with an example.

I have a public tenant, www.mysite.com, in which I have a form with the following fields: site_url, username, password.

When saving, the form should create a new tenant with the site_url given, eg: test.mysite.com, and then create a user with the given username and password.

Users are tenant based, not shared, so I'm searching how to create users in the newly created tenant.

Is this example helping you to understand the issue?

goodtune commented 7 years ago

This is something you need to write for yourself, but the pseudo code would be something like:

t = Tenant.objects.create()
with tenant_context(t):
    u = User.objects.create()
facconi commented 7 years ago

Yes, I was just wondering if I was missing from the documentation the tenant_context or a User.objects.using_tenant(t).create() methods. So, as I understand, there is not this functionality in the current version, isn't it? Is it possible to mark as Feature enhancement?

goodtune commented 7 years ago

In practice, I run an asynchronous worker to perform this (and other tenant initialization tasks). Using celery I can separate the user interface from the more laborious tasks of performing schema migrations, populating initial data and then creating some users and groups.

Upon (valid) form submission I immediately respond that "your service is being created" and then send them an email at the end of the async process. It's usually only 10s of seconds, but enough that an eager user could easily hit "refresh" if they are expecting instant gratification.

Given that almost every use case will be different, and the machinery is in place for you to deliver any workflow a developer may see fit, I would not like to see that added to this project. One mans feature is another's maintenance burden, and this really can just be a simple addition to your own project.

facconi commented 7 years ago

I do not agree that it is a one mans feature. I think that a feature that can help building custom workflows and that can adapt to every user needs is a good feature for a good tool. My two cents, of course!

goodtune commented 7 years ago

Sure, I'm not suggesting you're the only person who will ever need this; just that as a class of problem, it's tangential to multi-tenancy. If it's worthwhile addition it can happily exist outside of django-tenant-schemas as a related project.

Not every use case requires this, so it's just another permutation that needs to be tested and maintained into the future, which is why I'd rather see it as an external.

that can adapt to every user needs

This is what worries me most... that is so open ended that we'd increase the complexity of the existing codebase so greatly that we risk slowing down our ability to progress the meat-and-potatoes functionality for fear of breaking compatibility.

I remain unconvinced that such a feature could be implemented reliably in a way that is radically simpler than the 3 lines I proposed earlier, while also providing an equivalent level of flexibility.

I'm not saying you submit a create a pull request to appease those concerns; just declaring my objections and rationale to oppose the suggestion.

ishehata commented 7 years ago

after you create a new tenant, you can switch connection to use that schema

from django.db import connection

connection.set_schema('new_schema_name')

then you will be able to do any queries inside that schema,

u = User.objects.create()

you might need to set the connection back to public if you need to

connection.set_schema_to_public()
goodtune commented 7 years ago

@emostafa it's safer to use the context manager approach (either tenant_context or schema_context) as it will handle switching the schema search path and will restore prior state as you leave it's control.

See https://django-tenant-schemas.readthedocs.io/en/latest/use.html#utils

facconi commented 7 years ago

That's perfect, thank you everybody. That part of the documentation is what I was looking for. I hope others will have benefits from this discussion. Thanks again!