131 lines
4.5 KiB
Python
131 lines
4.5 KiB
Python
|
from django.conf import settings
|
||
|
from django.core.cache import caches
|
||
|
from django.core.cache.backends.db import BaseDatabaseCache
|
||
|
from django.core.management.base import BaseCommand, CommandError
|
||
|
from django.db import (
|
||
|
DEFAULT_DB_ALIAS,
|
||
|
DatabaseError,
|
||
|
connections,
|
||
|
models,
|
||
|
router,
|
||
|
transaction,
|
||
|
)
|
||
|
|
||
|
|
||
|
class Command(BaseCommand):
|
||
|
help = "Creates the tables needed to use the SQL cache backend."
|
||
|
|
||
|
requires_system_checks = []
|
||
|
|
||
|
def add_arguments(self, parser):
|
||
|
parser.add_argument(
|
||
|
"args",
|
||
|
metavar="table_name",
|
||
|
nargs="*",
|
||
|
help=(
|
||
|
"Optional table names. Otherwise, settings.CACHES is used to find "
|
||
|
"cache tables."
|
||
|
),
|
||
|
)
|
||
|
parser.add_argument(
|
||
|
"--database",
|
||
|
default=DEFAULT_DB_ALIAS,
|
||
|
help="Nominates a database onto which the cache tables will be "
|
||
|
'installed. Defaults to the "default" database.',
|
||
|
)
|
||
|
parser.add_argument(
|
||
|
"--dry-run",
|
||
|
action="store_true",
|
||
|
help="Does not create the table, just prints the SQL that would be run.",
|
||
|
)
|
||
|
|
||
|
def handle(self, *tablenames, **options):
|
||
|
db = options["database"]
|
||
|
self.verbosity = options["verbosity"]
|
||
|
dry_run = options["dry_run"]
|
||
|
if tablenames:
|
||
|
# Legacy behavior, tablename specified as argument
|
||
|
for tablename in tablenames:
|
||
|
self.create_table(db, tablename, dry_run)
|
||
|
else:
|
||
|
for cache_alias in settings.CACHES:
|
||
|
cache = caches[cache_alias]
|
||
|
if isinstance(cache, BaseDatabaseCache):
|
||
|
self.create_table(db, cache._table, dry_run)
|
||
|
|
||
|
def create_table(self, database, tablename, dry_run):
|
||
|
cache = BaseDatabaseCache(tablename, {})
|
||
|
if not router.allow_migrate_model(database, cache.cache_model_class):
|
||
|
return
|
||
|
connection = connections[database]
|
||
|
|
||
|
if tablename in connection.introspection.table_names():
|
||
|
if self.verbosity > 0:
|
||
|
self.stdout.write("Cache table '%s' already exists." % tablename)
|
||
|
return
|
||
|
|
||
|
fields = (
|
||
|
# "key" is a reserved word in MySQL, so use "cache_key" instead.
|
||
|
models.CharField(
|
||
|
name="cache_key", max_length=255, unique=True, primary_key=True
|
||
|
),
|
||
|
models.TextField(name="value"),
|
||
|
models.DateTimeField(name="expires", db_index=True),
|
||
|
)
|
||
|
table_output = []
|
||
|
index_output = []
|
||
|
qn = connection.ops.quote_name
|
||
|
for f in fields:
|
||
|
field_output = [
|
||
|
qn(f.name),
|
||
|
f.db_type(connection=connection),
|
||
|
"%sNULL" % ("NOT " if not f.null else ""),
|
||
|
]
|
||
|
if f.primary_key:
|
||
|
field_output.append("PRIMARY KEY")
|
||
|
elif f.unique:
|
||
|
field_output.append("UNIQUE")
|
||
|
if f.db_index:
|
||
|
unique = "UNIQUE " if f.unique else ""
|
||
|
index_output.append(
|
||
|
"CREATE %sINDEX %s ON %s (%s);"
|
||
|
% (
|
||
|
unique,
|
||
|
qn("%s_%s" % (tablename, f.name)),
|
||
|
qn(tablename),
|
||
|
qn(f.name),
|
||
|
)
|
||
|
)
|
||
|
table_output.append(" ".join(field_output))
|
||
|
full_statement = ["CREATE TABLE %s (" % qn(tablename)]
|
||
|
for i, line in enumerate(table_output):
|
||
|
full_statement.append(
|
||
|
" %s%s" % (line, "," if i < len(table_output) - 1 else "")
|
||
|
)
|
||
|
full_statement.append(");")
|
||
|
|
||
|
full_statement = "\n".join(full_statement)
|
||
|
|
||
|
if dry_run:
|
||
|
self.stdout.write(full_statement)
|
||
|
for statement in index_output:
|
||
|
self.stdout.write(statement)
|
||
|
return
|
||
|
|
||
|
with transaction.atomic(
|
||
|
using=database, savepoint=connection.features.can_rollback_ddl
|
||
|
):
|
||
|
with connection.cursor() as curs:
|
||
|
try:
|
||
|
curs.execute(full_statement)
|
||
|
except DatabaseError as e:
|
||
|
raise CommandError(
|
||
|
"Cache table '%s' could not be created.\nThe error was: %s."
|
||
|
% (tablename, e)
|
||
|
)
|
||
|
for statement in index_output:
|
||
|
curs.execute(statement)
|
||
|
|
||
|
if self.verbosity > 1:
|
||
|
self.stdout.write("Cache table '%s' created." % tablename)
|