I am trying to create a Django app that creates a new database for every user when he/she signs up. I am going with this approach due to some reason. I have tried many ways using management commands and even Celery. But I am still getting the same error.
2022-12-23 07:16:07.410 UTC [49] STATEMENT: CREATE DATABASE tenant_asdadsad
[2022-12-23 07:16:07,415: ERROR/ForkPoolWorker-4] Task user.utils.create_database[089b0bc0-0b5f-4199-8cf3-bc336acc7624] raised unexpected: ActiveSqlTransaction('CREATE DATABASE cannot run inside a transaction block\n')
Traceback (most recent call last):
File "/usr/local/lib/python3.9/site-packages/celery/app/trace.py", line 451, in trace_task
R = retval = fun(*args, **kwargs)
File "/usr/local/lib/python3.9/site-packages/celery/app/trace.py", line 734, in __protected_call__
return self.run(*args, **kwargs)
File "/app/user/utils.py", line 45, in create_database
cursor.execute(f'CREATE DATABASE tenant_{tenant_id}')
psycopg2.errors.ActiveSqlTransaction: CREATE DATABASE cannot run inside a transaction block
This is my task
@shared_task
def create_database(tenant_id):
conn = psycopg2.connect(database="mydb", user="dbuser", password="mypass", host="db")
cursor = conn.cursor()
transaction.set_autocommit(True)
cursor.execute(f'CREATE DATABASE tenant_{tenant_id}')
cursor.execute(f'GRANT ALL PRIVILEGES ON DATABASE tenant_{tenant_id} TO dbuser')
cursor.close()
conn.close()
I have tried several ways but I always get the same error
This is my API call
def create(self, request, *args, **kwargs):
serializer_class = mySerializer(data=request.data)
if serializer_class.is_valid():
validated_data = serializer_class.validated_data
or = validated_data["org"]
or = Org.objects.create(**org)
create_database.delay(str(or.id))
return Response(create_user(validated_data))
Use the autocommit property of the connection:
from psycopg2 import sql
def create_database(tenant_id):
conn = psycopg2.connect(database="mydb", user="dbuser", password="mypass", host="db")
cursor = conn.cursor()
conn.autocommit = True #!
# transaction.set_autocommit(True) #?
dbname = sql.Identifier(f'tenant_{tenant_id}')
create_cmd = sql.SQL('CREATE DATABASE {}').format(dbname)
grant_cmd = sql.SQL('GRANT ALL PRIVILEGES ON DATABASE {} TO dbuser').format(dbname)
cursor.execute(create_cmd)
cursor.execute(grant_cmd)
cursor.close()
conn.close()
Read in the docs about connection.autocommit.
Note also the use of the SQL string composition to avoid SQL injection.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With