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)

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章