Skip to content

Commit

Permalink
Split read-only and read/write API by the db backends (#37)
Browse files Browse the repository at this point in the history
  • Loading branch information
ruslan33 authored Jan 2, 2025
1 parent 5b4607e commit 1a5c2eb
Show file tree
Hide file tree
Showing 3 changed files with 92 additions and 6 deletions.
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

0 comments on commit 1a5c2eb

Please sign in to comment.