Added a stealth option to flush to allow cascades.
This allows using flush on a subset of the tables without having to manually cascade to all tables with foreign keys to the tables being truncated, when they're known to be empty. On databases where truncate is implemented with DELETE FROM, this doesn't make a difference. The cascade is allowed, not mandatory.
This commit is contained in:
parent
7a65c95d42
commit
13b7f299de
|
@ -32,8 +32,9 @@ class Command(NoArgsCommand):
|
||||||
connection = connections[db]
|
connection = connections[db]
|
||||||
verbosity = int(options.get('verbosity'))
|
verbosity = int(options.get('verbosity'))
|
||||||
interactive = options.get('interactive')
|
interactive = options.get('interactive')
|
||||||
# 'reset_sequences' is a stealth option
|
# 'reset_sequences' and 'allow_cascade' are stealth options
|
||||||
reset_sequences = options.get('reset_sequences', True)
|
reset_sequences = options.get('reset_sequences', True)
|
||||||
|
allow_cascade = options.get('allow_cascade', False)
|
||||||
|
|
||||||
self.style = no_style()
|
self.style = no_style()
|
||||||
|
|
||||||
|
@ -45,7 +46,9 @@ class Command(NoArgsCommand):
|
||||||
except ImportError:
|
except ImportError:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
sql_list = sql_flush(self.style, connection, only_django=True, reset_sequences=reset_sequences)
|
sql_list = sql_flush(self.style, connection, only_django=True,
|
||||||
|
reset_sequences=reset_sequences,
|
||||||
|
allow_cascade=allow_cascade)
|
||||||
|
|
||||||
if interactive:
|
if interactive:
|
||||||
confirm = input("""You have requested a flush of the database.
|
confirm = input("""You have requested a flush of the database.
|
||||||
|
|
|
@ -102,7 +102,7 @@ def sql_delete(app, style, connection):
|
||||||
return output[::-1] # Reverse it, to deal with table dependencies.
|
return output[::-1] # Reverse it, to deal with table dependencies.
|
||||||
|
|
||||||
|
|
||||||
def sql_flush(style, connection, only_django=False, reset_sequences=True):
|
def sql_flush(style, connection, only_django=False, reset_sequences=True, allow_cascade=False):
|
||||||
"""
|
"""
|
||||||
Returns a list of the SQL statements used to flush the database.
|
Returns a list of the SQL statements used to flush the database.
|
||||||
|
|
||||||
|
@ -114,7 +114,7 @@ def sql_flush(style, connection, only_django=False, reset_sequences=True):
|
||||||
else:
|
else:
|
||||||
tables = connection.introspection.table_names()
|
tables = connection.introspection.table_names()
|
||||||
seqs = connection.introspection.sequence_list() if reset_sequences else ()
|
seqs = connection.introspection.sequence_list() if reset_sequences else ()
|
||||||
statements = connection.ops.sql_flush(style, tables, seqs)
|
statements = connection.ops.sql_flush(style, tables, seqs, allow_cascade)
|
||||||
return statements
|
return statements
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -390,7 +390,7 @@ class BaseDatabaseWrapper(object):
|
||||||
def disable_constraint_checking(self):
|
def disable_constraint_checking(self):
|
||||||
"""
|
"""
|
||||||
Backends can implement as needed to temporarily disable foreign key
|
Backends can implement as needed to temporarily disable foreign key
|
||||||
constraint checking. Should return True if the constraints were
|
constraint checking. Should return True if the constraints were
|
||||||
disabled and will need to be reenabled.
|
disabled and will need to be reenabled.
|
||||||
"""
|
"""
|
||||||
return False
|
return False
|
||||||
|
@ -947,7 +947,7 @@ class BaseDatabaseOperations(object):
|
||||||
"""
|
"""
|
||||||
return ''
|
return ''
|
||||||
|
|
||||||
def sql_flush(self, style, tables, sequences):
|
def sql_flush(self, style, tables, sequences, allow_cascade=False):
|
||||||
"""
|
"""
|
||||||
Returns a list of SQL statements required to remove all data from
|
Returns a list of SQL statements required to remove all data from
|
||||||
the given database tables (without actually removing the tables
|
the given database tables (without actually removing the tables
|
||||||
|
@ -958,6 +958,10 @@ class BaseDatabaseOperations(object):
|
||||||
|
|
||||||
The `style` argument is a Style object as returned by either
|
The `style` argument is a Style object as returned by either
|
||||||
color_style() or no_style() in django.core.management.color.
|
color_style() or no_style() in django.core.management.color.
|
||||||
|
|
||||||
|
The `allow_cascade` argument determines whether truncation may cascade
|
||||||
|
to tables with foreign keys pointing the tables being truncated.
|
||||||
|
PostgreSQL requires a cascade even if these tables are empty.
|
||||||
"""
|
"""
|
||||||
raise NotImplementedError()
|
raise NotImplementedError()
|
||||||
|
|
||||||
|
|
|
@ -298,14 +298,17 @@ class DatabaseOperations(BaseDatabaseOperations):
|
||||||
def random_function_sql(self):
|
def random_function_sql(self):
|
||||||
return 'RAND()'
|
return 'RAND()'
|
||||||
|
|
||||||
def sql_flush(self, style, tables, sequences):
|
def sql_flush(self, style, tables, sequences, allow_cascade=False):
|
||||||
# NB: The generated SQL below is specific to MySQL
|
# NB: The generated SQL below is specific to MySQL
|
||||||
# 'TRUNCATE x;', 'TRUNCATE y;', 'TRUNCATE z;'... style SQL statements
|
# 'TRUNCATE x;', 'TRUNCATE y;', 'TRUNCATE z;'... style SQL statements
|
||||||
# to clear all tables of all data
|
# to clear all tables of all data
|
||||||
if tables:
|
if tables:
|
||||||
sql = ['SET FOREIGN_KEY_CHECKS = 0;']
|
sql = ['SET FOREIGN_KEY_CHECKS = 0;']
|
||||||
for table in tables:
|
for table in tables:
|
||||||
sql.append('%s %s;' % (style.SQL_KEYWORD('TRUNCATE'), style.SQL_FIELD(self.quote_name(table))))
|
sql.append('%s %s;' % (
|
||||||
|
style.SQL_KEYWORD('TRUNCATE'),
|
||||||
|
style.SQL_FIELD(self.quote_name(table)),
|
||||||
|
))
|
||||||
sql.append('SET FOREIGN_KEY_CHECKS = 1;')
|
sql.append('SET FOREIGN_KEY_CHECKS = 1;')
|
||||||
sql.extend(self.sequence_reset_by_name_sql(style, sequences))
|
sql.extend(self.sequence_reset_by_name_sql(style, sequences))
|
||||||
return sql
|
return sql
|
||||||
|
|
|
@ -339,17 +339,17 @@ WHEN (new.%(col_name)s IS NULL)
|
||||||
def savepoint_rollback_sql(self, sid):
|
def savepoint_rollback_sql(self, sid):
|
||||||
return convert_unicode("ROLLBACK TO SAVEPOINT " + self.quote_name(sid))
|
return convert_unicode("ROLLBACK TO SAVEPOINT " + self.quote_name(sid))
|
||||||
|
|
||||||
def sql_flush(self, style, tables, sequences):
|
def sql_flush(self, style, tables, sequences, allow_cascade=False):
|
||||||
# Return a list of 'TRUNCATE x;', 'TRUNCATE y;',
|
# Return a list of 'TRUNCATE x;', 'TRUNCATE y;',
|
||||||
# 'TRUNCATE z;'... style SQL statements
|
# 'TRUNCATE z;'... style SQL statements
|
||||||
if tables:
|
if tables:
|
||||||
# Oracle does support TRUNCATE, but it seems to get us into
|
# Oracle does support TRUNCATE, but it seems to get us into
|
||||||
# FK referential trouble, whereas DELETE FROM table works.
|
# FK referential trouble, whereas DELETE FROM table works.
|
||||||
sql = ['%s %s %s;' % \
|
sql = ['%s %s %s;' % (
|
||||||
(style.SQL_KEYWORD('DELETE'),
|
style.SQL_KEYWORD('DELETE'),
|
||||||
style.SQL_KEYWORD('FROM'),
|
style.SQL_KEYWORD('FROM'),
|
||||||
style.SQL_FIELD(self.quote_name(table)))
|
style.SQL_FIELD(self.quote_name(table))
|
||||||
for table in tables]
|
) for table in tables]
|
||||||
# Since we've just deleted all the rows, running our sequence
|
# Since we've just deleted all the rows, running our sequence
|
||||||
# ALTER code will reset the sequence to 0.
|
# ALTER code will reset the sequence to 0.
|
||||||
sql.extend(self.sequence_reset_by_name_sql(style, sequences))
|
sql.extend(self.sequence_reset_by_name_sql(style, sequences))
|
||||||
|
|
|
@ -101,15 +101,24 @@ class DatabaseOperations(BaseDatabaseOperations):
|
||||||
def set_time_zone_sql(self):
|
def set_time_zone_sql(self):
|
||||||
return "SET TIME ZONE %s"
|
return "SET TIME ZONE %s"
|
||||||
|
|
||||||
def sql_flush(self, style, tables, sequences):
|
def sql_flush(self, style, tables, sequences, allow_cascade=False):
|
||||||
if tables:
|
if tables:
|
||||||
# Perform a single SQL 'TRUNCATE x, y, z...;' statement. It allows
|
# Perform a single SQL 'TRUNCATE x, y, z...;' statement. It allows
|
||||||
# us to truncate tables referenced by a foreign key in any other
|
# us to truncate tables referenced by a foreign key in any other
|
||||||
# table.
|
# table.
|
||||||
sql = ['%s %s;' % \
|
tables_sql = ', '.join(
|
||||||
(style.SQL_KEYWORD('TRUNCATE'),
|
style.SQL_FIELD(self.quote_name(table)) for table in tables)
|
||||||
style.SQL_FIELD(', '.join([self.quote_name(table) for table in tables]))
|
if allow_cascade:
|
||||||
)]
|
sql = ['%s %s %s;' % (
|
||||||
|
style.SQL_KEYWORD('TRUNCATE'),
|
||||||
|
tables_sql,
|
||||||
|
style.SQL_KEYWORD('CASCADE'),
|
||||||
|
)]
|
||||||
|
else:
|
||||||
|
sql = ['%s %s;' % (
|
||||||
|
style.SQL_KEYWORD('TRUNCATE'),
|
||||||
|
tables_sql,
|
||||||
|
)]
|
||||||
sql.extend(self.sequence_reset_by_name_sql(style, sequences))
|
sql.extend(self.sequence_reset_by_name_sql(style, sequences))
|
||||||
return sql
|
return sql
|
||||||
else:
|
else:
|
||||||
|
|
|
@ -209,15 +209,15 @@ class DatabaseOperations(BaseDatabaseOperations):
|
||||||
def no_limit_value(self):
|
def no_limit_value(self):
|
||||||
return -1
|
return -1
|
||||||
|
|
||||||
def sql_flush(self, style, tables, sequences):
|
def sql_flush(self, style, tables, sequences, allow_cascade=False):
|
||||||
# NB: The generated SQL below is specific to SQLite
|
# NB: The generated SQL below is specific to SQLite
|
||||||
# Note: The DELETE FROM... SQL generated below works for SQLite databases
|
# Note: The DELETE FROM... SQL generated below works for SQLite databases
|
||||||
# because constraints don't exist
|
# because constraints don't exist
|
||||||
sql = ['%s %s %s;' % \
|
sql = ['%s %s %s;' % (
|
||||||
(style.SQL_KEYWORD('DELETE'),
|
style.SQL_KEYWORD('DELETE'),
|
||||||
style.SQL_KEYWORD('FROM'),
|
style.SQL_KEYWORD('FROM'),
|
||||||
style.SQL_FIELD(self.quote_name(table))
|
style.SQL_FIELD(self.quote_name(table))
|
||||||
) for table in tables]
|
) for table in tables]
|
||||||
# Note: No requirement for reset of auto-incremented indices (cf. other
|
# Note: No requirement for reset of auto-incremented indices (cf. other
|
||||||
# sql_flush() implementations). Just return SQL at this point
|
# sql_flush() implementations). Just return SQL at this point
|
||||||
return sql
|
return sql
|
||||||
|
|
Loading…
Reference in New Issue