Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Split read-only and read/write API by the db backends #34

Merged
merged 1 commit into from
Jan 2, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 29 additions & 0 deletions nopayloaddb/db_router.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import random
from nopayloaddb.middleware import get_current_request

logger = logging.getLogger(__name__)

class ReadWriteRouter:
def db_for_read(self, model, **hints):
"""Route read queries to one of the read databases."""
db = random.choice(['read_db_1', 'read_db_2'])
# Check if request information is available
request = get_current_request()
if request and request.method == 'GET':
return db
return 'default'

def db_for_write(self, model, **hints):
"""Route write queries to the default database."""
return 'default'

def allow_relation(self, obj1, obj2, **hints):
"""Allow any relation if both objects are in the same database."""
db_set = {'default', 'read_db_1', 'read_db_2'}
if obj1._state.db in db_set and obj2._state.db in db_set:
return True
return None

def allow_migrate(self, db, app_label, model_name=None, **hints):
"""Ensure migrations only run on the default database."""
return db == 'default'
20 changes: 20 additions & 0 deletions nopayloaddb/middleware.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
from threading import local

# Local storage for storing the current request
_request_local = local()

def get_current_request():
return getattr(_request_local, 'request', None)

class RequestMiddleware:
"""Middleware to store the current request for use in the DB router."""
def __init__(self, get_response):
self.get_response = get_response

def __call__(self, request):
# Save the request in the local thread storage
_request_local.request = request
response = self.get_response(request)
# Clear the request after processing to avoid conflicts
_request_local.request = None
return response
49 changes: 43 additions & 6 deletions nopayloaddb/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,8 @@
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
#My middleware
'nopayloaddb.middleware.RequestMiddleware',
]

ROOT_URLCONF = 'nopayloaddb.urls'
Expand Down Expand Up @@ -116,20 +118,55 @@
# }
#}

#DATABASES = {
# 'default': {
# 'ENGINE': 'django.db.backends.postgresql_psycopg2',
#
#
# 'NAME': os.environ.get("POSTGRES_DB", default='dbname'),
# 'USER': os.environ.get("POSTGRES_USER", default='login'),
# 'PASSWORD': os.environ.get("POSTGRES_PASSWORD", default='password'),
# 'HOST': os.environ.get("POSTGRES_HOST", default='localhost'),
# 'PORT': os.environ.get("POSTGRES_PORT", default='5432'),
#
# }
#}

DATABASES = {
'default': {
'ENGINE': 'django.db.backends.postgresql_psycopg2',


'NAME': os.environ.get("POSTGRES_DB", default='dbname'),
'USER': os.environ.get("POSTGRES_USER", default='login'),
'PASSWORD': os.environ.get("POSTGRES_PASSWORD", default='password'),
'HOST': os.environ.get("POSTGRES_HOST", default='localhost'),
'PORT': os.environ.get("POSTGRES_PORT", default='5432'),
'NAME': os.environ.get("POSTGRES_DB_W", default='dbname'),
'USER': os.environ.get("POSTGRES_USER_W", default='login'),
'PASSWORD': os.environ.get("POSTGRES_PASSWORD_W", default='password'),
'HOST': os.environ.get("POSTGRES_HOST_W", default='localhost'),
'PORT': os.environ.get("POSTGRES_PORT_W", default='5432'),
},
'read_db_1': {
'ENGINE': 'django.db.backends.postgresql_psycopg2',


'NAME': os.environ.get("POSTGRES_DB_R1", default='dbname'),
'USER': os.environ.get("POSTGRES_USER_R1", default='login'),
'PASSWORD': os.environ.get("POSTGRES_PASSWORD_R1", default='password'),
'HOST': os.environ.get("POSTGRES_HOST_R1", default='localhost'),
'PORT': os.environ.get("POSTGRES_PORT_R1", default='5432'),
},
'read_db_2': {
'ENGINE': 'django.db.backends.postgresql_psycopg2',

}

'NAME': os.environ.get("POSTGRES_DB_R2", default='dbname'),
'USER': os.environ.get("POSTGRES_USER_R2", default='login'),
'PASSWORD': os.environ.get("POSTGRES_PASSWORD_R2", default='password'),
'HOST': os.environ.get("POSTGRES_HOST_R2", default='localhost'),
'PORT': os.environ.get("POSTGRES_PORT_R2", default='5432'),
},
}

DATABASE_ROUTERS = ['nopayloaddb.db_router.ReadWriteRouter']

REST_FRAMEWORK = {
# 'DEFAULT_AUTHENTICATION_CLASSES': (
# 'rest_framework.authentication.TokenAuthentication',
Expand Down