Serving separate database per user django - python

i am creating database according this now: Saperate PostgreSQL db for each client, with automated migrations on creating client on single Django app and on same server
Now I want to serve the db per user. We can return db from db routers only if they exists in the DATABASES varriable in the settings file.
Does anybody know how to serve db which are created on server but not added in settings.py, which will be according to the logged in user.
There will be a main db for user, in which their relations with their db name is saved.
Settings.py
DATABASE_ROUTERS = ['app.router_middleware.DataBaseRouter']
DATABASES = {'default':
{
'ENGINE': 'django.db.backends.postgresql_psycopg2',
'NAME': 'abc',
'USER': 'xyz',
'PASSWORD': '*****',
'HOST': 'localhost',
'PORT': '5432',
}
}
import django
django.setup()
from Client.views import ALL_DB
DATABASES.update(ALL_DB)
Client.views
ALL_DB = { x.db_name: {
'ENGINE': 'django.db.backends.postgresql_psycopg2',
'NAME': x.db_name,
'USER': 'xyz',
'PASSWORD': '****',
'HOST': 'localhost',
'PORT': '5432',
} for x in Client.objects.all()}
router_middleware.py
db_name = 'default'
class RouterMiddleware(CoreSessionMiddleware):
def process_request(self, request):
if request.user.is_authenticated() :
user = request.user
if ClientEmployee.objects.filter(user=user).exists():
client_employee = ClientEmployee.objects.get(user=user)
db_name = client_employee.client.db_name
class DataBaseRouter(object):
def db_for_read(self, model, **hints):
return db_name
def db_for_write(self, model, **hints):
return db_name

Related

Test django with mongomock for django auth models

I'm trying to perform unit tests on Django with db mocking by mongomock.
My connection to the DB is made using settings.py:
DATABASES = {
'dbname': {
'ENGINE': 'djongo',
'NAME': 'db1',
'ENFORCE_SCHEMA': False,
'CLIENT': {
'host': DB_HOST,
'port': DB_PORT,
'username': DB_USERNAME,
'password': DB_PASSWORD,
'authSource': 'admin',
'authMechanism': 'SCRAM-SHA-1'
}
},
'default': {
'ENGINE': 'djongo',
'NAME': 'users',
'ENFORCE_SCHEMA': False,
'CLIENT': {
'host': DB_HOST,
'port': DB_PORT,
'username': DB_USERNAME,
'password': DB_PASSWORD,
'authSource': 'admin',
'authMechanism': 'SCRAM-SHA-1'
}
}
}
and the test looks like this:
from django.contrib.auth.models import User
class BaseApiTest():
def test_access_login(self):
User.objects.create_user(
username='admin',
password='admin'
)
....
self.assertEqual(AccessAttempt.objects.count(), 1)
Here there is an internal connection of Django to the DB. (when its trying to access django.contrib.auth.models.User)
Any ideas?
The goal is to run the tests without a DB instance.
In other words, how can I overwrite the Django connection (self.databases) to the DB using a mongomock connection...

Wrong model._meta.app_label (from other app) in Django database router

i have two different SQL databases and three apps in my django project.
The apps are named PROD, TEST and common.
I am trying to route everything that comes from an url of PROD to models.py from PROD and database1, and everything that comes from an url of TEST to models.py from TEST and database2.
TEST
-- models.py
PROD
-- models.py
common
It worked fine, until i introduced 'common'(after cloning the project to another folder) and i don't know why.
settings.py:
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME': 'cfg_db_ic2_net_dev_test',
'USER': '',
'PASSWORD': '',
'HOST': '',
'PORT': '',
},
'proddb': {
'ENGINE': 'django.db.backends.mysql',
'NAME': 'cfg_db_ic2_net_dev_prod',
'USER': '',
'PASSWORD': '',
'HOST': '',
'PORT': '',
}
}
DATABASE_ROUTERS = ['PROD.dbRouter.ProdDBRouter']
PROD/dbRouter.py:
def db_for_read(self, model, **hints):
"Point all operations on prod models to 'proddb'"
from django.conf import settings
print(model._meta.app_label)
if model._meta.app_label == 'PROD':
return 'proddb'
return None
...
PROD/views.py:
def hosts(request):
print("I did this")
return render(request=request, template_name="common/hosts.html", context={"hosts": NetDefined.objects.all, "landscape": landscape})
The models.py for each TEST and PROD is pretty identical.
The issue that i have is that the template hosts.html is populated with data from the default data base and not from proddb database.
The reason for this is that the DBRouter doesn't recognize the model's model._meta.app_label, it says it's "TEST".
Even though the url is definitely routed correctly, the "I did this" is printed.
This only occured after reinstalling the project and introducing the third app.
So my question is: why doesn't Django recognize, that the views and models from "PROD" are being used and instead provides the wrong app_label to the router?
Thanks for your help!

Can't reference Django database with dj_database_url

I have a Django application using decouple and dj_database_url (it is not on Heroku). If I put my connection information in settings.ini (DB_NAME, DB_USER, DB_PASSWORD, DB_HOST, and DB_PORT) and set up my database connection in settings.py like this:
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.postgresql_psycopg2',
'NAME': config('DB_NAME'),
'USER': config('DB_USER'),
'PASSWORD': config('DB_PASSWORD'),
'HOST': config('DB_HOST'),
'PORT': 'DB_PORT',
}
}
It works fine.
However, if I put this in my settings.ini:
DATABASE_URL=postgres://johndoe:mypassword#123.456.789.000:5000/blog_db
and reference it like this in my settings.py:
DATABASES = {"default": dj_database_url.config(default=config("DATABASE_URL"))}
It doesn't work. I just get a 500 when I try to run my server. I presume there is something wrong with my syntax. Can anyone point out what I'm doing wrong?
Thanks!

Django loaddata - instance is on database "postgres", value is on database "default"

I need to migrate from sqlite3 to postgres. The dumpdata of the whole database doesn't work so I'm doing it one by one. The problem is that when I try to load users it raises error:
ValueError: Problem installing fixture '/.../dbmig/auth.user.json': Could not load auth.User(pk=1): Cannot add "<Group: contractor>": instance is on database "postgres", value is on database "default"
This is not true, because the groups were migrated before users.
I've created a command that I use:
def dumpload(model):
json_filename = model+'.json'
DBMIG_DIR = os.path.join(settings.BASE_DIR, 'dbmig')
json_filepath = os.path.join(DBMIG_DIR,json_filename)
with open(json_filepath, 'w') as f:
call_command('dumpdata', model, stdout=f, database='default')
call_command('loaddata', json_filepath, database='postgres')
class Command(BaseCommand):
def handle(self, *args, **options):
dumpload('auth.group')
dumpload('auth.user')
EDIT
It doesn't make sense, the groups are already in the postgres db. I've added print(Group.objects.using('postgres').values('pk')) between the two commands and I can clearly see that the groups are in the postgres database and they have correct ids.
This is the output:
Installed 2 object(s) from 1 fixture(s)
<QuerySet [{'pk': 1}, {'pk': 2}]>
error...
EDIT - settings.DATABASES
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': BASE_DIR / 'db.sqlite3',
},
'postgres': {
'ENGINE': 'django.db.backends.postgresql_psycopg2',
'OPTIONS': {
},
'NAME': config.get('db', 'name'),
'USER': config.get('db', 'user'),
'PASSWORD': config.get('db', 'password'),
'HOST': config.get('db', 'host'),
'PORT': config.get('db', 'port'),
}
}

Running two databases on heroku with django

I have two databases that my Django application needs access. One is a shared database owned by a separate app with the Django app only having read access. The second is entirely owned by the Django app.
For local development I am ok but I'm not sure how to configure things so that Heroku uses the second database.
Currently I have the shared database promoted to DATABASE_URL and the secondary database is at HEROKU_POSTGRESQL_BLUE_URL.
In my settings I have:
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.postgresql',
'NAME': 'main_database_name',
'USER': 'username',
'PASSWORD': '',
'HOST': 'localhost',
'PORT': '5432',
}, 'secondary': {
'ENGINE': 'django.db.backends.postgresql',
'NAME': 'secondary_database_name',
'USER': 'username',
'PASSWORD': '',
'HOST': 'localhost',
'PORT': '5432',
}
}
Please ask any more questions if you need me to clarify.
Thanks!
In summary, my specific problem is: I don't know how to have Heroku use the HEROKU_POSTGRESQL_BLUE_URL as the "secondary" database.
---Edit----
At the bottom of settings.py:
# Configure Django App for Heroku.
import django_heroku
django_heroku.settings(locals())
This is where the connection is made between my app's default database and Heroku's DATABASE_URL. I still haven't solved the issue but after some troubleshooting help in the comments, I believe the answer will be found in there.
Here is my working solution.
I have a local_settings.py file not tracked by version control. This contains the database settings for the developer's postgres instance.
local_settings.py
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.postgresql',
'NAME': 'main_database_name',
'USER': 'username',
'PASSWORD': '',
'HOST': 'localhost',
'PORT': '5432',
}, 'secondary': {
'ENGINE': 'django.db.backends.postgresql',
'NAME': 'secondary_database_name',
'USER': 'username',
'PASSWORD': '',
'HOST': 'localhost',
'PORT': '5432',
}
}
Then in settings.py I try to import the local_settings.py file. If it doesn't exist, I use the django_heroku package to configure everything for Heroku. In my case, I need to pass the keyword argument databases=False since I want to do a more custom configuration for the databases.
settings.py (only the relevant parts)
# Database
# https://docs.djangoproject.com/en/2.0/ref/settings/#databases
# These database settings are used for heroku deployments. They are overwritten with local_settings.py in development.
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.postgresql',
'NAME': os.environ.get('DATABASE_URL'),
'USER': '',
'PASSWORD': '',
'HOST': 'localhost',
'PORT': '5432',
}, 'secondary': {
'ENGINE': 'django.db.backends.postgresql',
'NAME': os.environ.get('SECONDARY_DATABASE_URL'),
'USER': '',
'PASSWORD': '',
'HOST': 'localhost',
'PORT': '5432',
}
}
try:
from local_settings import *
except ImportError as e:
# Configure Django App for Heroku.
import django_heroku
django_heroku.settings(locals(), databases=False)
In order for this to work you would need to set the Heroku env variable SECONDARY_DATABASE_NAME to the url of your database.
To find out the URL of your secondary database run heroku config -a your_app_name. Copy the url and then set a new environment param in heroku by running
heroku config:set SECONDARY_DATABASE_URL=postgres://xxxxxxx -a your_app_Name
There are a lot of choices with how you would handle the ENV variables, I liked this because I can just set it in my staging and production environments and the same settings work for both.

Categories

Resources