I am building a multi-tenant project using third-party package (django-tenants) which makes me derive the Tenant and Domain models from it's own classes:
from django_tenants.models import TenantMixin, DomainMixin
class Tenant(TenantMixin):
name = models.CharField(max_length=100)
email = models.CharField(max_length=100)
created_on = models.DateField(auto_now_add=True)
auto_create_schema = True
auto_drop_shema = True
class Domain(DomainMixin):
pass;
Long story short, I want to create an API view to register tenants but I couldn't understand package code and failed when trying to create a TenantManager; But I did figure out how to call the CLI management commands provided by django-tenants (python manage.py create_tenant/create_tenant_superuser) from inside the code using django.core.management.call_commands:
management.call_command(
'create_tenant',
domain_domain = 'tenant1.mysite.com',
schema_name = 'tenant1Schema',
name ='tenant1Name',
email = '[email protected]',
domain_is_primary = True,
)
So I figured the temporary simplified solution - another model (Founder) made with regular models.Model and with it's own genericAPIview which I know how to create. Upon posting this model I want to execute the signal to my custom management.call_command.
As far as I understand, there are three parts to django signals:
- sender - this is supposed to be a "notify_about_sender_creation" method in my Founder model
- receiver - this is supposed to be a callable object, in my case it's this custom management.call_command
- signal - I don't know whether this should be a post_save or custom signal ? Can I only feed variables to a custom one ?
Based on this understanding I got:
class Founder(models.Model):
first_name = models.CharField(max_length=200)
last_name = models.CharField(max_length=200)
email = models.CharField(max_length=200, unique=True)
tenant_name = models.CharField(max_length=200)
domain_name = models.CharField(max_length=200)
def generate(self):
data = (Founder.first_name, Founder.last_name, Founder.email, Founder.tenant_name, Founder.domain_name)
save_founder(sender=self, data=data)
save_founder = Signal(providing_args=['first_name','last_name','email','tenant_name','domain_name'])
@receiver(save_founder) def generate_tenant(sender, first_name, last_name, email, tenant_name, domain_name , **kwargs):
management.call_command(
'create_tenant',
domain_domain = sender.domain_name,
schema_name = sender.tenant_name,
name = sender.tenant_name,
email = sender.email,
domain_is_primary = True,
) save_founder.connect(generate_tenant)
but in my console I get:
python manage.py shell
from tenant.models import Founder
f = Founder()
f.generate()
Traceback (most recent call last):
File "<console>", line 1, in <module>
File "/app/tenant/models.py", line 26, in generate
TypeError: 'Signal' object is not callable
What was needed was to pass instance to receiver function. Signal doesn't wasn't ought to be custom. I don't know whether I had to make my receiver function a method of Founder class but it doesn't hurt. Here's what worked: