mirror of
https://github.com/django/django.git
synced 2025-10-24 14:16:09 +00:00
Ensure cursors are closed when no longer needed.
This commit touchs various parts of the code base and test framework. Any found usage of opening a cursor for the sake of initializing a connection has been replaced with 'ensure_connection()'.
This commit is contained in:
@@ -11,10 +11,10 @@ class PostGISCreation(DatabaseCreation):
|
||||
@cached_property
|
||||
def template_postgis(self):
|
||||
template_postgis = getattr(settings, 'POSTGIS_TEMPLATE', 'template_postgis')
|
||||
cursor = self.connection.cursor()
|
||||
cursor.execute('SELECT 1 FROM pg_database WHERE datname = %s LIMIT 1;', (template_postgis,))
|
||||
if cursor.fetchone():
|
||||
return template_postgis
|
||||
with self.connection.cursor() as cursor:
|
||||
cursor.execute('SELECT 1 FROM pg_database WHERE datname = %s LIMIT 1;', (template_postgis,))
|
||||
if cursor.fetchone():
|
||||
return template_postgis
|
||||
return None
|
||||
|
||||
def sql_indexes_for_field(self, model, f, style):
|
||||
@@ -88,8 +88,8 @@ class PostGISCreation(DatabaseCreation):
|
||||
# Connect to the test database in order to create the postgis extension
|
||||
self.connection.close()
|
||||
self.connection.settings_dict["NAME"] = test_database_name
|
||||
cursor = self.connection.cursor()
|
||||
cursor.execute("CREATE EXTENSION IF NOT EXISTS postgis")
|
||||
cursor.connection.commit()
|
||||
with self.connection.cursor() as cursor:
|
||||
cursor.execute("CREATE EXTENSION IF NOT EXISTS postgis")
|
||||
cursor.connection.commit()
|
||||
|
||||
return test_database_name
|
||||
|
||||
@@ -55,9 +55,8 @@ class SpatiaLiteCreation(DatabaseCreation):
|
||||
|
||||
call_command('createcachetable', database=self.connection.alias)
|
||||
|
||||
# Get a cursor (even though we don't need one yet). This has
|
||||
# the side effect of initializing the test database.
|
||||
self.connection.cursor()
|
||||
# Ensure a connection for the side effect of initializing the test database.
|
||||
self.connection.ensure_connection()
|
||||
|
||||
return test_database_name
|
||||
|
||||
|
||||
@@ -33,9 +33,9 @@ def create_default_site(app_config, verbosity=2, interactive=True, db=DEFAULT_DB
|
||||
if sequence_sql:
|
||||
if verbosity >= 2:
|
||||
print("Resetting sequence")
|
||||
cursor = connections[db].cursor()
|
||||
for command in sequence_sql:
|
||||
cursor.execute(command)
|
||||
with connections[db].cursor() as cursor:
|
||||
for command in sequence_sql:
|
||||
cursor.execute(command)
|
||||
|
||||
Site.objects.clear_cache()
|
||||
|
||||
|
||||
129
django/core/cache/backends/db.py
vendored
129
django/core/cache/backends/db.py
vendored
@@ -59,11 +59,11 @@ class DatabaseCache(BaseDatabaseCache):
|
||||
self.validate_key(key)
|
||||
db = router.db_for_read(self.cache_model_class)
|
||||
table = connections[db].ops.quote_name(self._table)
|
||||
cursor = connections[db].cursor()
|
||||
|
||||
cursor.execute("SELECT cache_key, value, expires FROM %s "
|
||||
"WHERE cache_key = %%s" % table, [key])
|
||||
row = cursor.fetchone()
|
||||
with connections[db].cursor() as cursor:
|
||||
cursor.execute("SELECT cache_key, value, expires FROM %s "
|
||||
"WHERE cache_key = %%s" % table, [key])
|
||||
row = cursor.fetchone()
|
||||
if row is None:
|
||||
return default
|
||||
now = timezone.now()
|
||||
@@ -75,9 +75,9 @@ class DatabaseCache(BaseDatabaseCache):
|
||||
expires = typecast_timestamp(str(expires))
|
||||
if expires < now:
|
||||
db = router.db_for_write(self.cache_model_class)
|
||||
cursor = connections[db].cursor()
|
||||
cursor.execute("DELETE FROM %s "
|
||||
"WHERE cache_key = %%s" % table, [key])
|
||||
with connections[db].cursor() as cursor:
|
||||
cursor.execute("DELETE FROM %s "
|
||||
"WHERE cache_key = %%s" % table, [key])
|
||||
return default
|
||||
value = connections[db].ops.process_clob(row[1])
|
||||
return pickle.loads(base64.b64decode(force_bytes(value)))
|
||||
@@ -96,55 +96,55 @@ class DatabaseCache(BaseDatabaseCache):
|
||||
timeout = self.get_backend_timeout(timeout)
|
||||
db = router.db_for_write(self.cache_model_class)
|
||||
table = connections[db].ops.quote_name(self._table)
|
||||
cursor = connections[db].cursor()
|
||||
|
||||
cursor.execute("SELECT COUNT(*) FROM %s" % table)
|
||||
num = cursor.fetchone()[0]
|
||||
now = timezone.now()
|
||||
now = now.replace(microsecond=0)
|
||||
if timeout is None:
|
||||
exp = datetime.max
|
||||
elif settings.USE_TZ:
|
||||
exp = datetime.utcfromtimestamp(timeout)
|
||||
else:
|
||||
exp = datetime.fromtimestamp(timeout)
|
||||
exp = exp.replace(microsecond=0)
|
||||
if num > self._max_entries:
|
||||
self._cull(db, cursor, now)
|
||||
pickled = pickle.dumps(value, pickle.HIGHEST_PROTOCOL)
|
||||
b64encoded = base64.b64encode(pickled)
|
||||
# The DB column is expecting a string, so make sure the value is a
|
||||
# string, not bytes. Refs #19274.
|
||||
if six.PY3:
|
||||
b64encoded = b64encoded.decode('latin1')
|
||||
try:
|
||||
# Note: typecasting for datetimes is needed by some 3rd party
|
||||
# database backends. All core backends work without typecasting,
|
||||
# so be careful about changes here - test suite will NOT pick
|
||||
# regressions.
|
||||
with transaction.atomic(using=db):
|
||||
cursor.execute("SELECT cache_key, expires FROM %s "
|
||||
"WHERE cache_key = %%s" % table, [key])
|
||||
result = cursor.fetchone()
|
||||
if result:
|
||||
current_expires = result[1]
|
||||
if (connections[db].features.needs_datetime_string_cast and not
|
||||
isinstance(current_expires, datetime)):
|
||||
current_expires = typecast_timestamp(str(current_expires))
|
||||
exp = connections[db].ops.value_to_db_datetime(exp)
|
||||
if result and (mode == 'set' or (mode == 'add' and current_expires < now)):
|
||||
cursor.execute("UPDATE %s SET value = %%s, expires = %%s "
|
||||
"WHERE cache_key = %%s" % table,
|
||||
[b64encoded, exp, key])
|
||||
else:
|
||||
cursor.execute("INSERT INTO %s (cache_key, value, expires) "
|
||||
"VALUES (%%s, %%s, %%s)" % table,
|
||||
[key, b64encoded, exp])
|
||||
except DatabaseError:
|
||||
# To be threadsafe, updates/inserts are allowed to fail silently
|
||||
return False
|
||||
else:
|
||||
return True
|
||||
with connections[db].cursor() as cursor:
|
||||
cursor.execute("SELECT COUNT(*) FROM %s" % table)
|
||||
num = cursor.fetchone()[0]
|
||||
now = timezone.now()
|
||||
now = now.replace(microsecond=0)
|
||||
if timeout is None:
|
||||
exp = datetime.max
|
||||
elif settings.USE_TZ:
|
||||
exp = datetime.utcfromtimestamp(timeout)
|
||||
else:
|
||||
exp = datetime.fromtimestamp(timeout)
|
||||
exp = exp.replace(microsecond=0)
|
||||
if num > self._max_entries:
|
||||
self._cull(db, cursor, now)
|
||||
pickled = pickle.dumps(value, pickle.HIGHEST_PROTOCOL)
|
||||
b64encoded = base64.b64encode(pickled)
|
||||
# The DB column is expecting a string, so make sure the value is a
|
||||
# string, not bytes. Refs #19274.
|
||||
if six.PY3:
|
||||
b64encoded = b64encoded.decode('latin1')
|
||||
try:
|
||||
# Note: typecasting for datetimes is needed by some 3rd party
|
||||
# database backends. All core backends work without typecasting,
|
||||
# so be careful about changes here - test suite will NOT pick
|
||||
# regressions.
|
||||
with transaction.atomic(using=db):
|
||||
cursor.execute("SELECT cache_key, expires FROM %s "
|
||||
"WHERE cache_key = %%s" % table, [key])
|
||||
result = cursor.fetchone()
|
||||
if result:
|
||||
current_expires = result[1]
|
||||
if (connections[db].features.needs_datetime_string_cast and not
|
||||
isinstance(current_expires, datetime)):
|
||||
current_expires = typecast_timestamp(str(current_expires))
|
||||
exp = connections[db].ops.value_to_db_datetime(exp)
|
||||
if result and (mode == 'set' or (mode == 'add' and current_expires < now)):
|
||||
cursor.execute("UPDATE %s SET value = %%s, expires = %%s "
|
||||
"WHERE cache_key = %%s" % table,
|
||||
[b64encoded, exp, key])
|
||||
else:
|
||||
cursor.execute("INSERT INTO %s (cache_key, value, expires) "
|
||||
"VALUES (%%s, %%s, %%s)" % table,
|
||||
[key, b64encoded, exp])
|
||||
except DatabaseError:
|
||||
# To be threadsafe, updates/inserts are allowed to fail silently
|
||||
return False
|
||||
else:
|
||||
return True
|
||||
|
||||
def delete(self, key, version=None):
|
||||
key = self.make_key(key, version=version)
|
||||
@@ -152,9 +152,9 @@ class DatabaseCache(BaseDatabaseCache):
|
||||
|
||||
db = router.db_for_write(self.cache_model_class)
|
||||
table = connections[db].ops.quote_name(self._table)
|
||||
cursor = connections[db].cursor()
|
||||
|
||||
cursor.execute("DELETE FROM %s WHERE cache_key = %%s" % table, [key])
|
||||
with connections[db].cursor() as cursor:
|
||||
cursor.execute("DELETE FROM %s WHERE cache_key = %%s" % table, [key])
|
||||
|
||||
def has_key(self, key, version=None):
|
||||
key = self.make_key(key, version=version)
|
||||
@@ -162,17 +162,18 @@ class DatabaseCache(BaseDatabaseCache):
|
||||
|
||||
db = router.db_for_read(self.cache_model_class)
|
||||
table = connections[db].ops.quote_name(self._table)
|
||||
cursor = connections[db].cursor()
|
||||
|
||||
if settings.USE_TZ:
|
||||
now = datetime.utcnow()
|
||||
else:
|
||||
now = datetime.now()
|
||||
now = now.replace(microsecond=0)
|
||||
cursor.execute("SELECT cache_key FROM %s "
|
||||
"WHERE cache_key = %%s and expires > %%s" % table,
|
||||
[key, connections[db].ops.value_to_db_datetime(now)])
|
||||
return cursor.fetchone() is not None
|
||||
|
||||
with connections[db].cursor() as cursor:
|
||||
cursor.execute("SELECT cache_key FROM %s "
|
||||
"WHERE cache_key = %%s and expires > %%s" % table,
|
||||
[key, connections[db].ops.value_to_db_datetime(now)])
|
||||
return cursor.fetchone() is not None
|
||||
|
||||
def _cull(self, db, cursor, now):
|
||||
if self._cull_frequency == 0:
|
||||
@@ -197,8 +198,8 @@ class DatabaseCache(BaseDatabaseCache):
|
||||
def clear(self):
|
||||
db = router.db_for_write(self.cache_model_class)
|
||||
table = connections[db].ops.quote_name(self._table)
|
||||
cursor = connections[db].cursor()
|
||||
cursor.execute('DELETE FROM %s' % table)
|
||||
with connections[db].cursor() as cursor:
|
||||
cursor.execute('DELETE FROM %s' % table)
|
||||
|
||||
|
||||
# For backwards compatibility
|
||||
|
||||
@@ -72,14 +72,14 @@ class Command(BaseCommand):
|
||||
full_statement.append(' %s%s' % (line, ',' if i < len(table_output) - 1 else ''))
|
||||
full_statement.append(');')
|
||||
with transaction.commit_on_success_unless_managed():
|
||||
curs = connection.cursor()
|
||||
try:
|
||||
curs.execute("\n".join(full_statement))
|
||||
except DatabaseError as e:
|
||||
raise CommandError(
|
||||
"Cache table '%s' could not be created.\nThe error was: %s." %
|
||||
(tablename, force_text(e)))
|
||||
for statement in index_output:
|
||||
curs.execute(statement)
|
||||
with connection.cursor() as curs:
|
||||
try:
|
||||
curs.execute("\n".join(full_statement))
|
||||
except DatabaseError as e:
|
||||
raise CommandError(
|
||||
"Cache table '%s' could not be created.\nThe error was: %s." %
|
||||
(tablename, force_text(e)))
|
||||
for statement in index_output:
|
||||
curs.execute(statement)
|
||||
if self.verbosity > 1:
|
||||
self.stdout.write("Cache table '%s' created." % tablename)
|
||||
|
||||
@@ -64,9 +64,9 @@ Are you sure you want to do this?
|
||||
if confirm == 'yes':
|
||||
try:
|
||||
with transaction.commit_on_success_unless_managed():
|
||||
cursor = connection.cursor()
|
||||
for sql in sql_list:
|
||||
cursor.execute(sql)
|
||||
with connection.cursor() as cursor:
|
||||
for sql in sql_list:
|
||||
cursor.execute(sql)
|
||||
except Exception as e:
|
||||
new_msg = (
|
||||
"Database %s couldn't be flushed. Possible reasons:\n"
|
||||
|
||||
@@ -37,108 +37,108 @@ class Command(NoArgsCommand):
|
||||
table2model = lambda table_name: table_name.title().replace('_', '').replace(' ', '').replace('-', '')
|
||||
strip_prefix = lambda s: s[1:] if s.startswith("u'") else s
|
||||
|
||||
cursor = connection.cursor()
|
||||
yield "# This is an auto-generated Django model module."
|
||||
yield "# You'll have to do the following manually to clean this up:"
|
||||
yield "# * Rearrange models' order"
|
||||
yield "# * Make sure each model has one field with primary_key=True"
|
||||
yield "# * Remove `managed = False` lines for those models you wish to give write DB access"
|
||||
yield "# Feel free to rename the models, but don't rename db_table values or field names."
|
||||
yield "#"
|
||||
yield "# Also note: You'll have to insert the output of 'django-admin.py sqlcustom [app_label]'"
|
||||
yield "# into your database."
|
||||
yield "from __future__ import unicode_literals"
|
||||
yield ''
|
||||
yield 'from %s import models' % self.db_module
|
||||
known_models = []
|
||||
for table_name in connection.introspection.table_names(cursor):
|
||||
if table_name_filter is not None and callable(table_name_filter):
|
||||
if not table_name_filter(table_name):
|
||||
continue
|
||||
with connection.cursor() as cursor:
|
||||
yield "# This is an auto-generated Django model module."
|
||||
yield "# You'll have to do the following manually to clean this up:"
|
||||
yield "# * Rearrange models' order"
|
||||
yield "# * Make sure each model has one field with primary_key=True"
|
||||
yield "# * Remove `managed = False` lines for those models you wish to give write DB access"
|
||||
yield "# Feel free to rename the models, but don't rename db_table values or field names."
|
||||
yield "#"
|
||||
yield "# Also note: You'll have to insert the output of 'django-admin.py sqlcustom [app_label]'"
|
||||
yield "# into your database."
|
||||
yield "from __future__ import unicode_literals"
|
||||
yield ''
|
||||
yield ''
|
||||
yield 'class %s(models.Model):' % table2model(table_name)
|
||||
known_models.append(table2model(table_name))
|
||||
try:
|
||||
relations = connection.introspection.get_relations(cursor, table_name)
|
||||
except NotImplementedError:
|
||||
relations = {}
|
||||
try:
|
||||
indexes = connection.introspection.get_indexes(cursor, table_name)
|
||||
except NotImplementedError:
|
||||
indexes = {}
|
||||
used_column_names = [] # Holds column names used in the table so far
|
||||
for i, row in enumerate(connection.introspection.get_table_description(cursor, table_name)):
|
||||
comment_notes = [] # Holds Field notes, to be displayed in a Python comment.
|
||||
extra_params = OrderedDict() # Holds Field parameters such as 'db_column'.
|
||||
column_name = row[0]
|
||||
is_relation = i in relations
|
||||
|
||||
att_name, params, notes = self.normalize_col_name(
|
||||
column_name, used_column_names, is_relation)
|
||||
extra_params.update(params)
|
||||
comment_notes.extend(notes)
|
||||
|
||||
used_column_names.append(att_name)
|
||||
|
||||
# Add primary_key and unique, if necessary.
|
||||
if column_name in indexes:
|
||||
if indexes[column_name]['primary_key']:
|
||||
extra_params['primary_key'] = True
|
||||
elif indexes[column_name]['unique']:
|
||||
extra_params['unique'] = True
|
||||
|
||||
if is_relation:
|
||||
rel_to = "self" if relations[i][1] == table_name else table2model(relations[i][1])
|
||||
if rel_to in known_models:
|
||||
field_type = 'ForeignKey(%s' % rel_to
|
||||
else:
|
||||
field_type = "ForeignKey('%s'" % rel_to
|
||||
else:
|
||||
# Calling `get_field_type` to get the field type string and any
|
||||
# additional paramters and notes.
|
||||
field_type, field_params, field_notes = self.get_field_type(connection, table_name, row)
|
||||
extra_params.update(field_params)
|
||||
comment_notes.extend(field_notes)
|
||||
|
||||
field_type += '('
|
||||
|
||||
# Don't output 'id = meta.AutoField(primary_key=True)', because
|
||||
# that's assumed if it doesn't exist.
|
||||
if att_name == 'id' and extra_params == {'primary_key': True}:
|
||||
if field_type == 'AutoField(':
|
||||
yield 'from %s import models' % self.db_module
|
||||
known_models = []
|
||||
for table_name in connection.introspection.table_names(cursor):
|
||||
if table_name_filter is not None and callable(table_name_filter):
|
||||
if not table_name_filter(table_name):
|
||||
continue
|
||||
elif field_type == 'IntegerField(' and not connection.features.can_introspect_autofield:
|
||||
comment_notes.append('AutoField?')
|
||||
yield ''
|
||||
yield ''
|
||||
yield 'class %s(models.Model):' % table2model(table_name)
|
||||
known_models.append(table2model(table_name))
|
||||
try:
|
||||
relations = connection.introspection.get_relations(cursor, table_name)
|
||||
except NotImplementedError:
|
||||
relations = {}
|
||||
try:
|
||||
indexes = connection.introspection.get_indexes(cursor, table_name)
|
||||
except NotImplementedError:
|
||||
indexes = {}
|
||||
used_column_names = [] # Holds column names used in the table so far
|
||||
for i, row in enumerate(connection.introspection.get_table_description(cursor, table_name)):
|
||||
comment_notes = [] # Holds Field notes, to be displayed in a Python comment.
|
||||
extra_params = OrderedDict() # Holds Field parameters such as 'db_column'.
|
||||
column_name = row[0]
|
||||
is_relation = i in relations
|
||||
|
||||
# Add 'null' and 'blank', if the 'null_ok' flag was present in the
|
||||
# table description.
|
||||
if row[6]: # If it's NULL...
|
||||
if field_type == 'BooleanField(':
|
||||
field_type = 'NullBooleanField('
|
||||
att_name, params, notes = self.normalize_col_name(
|
||||
column_name, used_column_names, is_relation)
|
||||
extra_params.update(params)
|
||||
comment_notes.extend(notes)
|
||||
|
||||
used_column_names.append(att_name)
|
||||
|
||||
# Add primary_key and unique, if necessary.
|
||||
if column_name in indexes:
|
||||
if indexes[column_name]['primary_key']:
|
||||
extra_params['primary_key'] = True
|
||||
elif indexes[column_name]['unique']:
|
||||
extra_params['unique'] = True
|
||||
|
||||
if is_relation:
|
||||
rel_to = "self" if relations[i][1] == table_name else table2model(relations[i][1])
|
||||
if rel_to in known_models:
|
||||
field_type = 'ForeignKey(%s' % rel_to
|
||||
else:
|
||||
field_type = "ForeignKey('%s'" % rel_to
|
||||
else:
|
||||
extra_params['blank'] = True
|
||||
if not field_type in ('TextField(', 'CharField('):
|
||||
extra_params['null'] = True
|
||||
# Calling `get_field_type` to get the field type string and any
|
||||
# additional paramters and notes.
|
||||
field_type, field_params, field_notes = self.get_field_type(connection, table_name, row)
|
||||
extra_params.update(field_params)
|
||||
comment_notes.extend(field_notes)
|
||||
|
||||
field_desc = '%s = %s%s' % (
|
||||
att_name,
|
||||
# Custom fields will have a dotted path
|
||||
'' if '.' in field_type else 'models.',
|
||||
field_type,
|
||||
)
|
||||
if extra_params:
|
||||
if not field_desc.endswith('('):
|
||||
field_desc += ', '
|
||||
field_desc += ', '.join([
|
||||
'%s=%s' % (k, strip_prefix(repr(v)))
|
||||
for k, v in extra_params.items()])
|
||||
field_desc += ')'
|
||||
if comment_notes:
|
||||
field_desc += ' # ' + ' '.join(comment_notes)
|
||||
yield ' %s' % field_desc
|
||||
for meta_line in self.get_meta(table_name):
|
||||
yield meta_line
|
||||
field_type += '('
|
||||
|
||||
# Don't output 'id = meta.AutoField(primary_key=True)', because
|
||||
# that's assumed if it doesn't exist.
|
||||
if att_name == 'id' and extra_params == {'primary_key': True}:
|
||||
if field_type == 'AutoField(':
|
||||
continue
|
||||
elif field_type == 'IntegerField(' and not connection.features.can_introspect_autofield:
|
||||
comment_notes.append('AutoField?')
|
||||
|
||||
# Add 'null' and 'blank', if the 'null_ok' flag was present in the
|
||||
# table description.
|
||||
if row[6]: # If it's NULL...
|
||||
if field_type == 'BooleanField(':
|
||||
field_type = 'NullBooleanField('
|
||||
else:
|
||||
extra_params['blank'] = True
|
||||
if not field_type in ('TextField(', 'CharField('):
|
||||
extra_params['null'] = True
|
||||
|
||||
field_desc = '%s = %s%s' % (
|
||||
att_name,
|
||||
# Custom fields will have a dotted path
|
||||
'' if '.' in field_type else 'models.',
|
||||
field_type,
|
||||
)
|
||||
if extra_params:
|
||||
if not field_desc.endswith('('):
|
||||
field_desc += ', '
|
||||
field_desc += ', '.join([
|
||||
'%s=%s' % (k, strip_prefix(repr(v)))
|
||||
for k, v in extra_params.items()])
|
||||
field_desc += ')'
|
||||
if comment_notes:
|
||||
field_desc += ' # ' + ' '.join(comment_notes)
|
||||
yield ' %s' % field_desc
|
||||
for meta_line in self.get_meta(table_name):
|
||||
yield meta_line
|
||||
|
||||
def normalize_col_name(self, col_name, used_column_names, is_relation):
|
||||
"""
|
||||
|
||||
@@ -100,10 +100,9 @@ class Command(BaseCommand):
|
||||
if sequence_sql:
|
||||
if self.verbosity >= 2:
|
||||
self.stdout.write("Resetting sequences\n")
|
||||
cursor = connection.cursor()
|
||||
for line in sequence_sql:
|
||||
cursor.execute(line)
|
||||
cursor.close()
|
||||
with connection.cursor() as cursor:
|
||||
for line in sequence_sql:
|
||||
cursor.execute(line)
|
||||
|
||||
if self.verbosity >= 1:
|
||||
if self.fixture_object_count == self.loaded_object_count:
|
||||
|
||||
@@ -171,105 +171,110 @@ class Command(BaseCommand):
|
||||
"Runs the old syncdb-style operation on a list of app_labels."
|
||||
cursor = connection.cursor()
|
||||
|
||||
# Get a list of already installed *models* so that references work right.
|
||||
tables = connection.introspection.table_names()
|
||||
seen_models = connection.introspection.installed_models(tables)
|
||||
created_models = set()
|
||||
pending_references = {}
|
||||
try:
|
||||
# Get a list of already installed *models* so that references work right.
|
||||
tables = connection.introspection.table_names(cursor)
|
||||
seen_models = connection.introspection.installed_models(tables)
|
||||
created_models = set()
|
||||
pending_references = {}
|
||||
|
||||
# Build the manifest of apps and models that are to be synchronized
|
||||
all_models = [
|
||||
(app_config.label,
|
||||
router.get_migratable_models(app_config, connection.alias, include_auto_created=True))
|
||||
for app_config in apps.get_app_configs()
|
||||
if app_config.models_module is not None and app_config.label in app_labels
|
||||
]
|
||||
# Build the manifest of apps and models that are to be synchronized
|
||||
all_models = [
|
||||
(app_config.label,
|
||||
router.get_migratable_models(app_config, connection.alias, include_auto_created=True))
|
||||
for app_config in apps.get_app_configs()
|
||||
if app_config.models_module is not None and app_config.label in app_labels
|
||||
]
|
||||
|
||||
def model_installed(model):
|
||||
opts = model._meta
|
||||
converter = connection.introspection.table_name_converter
|
||||
# Note that if a model is unmanaged we short-circuit and never try to install it
|
||||
return not ((converter(opts.db_table) in tables) or
|
||||
(opts.auto_created and converter(opts.auto_created._meta.db_table) in tables))
|
||||
def model_installed(model):
|
||||
opts = model._meta
|
||||
converter = connection.introspection.table_name_converter
|
||||
# Note that if a model is unmanaged we short-circuit and never try to install it
|
||||
return not ((converter(opts.db_table) in tables) or
|
||||
(opts.auto_created and converter(opts.auto_created._meta.db_table) in tables))
|
||||
|
||||
manifest = OrderedDict(
|
||||
(app_name, list(filter(model_installed, model_list)))
|
||||
for app_name, model_list in all_models
|
||||
)
|
||||
manifest = OrderedDict(
|
||||
(app_name, list(filter(model_installed, model_list)))
|
||||
for app_name, model_list in all_models
|
||||
)
|
||||
|
||||
create_models = set(itertools.chain(*manifest.values()))
|
||||
emit_pre_migrate_signal(create_models, self.verbosity, self.interactive, connection.alias)
|
||||
create_models = set(itertools.chain(*manifest.values()))
|
||||
emit_pre_migrate_signal(create_models, self.verbosity, self.interactive, connection.alias)
|
||||
|
||||
# Create the tables for each model
|
||||
if self.verbosity >= 1:
|
||||
self.stdout.write(" Creating tables...\n")
|
||||
with transaction.atomic(using=connection.alias, savepoint=False):
|
||||
for app_name, model_list in manifest.items():
|
||||
for model in model_list:
|
||||
# Create the model's database table, if it doesn't already exist.
|
||||
if self.verbosity >= 3:
|
||||
self.stdout.write(" Processing %s.%s model\n" % (app_name, model._meta.object_name))
|
||||
sql, references = connection.creation.sql_create_model(model, no_style(), seen_models)
|
||||
seen_models.add(model)
|
||||
created_models.add(model)
|
||||
for refto, refs in references.items():
|
||||
pending_references.setdefault(refto, []).extend(refs)
|
||||
if refto in seen_models:
|
||||
sql.extend(connection.creation.sql_for_pending_references(refto, no_style(), pending_references))
|
||||
sql.extend(connection.creation.sql_for_pending_references(model, no_style(), pending_references))
|
||||
if self.verbosity >= 1 and sql:
|
||||
self.stdout.write(" Creating table %s\n" % model._meta.db_table)
|
||||
for statement in sql:
|
||||
cursor.execute(statement)
|
||||
tables.append(connection.introspection.table_name_converter(model._meta.db_table))
|
||||
# Create the tables for each model
|
||||
if self.verbosity >= 1:
|
||||
self.stdout.write(" Creating tables...\n")
|
||||
with transaction.atomic(using=connection.alias, savepoint=False):
|
||||
for app_name, model_list in manifest.items():
|
||||
for model in model_list:
|
||||
# Create the model's database table, if it doesn't already exist.
|
||||
if self.verbosity >= 3:
|
||||
self.stdout.write(" Processing %s.%s model\n" % (app_name, model._meta.object_name))
|
||||
sql, references = connection.creation.sql_create_model(model, no_style(), seen_models)
|
||||
seen_models.add(model)
|
||||
created_models.add(model)
|
||||
for refto, refs in references.items():
|
||||
pending_references.setdefault(refto, []).extend(refs)
|
||||
if refto in seen_models:
|
||||
sql.extend(connection.creation.sql_for_pending_references(refto, no_style(), pending_references))
|
||||
sql.extend(connection.creation.sql_for_pending_references(model, no_style(), pending_references))
|
||||
if self.verbosity >= 1 and sql:
|
||||
self.stdout.write(" Creating table %s\n" % model._meta.db_table)
|
||||
for statement in sql:
|
||||
cursor.execute(statement)
|
||||
tables.append(connection.introspection.table_name_converter(model._meta.db_table))
|
||||
|
||||
# We force a commit here, as that was the previous behaviour.
|
||||
# If you can prove we don't need this, remove it.
|
||||
transaction.set_dirty(using=connection.alias)
|
||||
# We force a commit here, as that was the previous behaviour.
|
||||
# If you can prove we don't need this, remove it.
|
||||
transaction.set_dirty(using=connection.alias)
|
||||
finally:
|
||||
cursor.close()
|
||||
|
||||
# The connection may have been closed by a syncdb handler.
|
||||
cursor = connection.cursor()
|
||||
try:
|
||||
# Install custom SQL for the app (but only if this
|
||||
# is a model we've just created)
|
||||
if self.verbosity >= 1:
|
||||
self.stdout.write(" Installing custom SQL...\n")
|
||||
for app_name, model_list in manifest.items():
|
||||
for model in model_list:
|
||||
if model in created_models:
|
||||
custom_sql = custom_sql_for_model(model, no_style(), connection)
|
||||
if custom_sql:
|
||||
if self.verbosity >= 2:
|
||||
self.stdout.write(" Installing custom SQL for %s.%s model\n" % (app_name, model._meta.object_name))
|
||||
try:
|
||||
with transaction.commit_on_success_unless_managed(using=connection.alias):
|
||||
for sql in custom_sql:
|
||||
cursor.execute(sql)
|
||||
except Exception as e:
|
||||
self.stderr.write(" Failed to install custom SQL for %s.%s model: %s\n" % (app_name, model._meta.object_name, e))
|
||||
if self.show_traceback:
|
||||
traceback.print_exc()
|
||||
else:
|
||||
if self.verbosity >= 3:
|
||||
self.stdout.write(" No custom SQL for %s.%s model\n" % (app_name, model._meta.object_name))
|
||||
|
||||
# Install custom SQL for the app (but only if this
|
||||
# is a model we've just created)
|
||||
if self.verbosity >= 1:
|
||||
self.stdout.write(" Installing custom SQL...\n")
|
||||
for app_name, model_list in manifest.items():
|
||||
for model in model_list:
|
||||
if model in created_models:
|
||||
custom_sql = custom_sql_for_model(model, no_style(), connection)
|
||||
if custom_sql:
|
||||
if self.verbosity >= 2:
|
||||
self.stdout.write(" Installing custom SQL for %s.%s model\n" % (app_name, model._meta.object_name))
|
||||
try:
|
||||
with transaction.commit_on_success_unless_managed(using=connection.alias):
|
||||
for sql in custom_sql:
|
||||
cursor.execute(sql)
|
||||
except Exception as e:
|
||||
self.stderr.write(" Failed to install custom SQL for %s.%s model: %s\n" % (app_name, model._meta.object_name, e))
|
||||
if self.show_traceback:
|
||||
traceback.print_exc()
|
||||
else:
|
||||
if self.verbosity >= 3:
|
||||
self.stdout.write(" No custom SQL for %s.%s model\n" % (app_name, model._meta.object_name))
|
||||
if self.verbosity >= 1:
|
||||
self.stdout.write(" Installing indexes...\n")
|
||||
|
||||
if self.verbosity >= 1:
|
||||
self.stdout.write(" Installing indexes...\n")
|
||||
|
||||
# Install SQL indices for all newly created models
|
||||
for app_name, model_list in manifest.items():
|
||||
for model in model_list:
|
||||
if model in created_models:
|
||||
index_sql = connection.creation.sql_indexes_for_model(model, no_style())
|
||||
if index_sql:
|
||||
if self.verbosity >= 2:
|
||||
self.stdout.write(" Installing index for %s.%s model\n" % (app_name, model._meta.object_name))
|
||||
try:
|
||||
with transaction.commit_on_success_unless_managed(using=connection.alias):
|
||||
for sql in index_sql:
|
||||
cursor.execute(sql)
|
||||
except Exception as e:
|
||||
self.stderr.write(" Failed to install index for %s.%s model: %s\n" % (app_name, model._meta.object_name, e))
|
||||
# Install SQL indices for all newly created models
|
||||
for app_name, model_list in manifest.items():
|
||||
for model in model_list:
|
||||
if model in created_models:
|
||||
index_sql = connection.creation.sql_indexes_for_model(model, no_style())
|
||||
if index_sql:
|
||||
if self.verbosity >= 2:
|
||||
self.stdout.write(" Installing index for %s.%s model\n" % (app_name, model._meta.object_name))
|
||||
try:
|
||||
with transaction.commit_on_success_unless_managed(using=connection.alias):
|
||||
for sql in index_sql:
|
||||
cursor.execute(sql)
|
||||
except Exception as e:
|
||||
self.stderr.write(" Failed to install index for %s.%s model: %s\n" % (app_name, model._meta.object_name, e))
|
||||
finally:
|
||||
cursor.close()
|
||||
|
||||
# Load initial_data fixtures (unless that has been disabled)
|
||||
if self.load_initial_data:
|
||||
|
||||
@@ -67,38 +67,39 @@ def sql_delete(app_config, style, connection):
|
||||
except Exception:
|
||||
cursor = None
|
||||
|
||||
# Figure out which tables already exist
|
||||
if cursor:
|
||||
table_names = connection.introspection.table_names(cursor)
|
||||
else:
|
||||
table_names = []
|
||||
try:
|
||||
# Figure out which tables already exist
|
||||
if cursor:
|
||||
table_names = connection.introspection.table_names(cursor)
|
||||
else:
|
||||
table_names = []
|
||||
|
||||
output = []
|
||||
output = []
|
||||
|
||||
# Output DROP TABLE statements for standard application tables.
|
||||
to_delete = set()
|
||||
# Output DROP TABLE statements for standard application tables.
|
||||
to_delete = set()
|
||||
|
||||
references_to_delete = {}
|
||||
app_models = router.get_migratable_models(app_config, connection.alias, include_auto_created=True)
|
||||
for model in app_models:
|
||||
if cursor and connection.introspection.table_name_converter(model._meta.db_table) in table_names:
|
||||
# The table exists, so it needs to be dropped
|
||||
opts = model._meta
|
||||
for f in opts.local_fields:
|
||||
if f.rel and f.rel.to not in to_delete:
|
||||
references_to_delete.setdefault(f.rel.to, []).append((model, f))
|
||||
references_to_delete = {}
|
||||
app_models = router.get_migratable_models(app_config, connection.alias, include_auto_created=True)
|
||||
for model in app_models:
|
||||
if cursor and connection.introspection.table_name_converter(model._meta.db_table) in table_names:
|
||||
# The table exists, so it needs to be dropped
|
||||
opts = model._meta
|
||||
for f in opts.local_fields:
|
||||
if f.rel and f.rel.to not in to_delete:
|
||||
references_to_delete.setdefault(f.rel.to, []).append((model, f))
|
||||
|
||||
to_delete.add(model)
|
||||
to_delete.add(model)
|
||||
|
||||
for model in app_models:
|
||||
if connection.introspection.table_name_converter(model._meta.db_table) in table_names:
|
||||
output.extend(connection.creation.sql_destroy_model(model, references_to_delete, style))
|
||||
|
||||
# Close database connection explicitly, in case this output is being piped
|
||||
# directly into a database client, to avoid locking issues.
|
||||
if cursor:
|
||||
cursor.close()
|
||||
connection.close()
|
||||
for model in app_models:
|
||||
if connection.introspection.table_name_converter(model._meta.db_table) in table_names:
|
||||
output.extend(connection.creation.sql_destroy_model(model, references_to_delete, style))
|
||||
finally:
|
||||
# Close database connection explicitly, in case this output is being piped
|
||||
# directly into a database client, to avoid locking issues.
|
||||
if cursor:
|
||||
cursor.close()
|
||||
connection.close()
|
||||
|
||||
return output[::-1] # Reverse it, to deal with table dependencies.
|
||||
|
||||
|
||||
@@ -194,13 +194,16 @@ class BaseDatabaseWrapper(object):
|
||||
##### Backend-specific savepoint management methods #####
|
||||
|
||||
def _savepoint(self, sid):
|
||||
self.cursor().execute(self.ops.savepoint_create_sql(sid))
|
||||
with self.cursor() as cursor:
|
||||
cursor.execute(self.ops.savepoint_create_sql(sid))
|
||||
|
||||
def _savepoint_rollback(self, sid):
|
||||
self.cursor().execute(self.ops.savepoint_rollback_sql(sid))
|
||||
with self.cursor() as cursor:
|
||||
cursor.execute(self.ops.savepoint_rollback_sql(sid))
|
||||
|
||||
def _savepoint_commit(self, sid):
|
||||
self.cursor().execute(self.ops.savepoint_commit_sql(sid))
|
||||
with self.cursor() as cursor:
|
||||
cursor.execute(self.ops.savepoint_commit_sql(sid))
|
||||
|
||||
def _savepoint_allowed(self):
|
||||
# Savepoints cannot be created outside a transaction
|
||||
@@ -688,15 +691,15 @@ class BaseDatabaseFeatures(object):
|
||||
# otherwise autocommit will cause the confimation to
|
||||
# fail.
|
||||
self.connection.enter_transaction_management()
|
||||
cursor = self.connection.cursor()
|
||||
cursor.execute('CREATE TABLE ROLLBACK_TEST (X INT)')
|
||||
self.connection.commit()
|
||||
cursor.execute('INSERT INTO ROLLBACK_TEST (X) VALUES (8)')
|
||||
self.connection.rollback()
|
||||
cursor.execute('SELECT COUNT(X) FROM ROLLBACK_TEST')
|
||||
count, = cursor.fetchone()
|
||||
cursor.execute('DROP TABLE ROLLBACK_TEST')
|
||||
self.connection.commit()
|
||||
with self.connection.cursor() as cursor:
|
||||
cursor.execute('CREATE TABLE ROLLBACK_TEST (X INT)')
|
||||
self.connection.commit()
|
||||
cursor.execute('INSERT INTO ROLLBACK_TEST (X) VALUES (8)')
|
||||
self.connection.rollback()
|
||||
cursor.execute('SELECT COUNT(X) FROM ROLLBACK_TEST')
|
||||
count, = cursor.fetchone()
|
||||
cursor.execute('DROP TABLE ROLLBACK_TEST')
|
||||
self.connection.commit()
|
||||
finally:
|
||||
self.connection.leave_transaction_management()
|
||||
return count == 0
|
||||
@@ -1253,7 +1256,8 @@ class BaseDatabaseIntrospection(object):
|
||||
in sorting order between databases.
|
||||
"""
|
||||
if cursor is None:
|
||||
cursor = self.connection.cursor()
|
||||
with self.connection.cursor() as cursor:
|
||||
return sorted(self.get_table_list(cursor))
|
||||
return sorted(self.get_table_list(cursor))
|
||||
|
||||
def get_table_list(self, cursor):
|
||||
|
||||
@@ -378,9 +378,8 @@ class BaseDatabaseCreation(object):
|
||||
|
||||
call_command('createcachetable', database=self.connection.alias)
|
||||
|
||||
# Get a cursor (even though we don't need one yet). This has
|
||||
# the side effect of initializing the test database.
|
||||
self.connection.cursor()
|
||||
# Ensure a connection for the side effect of initializing the test database.
|
||||
self.connection.ensure_connection()
|
||||
|
||||
return test_database_name
|
||||
|
||||
@@ -406,34 +405,34 @@ class BaseDatabaseCreation(object):
|
||||
qn = self.connection.ops.quote_name
|
||||
|
||||
# Create the test database and connect to it.
|
||||
cursor = self._nodb_connection.cursor()
|
||||
try:
|
||||
cursor.execute(
|
||||
"CREATE DATABASE %s %s" % (qn(test_database_name), suffix))
|
||||
except Exception as e:
|
||||
sys.stderr.write(
|
||||
"Got an error creating the test database: %s\n" % e)
|
||||
if not autoclobber:
|
||||
confirm = input(
|
||||
"Type 'yes' if you would like to try deleting the test "
|
||||
"database '%s', or 'no' to cancel: " % test_database_name)
|
||||
if autoclobber or confirm == 'yes':
|
||||
try:
|
||||
if verbosity >= 1:
|
||||
print("Destroying old test database '%s'..."
|
||||
% self.connection.alias)
|
||||
cursor.execute(
|
||||
"DROP DATABASE %s" % qn(test_database_name))
|
||||
cursor.execute(
|
||||
"CREATE DATABASE %s %s" % (qn(test_database_name),
|
||||
suffix))
|
||||
except Exception as e:
|
||||
sys.stderr.write(
|
||||
"Got an error recreating the test database: %s\n" % e)
|
||||
sys.exit(2)
|
||||
else:
|
||||
print("Tests cancelled.")
|
||||
sys.exit(1)
|
||||
with self._nodb_connection.cursor() as cursor:
|
||||
try:
|
||||
cursor.execute(
|
||||
"CREATE DATABASE %s %s" % (qn(test_database_name), suffix))
|
||||
except Exception as e:
|
||||
sys.stderr.write(
|
||||
"Got an error creating the test database: %s\n" % e)
|
||||
if not autoclobber:
|
||||
confirm = input(
|
||||
"Type 'yes' if you would like to try deleting the test "
|
||||
"database '%s', or 'no' to cancel: " % test_database_name)
|
||||
if autoclobber or confirm == 'yes':
|
||||
try:
|
||||
if verbosity >= 1:
|
||||
print("Destroying old test database '%s'..."
|
||||
% self.connection.alias)
|
||||
cursor.execute(
|
||||
"DROP DATABASE %s" % qn(test_database_name))
|
||||
cursor.execute(
|
||||
"CREATE DATABASE %s %s" % (qn(test_database_name),
|
||||
suffix))
|
||||
except Exception as e:
|
||||
sys.stderr.write(
|
||||
"Got an error recreating the test database: %s\n" % e)
|
||||
sys.exit(2)
|
||||
else:
|
||||
print("Tests cancelled.")
|
||||
sys.exit(1)
|
||||
|
||||
return test_database_name
|
||||
|
||||
@@ -461,11 +460,11 @@ class BaseDatabaseCreation(object):
|
||||
# ourselves. Connect to the previous database (not the test database)
|
||||
# to do so, because it's not allowed to delete a database while being
|
||||
# connected to it.
|
||||
cursor = self._nodb_connection.cursor()
|
||||
# Wait to avoid "database is being accessed by other users" errors.
|
||||
time.sleep(1)
|
||||
cursor.execute("DROP DATABASE %s"
|
||||
% self.connection.ops.quote_name(test_database_name))
|
||||
with self._nodb_connection.cursor() as cursor:
|
||||
# Wait to avoid "database is being accessed by other users" errors.
|
||||
time.sleep(1)
|
||||
cursor.execute("DROP DATABASE %s"
|
||||
% self.connection.ops.quote_name(test_database_name))
|
||||
|
||||
def set_autocommit(self):
|
||||
"""
|
||||
|
||||
@@ -180,15 +180,15 @@ class DatabaseFeatures(BaseDatabaseFeatures):
|
||||
@cached_property
|
||||
def _mysql_storage_engine(self):
|
||||
"Internal method used in Django tests. Don't rely on this from your code"
|
||||
cursor = self.connection.cursor()
|
||||
cursor.execute('CREATE TABLE INTROSPECT_TEST (X INT)')
|
||||
# This command is MySQL specific; the second column
|
||||
# will tell you the default table type of the created
|
||||
# table. Since all Django's test tables will have the same
|
||||
# table type, that's enough to evaluate the feature.
|
||||
cursor.execute("SHOW TABLE STATUS WHERE Name='INTROSPECT_TEST'")
|
||||
result = cursor.fetchone()
|
||||
cursor.execute('DROP TABLE INTROSPECT_TEST')
|
||||
with self.connection.cursor() as cursor:
|
||||
cursor.execute('CREATE TABLE INTROSPECT_TEST (X INT)')
|
||||
# This command is MySQL specific; the second column
|
||||
# will tell you the default table type of the created
|
||||
# table. Since all Django's test tables will have the same
|
||||
# table type, that's enough to evaluate the feature.
|
||||
cursor.execute("SHOW TABLE STATUS WHERE Name='INTROSPECT_TEST'")
|
||||
result = cursor.fetchone()
|
||||
cursor.execute('DROP TABLE INTROSPECT_TEST')
|
||||
return result[1]
|
||||
|
||||
@cached_property
|
||||
@@ -207,9 +207,9 @@ class DatabaseFeatures(BaseDatabaseFeatures):
|
||||
return False
|
||||
|
||||
# Test if the time zone definitions are installed.
|
||||
cursor = self.connection.cursor()
|
||||
cursor.execute("SELECT 1 FROM mysql.time_zone LIMIT 1")
|
||||
return cursor.fetchone() is not None
|
||||
with self.connection.cursor() as cursor:
|
||||
cursor.execute("SELECT 1 FROM mysql.time_zone LIMIT 1")
|
||||
return cursor.fetchone() is not None
|
||||
|
||||
|
||||
class DatabaseOperations(BaseDatabaseOperations):
|
||||
@@ -461,13 +461,12 @@ class DatabaseWrapper(BaseDatabaseWrapper):
|
||||
return conn
|
||||
|
||||
def init_connection_state(self):
|
||||
cursor = self.connection.cursor()
|
||||
# SQL_AUTO_IS_NULL in MySQL controls whether an AUTO_INCREMENT column
|
||||
# on a recently-inserted row will return when the field is tested for
|
||||
# NULL. Disabling this value brings this aspect of MySQL in line with
|
||||
# SQL standards.
|
||||
cursor.execute('SET SQL_AUTO_IS_NULL = 0')
|
||||
cursor.close()
|
||||
with self.connection.cursor() as cursor:
|
||||
# SQL_AUTO_IS_NULL in MySQL controls whether an AUTO_INCREMENT column
|
||||
# on a recently-inserted row will return when the field is tested for
|
||||
# NULL. Disabling this value brings this aspect of MySQL in line with
|
||||
# SQL standards.
|
||||
cursor.execute('SET SQL_AUTO_IS_NULL = 0')
|
||||
|
||||
def create_cursor(self):
|
||||
cursor = self.connection.cursor()
|
||||
|
||||
@@ -353,8 +353,8 @@ WHEN (new.%(col_name)s IS NULL)
|
||||
def regex_lookup(self, lookup_type):
|
||||
# If regex_lookup is called before it's been initialized, then create
|
||||
# a cursor to initialize it and recur.
|
||||
self.connection.cursor()
|
||||
return self.connection.ops.regex_lookup(lookup_type)
|
||||
with self.connection.cursor():
|
||||
return self.connection.ops.regex_lookup(lookup_type)
|
||||
|
||||
def return_insert_id(self):
|
||||
return "RETURNING %s INTO %%s", (InsertIdVar(),)
|
||||
|
||||
@@ -149,8 +149,10 @@ class DatabaseWrapper(BaseDatabaseWrapper):
|
||||
|
||||
if conn_tz != tz:
|
||||
cursor = self.connection.cursor()
|
||||
cursor.execute(self.ops.set_time_zone_sql(), [tz])
|
||||
cursor.close()
|
||||
try:
|
||||
cursor.execute(self.ops.set_time_zone_sql(), [tz])
|
||||
finally:
|
||||
cursor.close()
|
||||
# Commit after setting the time zone (see #17062)
|
||||
if not self.get_autocommit():
|
||||
self.connection.commit()
|
||||
|
||||
@@ -39,6 +39,6 @@ def get_version(connection):
|
||||
if hasattr(connection, 'server_version'):
|
||||
return connection.server_version
|
||||
else:
|
||||
cursor = connection.cursor()
|
||||
cursor.execute("SELECT version()")
|
||||
return _parse_version(cursor.fetchone()[0])
|
||||
with connection.cursor() as cursor:
|
||||
cursor.execute("SELECT version()")
|
||||
return _parse_version(cursor.fetchone()[0])
|
||||
|
||||
@@ -86,14 +86,13 @@ class BaseDatabaseSchemaEditor(object):
|
||||
"""
|
||||
Executes the given SQL statement, with optional parameters.
|
||||
"""
|
||||
# Get the cursor
|
||||
cursor = self.connection.cursor()
|
||||
# Log the command we're running, then run it
|
||||
logger.debug("%s; (params %r)" % (sql, params))
|
||||
if self.collect_sql:
|
||||
self.collected_sql.append((sql % tuple(map(self.connection.ops.quote_parameter, params))) + ";")
|
||||
else:
|
||||
cursor.execute(sql, params)
|
||||
with self.connection.cursor() as cursor:
|
||||
cursor.execute(sql, params)
|
||||
|
||||
def quote_name(self, name):
|
||||
return self.connection.ops.quote_name(name)
|
||||
@@ -791,7 +790,8 @@ class BaseDatabaseSchemaEditor(object):
|
||||
Returns all constraint names matching the columns and conditions
|
||||
"""
|
||||
column_names = list(column_names) if column_names else None
|
||||
constraints = self.connection.introspection.get_constraints(self.connection.cursor(), model._meta.db_table)
|
||||
with self.connection.cursor() as cursor:
|
||||
constraints = self.connection.introspection.get_constraints(cursor, model._meta.db_table)
|
||||
result = []
|
||||
for name, infodict in constraints.items():
|
||||
if column_names is None or column_names == infodict['columns']:
|
||||
|
||||
@@ -122,14 +122,14 @@ class DatabaseFeatures(BaseDatabaseFeatures):
|
||||
rule out support for STDDEV. We need to manually check
|
||||
whether the call works.
|
||||
"""
|
||||
cursor = self.connection.cursor()
|
||||
cursor.execute('CREATE TABLE STDDEV_TEST (X INT)')
|
||||
try:
|
||||
cursor.execute('SELECT STDDEV(*) FROM STDDEV_TEST')
|
||||
has_support = True
|
||||
except utils.DatabaseError:
|
||||
has_support = False
|
||||
cursor.execute('DROP TABLE STDDEV_TEST')
|
||||
with self.connection.cursor() as cursor:
|
||||
cursor.execute('CREATE TABLE STDDEV_TEST (X INT)')
|
||||
try:
|
||||
cursor.execute('SELECT STDDEV(*) FROM STDDEV_TEST')
|
||||
has_support = True
|
||||
except utils.DatabaseError:
|
||||
has_support = False
|
||||
cursor.execute('DROP TABLE STDDEV_TEST')
|
||||
return has_support
|
||||
|
||||
@cached_property
|
||||
|
||||
@@ -1522,54 +1522,59 @@ class RawQuerySet(object):
|
||||
|
||||
query = iter(self.query)
|
||||
|
||||
# Find out which columns are model's fields, and which ones should be
|
||||
# annotated to the model.
|
||||
for pos, column in enumerate(self.columns):
|
||||
if column in self.model_fields:
|
||||
model_init_field_names[self.model_fields[column].attname] = pos
|
||||
else:
|
||||
annotation_fields.append((column, pos))
|
||||
try:
|
||||
# Find out which columns are model's fields, and which ones should be
|
||||
# annotated to the model.
|
||||
for pos, column in enumerate(self.columns):
|
||||
if column in self.model_fields:
|
||||
model_init_field_names[self.model_fields[column].attname] = pos
|
||||
else:
|
||||
annotation_fields.append((column, pos))
|
||||
|
||||
# Find out which model's fields are not present in the query.
|
||||
skip = set()
|
||||
for field in self.model._meta.fields:
|
||||
if field.attname not in model_init_field_names:
|
||||
skip.add(field.attname)
|
||||
if skip:
|
||||
if self.model._meta.pk.attname in skip:
|
||||
raise InvalidQuery('Raw query must include the primary key')
|
||||
model_cls = deferred_class_factory(self.model, skip)
|
||||
else:
|
||||
model_cls = self.model
|
||||
# All model's fields are present in the query. So, it is possible
|
||||
# to use *args based model instantation. For each field of the model,
|
||||
# record the query column position matching that field.
|
||||
model_init_field_pos = []
|
||||
# Find out which model's fields are not present in the query.
|
||||
skip = set()
|
||||
for field in self.model._meta.fields:
|
||||
model_init_field_pos.append(model_init_field_names[field.attname])
|
||||
if need_resolv_columns:
|
||||
fields = [self.model_fields.get(c, None) for c in self.columns]
|
||||
# Begin looping through the query values.
|
||||
for values in query:
|
||||
if need_resolv_columns:
|
||||
values = compiler.resolve_columns(values, fields)
|
||||
# Associate fields to values
|
||||
if field.attname not in model_init_field_names:
|
||||
skip.add(field.attname)
|
||||
if skip:
|
||||
model_init_kwargs = {}
|
||||
for attname, pos in six.iteritems(model_init_field_names):
|
||||
model_init_kwargs[attname] = values[pos]
|
||||
instance = model_cls(**model_init_kwargs)
|
||||
if self.model._meta.pk.attname in skip:
|
||||
raise InvalidQuery('Raw query must include the primary key')
|
||||
model_cls = deferred_class_factory(self.model, skip)
|
||||
else:
|
||||
model_init_args = [values[pos] for pos in model_init_field_pos]
|
||||
instance = model_cls(*model_init_args)
|
||||
if annotation_fields:
|
||||
for column, pos in annotation_fields:
|
||||
setattr(instance, column, values[pos])
|
||||
model_cls = self.model
|
||||
# All model's fields are present in the query. So, it is possible
|
||||
# to use *args based model instantation. For each field of the model,
|
||||
# record the query column position matching that field.
|
||||
model_init_field_pos = []
|
||||
for field in self.model._meta.fields:
|
||||
model_init_field_pos.append(model_init_field_names[field.attname])
|
||||
if need_resolv_columns:
|
||||
fields = [self.model_fields.get(c, None) for c in self.columns]
|
||||
# Begin looping through the query values.
|
||||
for values in query:
|
||||
if need_resolv_columns:
|
||||
values = compiler.resolve_columns(values, fields)
|
||||
# Associate fields to values
|
||||
if skip:
|
||||
model_init_kwargs = {}
|
||||
for attname, pos in six.iteritems(model_init_field_names):
|
||||
model_init_kwargs[attname] = values[pos]
|
||||
instance = model_cls(**model_init_kwargs)
|
||||
else:
|
||||
model_init_args = [values[pos] for pos in model_init_field_pos]
|
||||
instance = model_cls(*model_init_args)
|
||||
if annotation_fields:
|
||||
for column, pos in annotation_fields:
|
||||
setattr(instance, column, values[pos])
|
||||
|
||||
instance._state.db = db
|
||||
instance._state.adding = False
|
||||
instance._state.db = db
|
||||
instance._state.adding = False
|
||||
|
||||
yield instance
|
||||
yield instance
|
||||
finally:
|
||||
# Done iterating the Query. If it has its own cursor, close it.
|
||||
if hasattr(self.query, 'cursor') and self.query.cursor:
|
||||
self.query.cursor.close()
|
||||
|
||||
def __repr__(self):
|
||||
text = self.raw_query
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import datetime
|
||||
import sys
|
||||
|
||||
from django.conf import settings
|
||||
from django.core.exceptions import FieldError
|
||||
@@ -777,7 +778,7 @@ class SQLCompiler(object):
|
||||
cursor = self.connection.cursor()
|
||||
try:
|
||||
cursor.execute(sql, params)
|
||||
except:
|
||||
except Exception:
|
||||
cursor.close()
|
||||
raise
|
||||
|
||||
@@ -908,15 +909,15 @@ class SQLInsertCompiler(SQLCompiler):
|
||||
def execute_sql(self, return_id=False):
|
||||
assert not (return_id and len(self.query.objs) != 1)
|
||||
self.return_id = return_id
|
||||
cursor = self.connection.cursor()
|
||||
for sql, params in self.as_sql():
|
||||
cursor.execute(sql, params)
|
||||
if not (return_id and cursor):
|
||||
return
|
||||
if self.connection.features.can_return_id_from_insert:
|
||||
return self.connection.ops.fetch_returned_insert_id(cursor)
|
||||
return self.connection.ops.last_insert_id(cursor,
|
||||
self.query.get_meta().db_table, self.query.get_meta().pk.column)
|
||||
with self.connection.cursor() as cursor:
|
||||
for sql, params in self.as_sql():
|
||||
cursor.execute(sql, params)
|
||||
if not (return_id and cursor):
|
||||
return
|
||||
if self.connection.features.can_return_id_from_insert:
|
||||
return self.connection.ops.fetch_returned_insert_id(cursor)
|
||||
return self.connection.ops.last_insert_id(cursor,
|
||||
self.query.get_meta().db_table, self.query.get_meta().pk.column)
|
||||
|
||||
|
||||
class SQLDeleteCompiler(SQLCompiler):
|
||||
|
||||
Reference in New Issue
Block a user