summaryrefslogtreecommitdiff
path: root/django/db
diff options
context:
space:
mode:
authorAlex Gaynor <alex.gaynor@gmail.com>2010-08-09 21:22:37 +0000
committerAlex Gaynor <alex.gaynor@gmail.com>2010-08-09 21:22:37 +0000
commit6001ba016a3db4701d56abc6d30868d4e5d88dbf (patch)
tree7a42c57d802484300c2384d3cd3a968de1804383 /django/db
parentc7bd48cb9f645e5ff07d1e68b86130e3bb2b043f (diff)
downloaddjango-soc2010/query-refactor.tar.gz
[soc2010/query-refactor] Merged up to trunk r13556, resolved merge conflictsarchive/soc2010/query-refactorsoc2010/query-refactor
git-svn-id: http://code.djangoproject.com/svn/django/branches/soc2010/query-refactor@13565 bcc190cf-cafb-0310-a4f2-bffc1f526a37
Diffstat (limited to 'django/db')
-rw-r--r--django/db/__init__.py2
-rw-r--r--django/db/backends/creation.py17
-rw-r--r--django/db/backends/oracle/creation.py6
-rw-r--r--django/db/backends/postgresql/creation.py2
-rw-r--r--django/db/backends/postgresql/operations.py9
-rw-r--r--django/db/backends/sqlite3/creation.py6
-rw-r--r--django/db/models/base.py4
-rw-r--r--django/db/models/fields/__init__.py19
-rw-r--r--django/db/models/fields/related.py23
-rw-r--r--django/db/models/query.py5
-rw-r--r--django/db/models/signals.py10
-rw-r--r--django/db/models/sql/query.py11
12 files changed, 65 insertions, 49 deletions
diff --git a/django/db/__init__.py b/django/db/__init__.py
index 73d25e1f3a..4b85549c87 100644
--- a/django/db/__init__.py
+++ b/django/db/__init__.py
@@ -35,6 +35,8 @@ if DEFAULT_DB_ALIAS not in settings.DATABASES:
raise ImproperlyConfigured("You must default a '%s' database" % DEFAULT_DB_ALIAS)
for alias, database in settings.DATABASES.items():
+ if 'ENGINE' not in database:
+ raise ImproperlyConfigured("You must specify a 'ENGINE' for database '%s'" % alias)
if database['ENGINE'] in ("postgresql", "postgresql_psycopg2", "sqlite3", "mysql", "oracle"):
import warnings
if 'django.contrib.gis' in settings.INSTALLED_APPS:
diff --git a/django/db/backends/creation.py b/django/db/backends/creation.py
index 999d1cb5fe..c10ad9da31 100644
--- a/django/db/backends/creation.py
+++ b/django/db/backends/creation.py
@@ -359,12 +359,17 @@ class BaseDatabaseCreation(object):
can_rollback = self._rollback_works()
self.connection.settings_dict["SUPPORTS_TRANSACTIONS"] = can_rollback
- call_command('syncdb', verbosity=verbosity, interactive=False, database=self.connection.alias)
+ # Report syncdb messages at one level lower than that requested.
+ # This ensures we don't get flooded with messages during testing
+ # (unless you really ask to be flooded)
+ call_command('syncdb', verbosity=max(verbosity - 1, 0), interactive=False, database=self.connection.alias)
if settings.CACHE_BACKEND.startswith('db://'):
- from django.core.cache import parse_backend_uri
- _, cache_name, _ = parse_backend_uri(settings.CACHE_BACKEND)
- call_command('createcachetable', cache_name)
+ from django.core.cache import parse_backend_uri, cache
+ from django.db import router
+ if router.allow_syncdb(self.connection.alias, cache.cache_model_class):
+ _, cache_name, _ = parse_backend_uri(settings.CACHE_BACKEND)
+ call_command('createcachetable', cache_name, 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.
@@ -397,10 +402,8 @@ class BaseDatabaseCreation(object):
if autoclobber or confirm == 'yes':
try:
if verbosity >= 1:
- print "Destroying old test database..."
+ print "Destroying old test database '%s'..." % self.connection.alias
cursor.execute("DROP DATABASE %s" % qn(test_database_name))
- if verbosity >= 1:
- print "Creating test database..."
cursor.execute("CREATE DATABASE %s %s" % (qn(test_database_name), suffix))
except Exception, e:
sys.stderr.write("Got an error recreating the test database: %s\n" % e)
diff --git a/django/db/backends/oracle/creation.py b/django/db/backends/oracle/creation.py
index e6e242b9f7..8167640aac 100644
--- a/django/db/backends/oracle/creation.py
+++ b/django/db/backends/oracle/creation.py
@@ -61,8 +61,6 @@ class DatabaseCreation(BaseDatabaseCreation):
cursor = self.connection.cursor()
if self._test_database_create():
- if verbosity >= 1:
- print 'Creating test database...'
try:
self._execute_test_db_creation(cursor, parameters, verbosity)
except Exception, e:
@@ -72,10 +70,8 @@ class DatabaseCreation(BaseDatabaseCreation):
if autoclobber or confirm == 'yes':
try:
if verbosity >= 1:
- print "Destroying old test database..."
+ print "Destroying old test database '%s'..." % self.connection.alias
self._execute_test_db_destruction(cursor, parameters, verbosity)
- if verbosity >= 1:
- print "Creating test database..."
self._execute_test_db_creation(cursor, parameters, verbosity)
except Exception, e:
sys.stderr.write("Got an error recreating the test database: %s\n" % e)
diff --git a/django/db/backends/postgresql/creation.py b/django/db/backends/postgresql/creation.py
index e3587f0e37..9984716389 100644
--- a/django/db/backends/postgresql/creation.py
+++ b/django/db/backends/postgresql/creation.py
@@ -64,7 +64,7 @@ class DatabaseCreation(BaseDatabaseCreation):
# a second index that specifies their operator class, which is
# needed when performing correct LIKE queries outside the
# C locale. See #12234.
- db_type = f.db_type()
+ db_type = f.db_type(connection=self.connection)
if db_type.startswith('varchar'):
output.append(get_index_sql('%s_%s_like' % (db_table, f.column),
' varchar_pattern_ops'))
diff --git a/django/db/backends/postgresql/operations.py b/django/db/backends/postgresql/operations.py
index e5dd0fdd11..d55aae93bc 100644
--- a/django/db/backends/postgresql/operations.py
+++ b/django/db/backends/postgresql/operations.py
@@ -55,7 +55,8 @@ class DatabaseOperations(BaseDatabaseOperations):
def last_insert_id(self, cursor, table_name, pk_name):
# Use pg_get_serial_sequence to get the underlying sequence name
# from the table name and column name (available since PostgreSQL 8)
- cursor.execute("SELECT CURRVAL(pg_get_serial_sequence('%s','%s'))" % (table_name, pk_name))
+ cursor.execute("SELECT CURRVAL(pg_get_serial_sequence('%s','%s'))" % (
+ self.quote_name(table_name), pk_name))
return cursor.fetchone()[0]
def no_limit_value(self):
@@ -97,7 +98,7 @@ class DatabaseOperations(BaseDatabaseOperations):
column_name = 'id'
sql.append("%s setval(pg_get_serial_sequence('%s','%s'), 1, false);" % \
(style.SQL_KEYWORD('SELECT'),
- style.SQL_TABLE(table_name),
+ style.SQL_TABLE(self.quote_name(table_name)),
style.SQL_FIELD(column_name))
)
return sql
@@ -119,7 +120,7 @@ class DatabaseOperations(BaseDatabaseOperations):
if isinstance(f, models.BaseAutoField):
output.append("%s setval(pg_get_serial_sequence('%s','%s'), coalesce(max(%s), 1), max(%s) %s null) %s %s;" % \
(style.SQL_KEYWORD('SELECT'),
- style.SQL_TABLE(model._meta.db_table),
+ style.SQL_TABLE(qn(model._meta.db_table)),
style.SQL_FIELD(f.column),
style.SQL_FIELD(qn(f.column)),
style.SQL_FIELD(qn(f.column)),
@@ -131,7 +132,7 @@ class DatabaseOperations(BaseDatabaseOperations):
if not f.rel.through:
output.append("%s setval(pg_get_serial_sequence('%s','%s'), coalesce(max(%s), 1), max(%s) %s null) %s %s;" % \
(style.SQL_KEYWORD('SELECT'),
- style.SQL_TABLE(model._meta.db_table),
+ style.SQL_TABLE(qn(f.m2m_db_table())),
style.SQL_FIELD('id'),
style.SQL_FIELD(qn('id')),
style.SQL_FIELD(qn('id')),
diff --git a/django/db/backends/sqlite3/creation.py b/django/db/backends/sqlite3/creation.py
index 03897078a2..a65db1160b 100644
--- a/django/db/backends/sqlite3/creation.py
+++ b/django/db/backends/sqlite3/creation.py
@@ -43,14 +43,12 @@ class DatabaseCreation(BaseDatabaseCreation):
if test_database_name and test_database_name != ":memory:":
# Erase the old test database
if verbosity >= 1:
- print "Destroying old test database..."
+ print "Destroying old test database '%s'..." % self.connection.alias
if os.access(test_database_name, os.F_OK):
if not autoclobber:
confirm = raw_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..."
os.remove(test_database_name)
except Exception, e:
sys.stderr.write("Got an error deleting the old test database: %s\n" % e)
@@ -58,8 +56,6 @@ class DatabaseCreation(BaseDatabaseCreation):
else:
print "Tests cancelled."
sys.exit(1)
- if verbosity >= 1:
- print "Creating test database..."
else:
test_database_name = ":memory:"
return test_database_name
diff --git a/django/db/models/base.py b/django/db/models/base.py
index 3e8b54ce19..ee46b2f3c6 100644
--- a/django/db/models/base.py
+++ b/django/db/models/base.py
@@ -456,7 +456,7 @@ class Model(object):
meta = cls._meta
if origin and not meta.auto_created:
- signals.pre_save.send(sender=origin, instance=self, raw=raw)
+ signals.pre_save.send(sender=origin, instance=self, raw=raw, using=using)
# If we are in a raw save, save the object exactly as presented.
# That means that we don't try to be smart about saving attributes
@@ -542,7 +542,7 @@ class Model(object):
# Signal that the save is complete
if origin and not meta.auto_created:
signals.post_save.send(sender=origin, instance=self,
- created=(not record_exists), raw=raw)
+ created=(not record_exists), raw=raw, using=using)
save_base.alters_data = True
diff --git a/django/db/models/fields/__init__.py b/django/db/models/fields/__init__.py
index f95efd0ce3..a89b165f6f 100644
--- a/django/db/models/fields/__init__.py
+++ b/django/db/models/fields/__init__.py
@@ -469,6 +469,9 @@ class AutoField(BaseAutoField):
'invalid': _(u'This value must be an integer.'),
}
+ def get_internal_type(self):
+ return "AutoField"
+
def to_python(self, value):
if value is None:
return value
@@ -801,6 +804,14 @@ class EmailField(CharField):
kwargs['max_length'] = kwargs.get('max_length', 75)
CharField.__init__(self, *args, **kwargs)
+ def formfield(self, **kwargs):
+ # As with CharField, this will cause email validation to be performed twice
+ defaults = {
+ 'form_class': forms.EmailField,
+ }
+ defaults.update(kwargs)
+ return super(EmailField, self).formfield(**defaults)
+
class FilePathField(Field):
description = _("File path")
@@ -1111,6 +1122,14 @@ class URLField(CharField):
CharField.__init__(self, verbose_name, name, **kwargs)
self.validators.append(validators.URLValidator(verify_exists=verify_exists))
+ def formfield(self, **kwargs):
+ # As with CharField, this will cause URL validation to be performed twice
+ defaults = {
+ 'form_class': forms.URLField,
+ }
+ defaults.update(kwargs)
+ return super(URLField, self).formfield(**defaults)
+
class XMLField(TextField):
description = _("XML text")
diff --git a/django/db/models/fields/related.py b/django/db/models/fields/related.py
index 5830a794df..1634d7d974 100644
--- a/django/db/models/fields/related.py
+++ b/django/db/models/fields/related.py
@@ -566,7 +566,7 @@ def create_many_related_manager(superclass, rel=False):
# duplicate data row for symmetrical reverse entries.
signals.m2m_changed.send(sender=rel.through, action='pre_add',
instance=self.instance, reverse=self.reverse,
- model=self.model, pk_set=new_ids)
+ model=self.model, pk_set=new_ids, using=db)
# Add the ones that aren't there already
for obj_id in new_ids:
self.through._default_manager.using(db).create(**{
@@ -578,7 +578,7 @@ def create_many_related_manager(superclass, rel=False):
# duplicate data row for symmetrical reverse entries.
signals.m2m_changed.send(sender=rel.through, action='post_add',
instance=self.instance, reverse=self.reverse,
- model=self.model, pk_set=new_ids)
+ model=self.model, pk_set=new_ids, using=db)
def _remove_items(self, source_field_name, target_field_name, *objs):
# source_col_name: the PK colname in join_table for the source object
@@ -594,14 +594,16 @@ def create_many_related_manager(superclass, rel=False):
old_ids.add(obj.pk)
else:
old_ids.add(obj)
+ # Work out what DB we're operating on
+ db = router.db_for_write(self.through.__class__, instance=self.instance)
+ # Send a signal to the other end if need be.
if self.reverse or source_field_name == self.source_field_name:
# Don't send the signal when we are deleting the
# duplicate data row for symmetrical reverse entries.
signals.m2m_changed.send(sender=rel.through, action="pre_remove",
instance=self.instance, reverse=self.reverse,
- model=self.model, pk_set=old_ids)
+ model=self.model, pk_set=old_ids, using=db)
# Remove the specified objects from the join table
- db = router.db_for_write(self.through.__class__, instance=self.instance)
self.through._default_manager.using(db).filter(**{
source_field_name: self._pk_val,
'%s__in' % target_field_name: old_ids
@@ -611,17 +613,17 @@ def create_many_related_manager(superclass, rel=False):
# duplicate data row for symmetrical reverse entries.
signals.m2m_changed.send(sender=rel.through, action="post_remove",
instance=self.instance, reverse=self.reverse,
- model=self.model, pk_set=old_ids)
+ model=self.model, pk_set=old_ids, using=db)
def _clear_items(self, source_field_name):
+ db = router.db_for_write(self.through.__class__, instance=self.instance)
# source_col_name: the PK colname in join_table for the source object
if self.reverse or source_field_name == self.source_field_name:
# Don't send the signal when we are clearing the
# duplicate data rows for symmetrical reverse entries.
signals.m2m_changed.send(sender=rel.through, action="pre_clear",
instance=self.instance, reverse=self.reverse,
- model=self.model, pk_set=None)
- db = router.db_for_write(self.through.__class__, instance=self.instance)
+ model=self.model, pk_set=None, using=db)
self.through._default_manager.using(db).filter(**{
source_field_name: self._pk_val
}).delete()
@@ -630,7 +632,7 @@ def create_many_related_manager(superclass, rel=False):
# duplicate data rows for symmetrical reverse entries.
signals.m2m_changed.send(sender=rel.through, action="post_clear",
instance=self.instance, reverse=self.reverse,
- model=self.model, pk_set=None)
+ model=self.model, pk_set=None, using=db)
return ManyRelatedManager
@@ -812,6 +814,9 @@ class ForeignKey(RelatedField, Field):
to_field = to_field or (to._meta.pk and to._meta.pk.name)
kwargs['verbose_name'] = kwargs.get('verbose_name', None)
+ if 'db_index' not in kwargs:
+ kwargs['db_index'] = True
+
kwargs['rel'] = rel_class(to, to_field,
related_name=kwargs.pop('related_name', None),
limit_choices_to=kwargs.pop('limit_choices_to', None),
@@ -819,8 +824,6 @@ class ForeignKey(RelatedField, Field):
parent_link=kwargs.pop('parent_link', False))
Field.__init__(self, **kwargs)
- self.db_index = True
-
def validate(self, value, model_instance):
if self.rel.parent_link:
return
diff --git a/django/db/models/query.py b/django/db/models/query.py
index d055490713..fbd3ca6f8c 100644
--- a/django/db/models/query.py
+++ b/django/db/models/query.py
@@ -1312,7 +1312,8 @@ def delete_objects(seen_objs, using):
# Pre-notify all instances to be deleted.
for pk_val, instance in items:
if not cls._meta.auto_created:
- signals.pre_delete.send(sender=cls, instance=instance)
+ signals.pre_delete.send(sender=cls, instance=instance,
+ using=using)
pk_list = [pk for pk,instance in items]
@@ -1344,7 +1345,7 @@ def delete_objects(seen_objs, using):
setattr(instance, field.attname, None)
if not cls._meta.auto_created:
- signals.post_delete.send(sender=cls, instance=instance)
+ signals.post_delete.send(sender=cls, instance=instance, using=using)
setattr(instance, cls._meta.pk.attname, None)
if forced_managed:
diff --git a/django/db/models/signals.py b/django/db/models/signals.py
index cd0350bc01..48872e7e7f 100644
--- a/django/db/models/signals.py
+++ b/django/db/models/signals.py
@@ -5,12 +5,12 @@ class_prepared = Signal(providing_args=["class"])
pre_init = Signal(providing_args=["instance", "args", "kwargs"])
post_init = Signal(providing_args=["instance"])
-pre_save = Signal(providing_args=["instance", "raw"])
-post_save = Signal(providing_args=["instance", "raw", "created"])
+pre_save = Signal(providing_args=["instance", "raw", "using"])
+post_save = Signal(providing_args=["instance", "raw", "created", "using"])
-pre_delete = Signal(providing_args=["instance"])
-post_delete = Signal(providing_args=["instance"])
+pre_delete = Signal(providing_args=["instance", "using"])
+post_delete = Signal(providing_args=["instance", "using"])
post_syncdb = Signal(providing_args=["class", "app", "created_models", "verbosity", "interactive"])
-m2m_changed = Signal(providing_args=["action", "instance", "reverse", "model", "pk_set"])
+m2m_changed = Signal(providing_args=["action", "instance", "reverse", "model", "pk_set", "using"])
diff --git a/django/db/models/sql/query.py b/django/db/models/sql/query.py
index 6836337429..6037ae8842 100644
--- a/django/db/models/sql/query.py
+++ b/django/db/models/sql/query.py
@@ -1076,14 +1076,9 @@ class Query(object):
# exclude the "foo__in=[]" case from this handling, because
# it's short-circuited in the Where class.
# We also need to handle the case where a subquery is provided
- entry = self.where_class()
- entry.add((
- Constraint(alias, col, None, eliminatable_if=lambda connection: not getattr(connection.features, "sql_nulls", True)),
- 'isnull',
- True
- ), AND)
- entry.negate()
- self.where.add(entry, AND)
+ self.where.add(
+ (Constraint(alias, col, None, eliminatable_if=lambda connection: not getattr(connection.features, "sql_nulls", True)), 'isnull', False), AND
+ )
if can_reuse is not None:
can_reuse.update(join_list)