Django 动态修改库名
需求场场景
一个项目需要把数据库按天存档,所以每天都会创建一个新的库,第二天切换到新库,名的明称是以日期命名
这是一个独立使用Django ORM的项目
setting.py
import os
import sys
from datetime import datetime
# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
# 生成当天db名
def trade_db_file():
now = datetime.now()
now_str = now.strftime('%Y-%m-%d')
return "{}_pos.db".format(now_str)
def cashier_db_file():
return "cashier.db"
# sqlite 配置
def make_config(db_file):
return {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': os.path.join(BASE_DIR, db_file),
}
def db_full_path(db_file):
return os.path.join(BASE_DIR, db_file)
BASE_DIR = os.path.dirname(__file__)
sys.path.insert(0, BASE_DIR)
print(__file__)
print(BASE_DIR)
# Quick-start development settings - unsuitable for production
# See https://docs.djangoproject.com/en/2.1/howto/deployment/checklist/
# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = 'lyv+won7%7!=ra!nc160o-x1yz+m%n1jxm)wtw_y1r3%shh@-%'
# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = True
DATABASE_MAPPING = {
"cashier": "cashier_db",
"trade": "default"
}
# 多库路由
DATABASE_ROUTERS = ['models.database.router.DatabaseAppsRouter']
# Application definition
# 两个APP
INSTALLED_APPS = [
"models.database.trade",
'models.database.cashier',
]
# Database
# https://docs.djangoproject.com/en/2.1/ref/settings/#databases
# 默认库配置
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': os.path.join(BASE_DIR, trade_db_file()),
},
'cashier_db': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': os.path.join(BASE_DIR, cashier_db_file()),
}
}
router.py 这个是db路由文件,决定了迁移,读写等操作的路由
from .settings import DATABASE_MAPPING
class DatabaseAppsRouter(object):
"""
A router to control all database operations on models for different
databases.
In case an app is not set in settings.DATABASE_APPS_MAPPING, the router
will fallback to the `default` database.
Settings example:
DATABASE_APPS_MAPPING = {'app1': 'db1', 'app2': 'db2'}
"""
default_database = "default"
def db_for_read(self, model, **hints):
""""
Point all read operations to the specific database.
"""
if model._meta.app_label in DATABASE_MAPPING:
return DATABASE_MAPPING[model._meta.app_label]
else:
return self.default_database
def db_for_write(self, model, **hints):
"""
Point all write operations to the specific database.
"""
if model._meta.app_label in DATABASE_MAPPING:
return DATABASE_MAPPING[model._meta.app_label]
else:
return self.default_database
def allow_relation(self, obj1, obj2, **hints):
"""
Allow any relation between apps that use the same database.
"""
db_obj1 = DATABASE_MAPPING.get(obj1._meta.app_label) or self.default_database
db_obj2 = DATABASE_MAPPING.get(obj2._meta.app_label) or self.default_database
if db_obj1 and db_obj2:
if db_obj1 == db_obj2:
return True
else:
return False
else:
return None
def allow_syncdb(self, db, model):
"""Make sure that apps only appear in the related database."""
if db in DATABASE_MAPPING.values():
return DATABASE_MAPPING.get(model._meta.app_label) == db
elif model._meta.app_label in DATABASE_MAPPING:
return False
return None
def allow_migrate(self, db, app_label, model=None, **hints):
"""
Make sure the auth app only appears in the 'auth_db'
database.
"""
if db in DATABASE_MAPPING.values():
return DATABASE_MAPPING.get(app_label) == db
elif app_label in DATABASE_MAPPING:
return False
return None
/models/database/init.py
import os
from django.db.utils import load_backend
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "models.database.settings")
from django.apps import apps
from django.conf import settings
from django.core.management import call_command
from django.core import checks
debug = print
apps.populate(settings.INSTALLED_APPS)
def check_error():
errors = checks.run_checks()
if errors:
for error in errors:
debug(f"Error:{error}")
return True
else:
return False
def migrate(app_name: str):
if check_error():
return
database = settings.DATABASE_MAPPING.get(app_name) or "default"
call_command("migrate", app_name, database=database)
def make_migrations(app_name: str):
call_command("makemigrations", app_name)
def init_date_db(date: str = "2020-02-02"):
from models.database.settings import make_config
from django.db import connections
db = make_config("{}_pos.db".format(date))
connections.databases[date] = db
con = connections[date]
print(con)
def init():
from django.conf import settings
for app in settings.INSTALLED_APPS:
name = app.split(".")
make_migrations(name[-1])
migrate(name[-1])
应用层换库操作
from models.database import init, init_date_db
# 当天默认库的mirate
init()
s = Sale.objects.create(sale_dt="2021-01-15 08:49:01", sale_id=2)
print(s.sale_id)
# 指定天库的操作
init_date_db("2021-01-14")
from models.database.trade.models import Sale
s = Sale.objects.using("2021-01-14").create(sale_dt="2021-01-15 08:49:01", sale_id=2)
print(s.sale_id)