Fixed #12308 -- Added tablespace support to the PostgreSQL backend.
git-svn-id: http://code.djangoproject.com/svn/django/trunk@16987 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
parent
69e1e6187a
commit
246580573d
|
@ -365,6 +365,10 @@ class BaseDatabaseFeatures(object):
|
||||||
# date_interval_sql can properly handle mixed Date/DateTime fields and timedeltas
|
# date_interval_sql can properly handle mixed Date/DateTime fields and timedeltas
|
||||||
supports_mixed_date_datetime_comparisons = True
|
supports_mixed_date_datetime_comparisons = True
|
||||||
|
|
||||||
|
# Does the backend support tablespaces? Default to False because it isn't
|
||||||
|
# in the SQL standard.
|
||||||
|
supports_tablespaces = False
|
||||||
|
|
||||||
# Features that need to be confirmed at runtime
|
# Features that need to be confirmed at runtime
|
||||||
# Cache whether the confirmation has been performed.
|
# Cache whether the confirmation has been performed.
|
||||||
_confirmed = False
|
_confirmed = False
|
||||||
|
@ -696,8 +700,12 @@ class BaseDatabaseOperations(object):
|
||||||
|
|
||||||
def tablespace_sql(self, tablespace, inline=False):
|
def tablespace_sql(self, tablespace, inline=False):
|
||||||
"""
|
"""
|
||||||
Returns the SQL that will be appended to tables or rows to define
|
Returns the SQL that will be used in a query to define the tablespace.
|
||||||
a tablespace. Returns '' if the backend doesn't use tablespaces.
|
|
||||||
|
Returns '' if the backend doesn't support tablespaces.
|
||||||
|
|
||||||
|
If inline is True, the SQL is appended to a row; otherwise it's appended
|
||||||
|
to the entire CREATE TABLE or CREATE INDEX statement.
|
||||||
"""
|
"""
|
||||||
return ''
|
return ''
|
||||||
|
|
||||||
|
|
|
@ -57,7 +57,9 @@ class BaseDatabaseCreation(object):
|
||||||
if tablespace and f.unique:
|
if tablespace and f.unique:
|
||||||
# We must specify the index tablespace inline, because we
|
# We must specify the index tablespace inline, because we
|
||||||
# won't be generating a CREATE INDEX statement for this field.
|
# won't be generating a CREATE INDEX statement for this field.
|
||||||
field_output.append(self.connection.ops.tablespace_sql(tablespace, inline=True))
|
tablespace_sql = self.connection.ops.tablespace_sql(tablespace, inline=True)
|
||||||
|
if tablespace_sql:
|
||||||
|
field_output.append(tablespace_sql)
|
||||||
if f.rel:
|
if f.rel:
|
||||||
ref_output, pending = self.sql_for_inline_foreign_key_references(f, known_models, style)
|
ref_output, pending = self.sql_for_inline_foreign_key_references(f, known_models, style)
|
||||||
if pending:
|
if pending:
|
||||||
|
@ -74,7 +76,9 @@ class BaseDatabaseCreation(object):
|
||||||
full_statement.append(' %s%s' % (line, i < len(table_output)-1 and ',' or ''))
|
full_statement.append(' %s%s' % (line, i < len(table_output)-1 and ',' or ''))
|
||||||
full_statement.append(')')
|
full_statement.append(')')
|
||||||
if opts.db_tablespace:
|
if opts.db_tablespace:
|
||||||
full_statement.append(self.connection.ops.tablespace_sql(opts.db_tablespace))
|
tablespace_sql = self.connection.ops.tablespace_sql(opts.db_tablespace)
|
||||||
|
if tablespace_sql:
|
||||||
|
full_statement.append(tablespace_sql)
|
||||||
full_statement.append(';')
|
full_statement.append(';')
|
||||||
final_output.append('\n'.join(full_statement))
|
final_output.append('\n'.join(full_statement))
|
||||||
|
|
||||||
|
@ -149,11 +153,9 @@ class BaseDatabaseCreation(object):
|
||||||
qn = self.connection.ops.quote_name
|
qn = self.connection.ops.quote_name
|
||||||
tablespace = f.db_tablespace or model._meta.db_tablespace
|
tablespace = f.db_tablespace or model._meta.db_tablespace
|
||||||
if tablespace:
|
if tablespace:
|
||||||
sql = self.connection.ops.tablespace_sql(tablespace)
|
tablespace_sql = self.connection.ops.tablespace_sql(tablespace)
|
||||||
if sql:
|
if tablespace_sql:
|
||||||
tablespace_sql = ' ' + sql
|
tablespace_sql = ' ' + tablespace_sql
|
||||||
else:
|
|
||||||
tablespace_sql = ''
|
|
||||||
else:
|
else:
|
||||||
tablespace_sql = ''
|
tablespace_sql = ''
|
||||||
i_name = '%s_%s' % (model._meta.db_table, self._digest(f.column))
|
i_name = '%s_%s' % (model._meta.db_table, self._digest(f.column))
|
||||||
|
|
|
@ -79,6 +79,7 @@ class DatabaseFeatures(BaseDatabaseFeatures):
|
||||||
can_defer_constraint_checks = True
|
can_defer_constraint_checks = True
|
||||||
ignores_nulls_in_unique_constraints = False
|
ignores_nulls_in_unique_constraints = False
|
||||||
has_bulk_insert = True
|
has_bulk_insert = True
|
||||||
|
supports_tablespaces = True
|
||||||
|
|
||||||
class DatabaseOperations(BaseDatabaseOperations):
|
class DatabaseOperations(BaseDatabaseOperations):
|
||||||
compiler_module = "django.db.backends.oracle.compiler"
|
compiler_module = "django.db.backends.oracle.compiler"
|
||||||
|
@ -326,8 +327,10 @@ WHEN (new.%(col_name)s IS NULL)
|
||||||
return ''
|
return ''
|
||||||
|
|
||||||
def tablespace_sql(self, tablespace, inline=False):
|
def tablespace_sql(self, tablespace, inline=False):
|
||||||
return "%sTABLESPACE %s" % ((inline and "USING INDEX " or ""),
|
if inline:
|
||||||
self.quote_name(tablespace))
|
return "USING INDEX TABLESPACE %s" % self.quote_name(tablespace)
|
||||||
|
else:
|
||||||
|
return "TABLESPACE %s" % self.quote_name(tablespace)
|
||||||
|
|
||||||
def value_to_db_datetime(self, value):
|
def value_to_db_datetime(self, value):
|
||||||
# Oracle doesn't support tz-aware datetimes
|
# Oracle doesn't support tz-aware datetimes
|
||||||
|
|
|
@ -75,7 +75,7 @@ class DatabaseFeatures(BaseDatabaseFeatures):
|
||||||
has_select_for_update = True
|
has_select_for_update = True
|
||||||
has_select_for_update_nowait = True
|
has_select_for_update_nowait = True
|
||||||
has_bulk_insert = True
|
has_bulk_insert = True
|
||||||
|
supports_tablespaces = True
|
||||||
|
|
||||||
class DatabaseWrapper(BaseDatabaseWrapper):
|
class DatabaseWrapper(BaseDatabaseWrapper):
|
||||||
vendor = 'postgresql'
|
vendor = 'postgresql'
|
||||||
|
|
|
@ -44,11 +44,9 @@ class DatabaseCreation(BaseDatabaseCreation):
|
||||||
db_table = model._meta.db_table
|
db_table = model._meta.db_table
|
||||||
tablespace = f.db_tablespace or model._meta.db_tablespace
|
tablespace = f.db_tablespace or model._meta.db_tablespace
|
||||||
if tablespace:
|
if tablespace:
|
||||||
sql = self.connection.ops.tablespace_sql(tablespace)
|
tablespace_sql = self.connection.ops.tablespace_sql(tablespace)
|
||||||
if sql:
|
if tablespace_sql:
|
||||||
tablespace_sql = ' ' + sql
|
tablespace_sql = ' ' + tablespace_sql
|
||||||
else:
|
|
||||||
tablespace_sql = ''
|
|
||||||
else:
|
else:
|
||||||
tablespace_sql = ''
|
tablespace_sql = ''
|
||||||
|
|
||||||
|
|
|
@ -99,6 +99,12 @@ class DatabaseOperations(BaseDatabaseOperations):
|
||||||
else:
|
else:
|
||||||
return []
|
return []
|
||||||
|
|
||||||
|
def tablespace_sql(self, tablespace, inline=False):
|
||||||
|
if inline:
|
||||||
|
return "USING INDEX TABLESPACE %s" % self.quote_name(tablespace)
|
||||||
|
else:
|
||||||
|
return "TABLESPACE %s" % self.quote_name(tablespace)
|
||||||
|
|
||||||
def sequence_reset_sql(self, style, model_list):
|
def sequence_reset_sql(self, style, model_list):
|
||||||
from django.db import models
|
from django.db import models
|
||||||
output = []
|
output = []
|
||||||
|
|
|
@ -1078,6 +1078,7 @@ def create_many_to_many_intermediary_model(field, klass):
|
||||||
'managed': managed,
|
'managed': managed,
|
||||||
'auto_created': klass,
|
'auto_created': klass,
|
||||||
'app_label': klass._meta.app_label,
|
'app_label': klass._meta.app_label,
|
||||||
|
'db_tablespace': klass._meta.db_tablespace,
|
||||||
'unique_together': (from_, to),
|
'unique_together': (from_, to),
|
||||||
'verbose_name': '%(from)s-%(to)s relationship' % {'from': from_, 'to': to},
|
'verbose_name': '%(from)s-%(to)s relationship' % {'from': from_, 'to': to},
|
||||||
'verbose_name_plural': '%(from)s-%(to)s relationships' % {'from': from_, 'to': to},
|
'verbose_name_plural': '%(from)s-%(to)s relationships' % {'from': from_, 'to': to},
|
||||||
|
@ -1086,8 +1087,8 @@ def create_many_to_many_intermediary_model(field, klass):
|
||||||
return type(name, (models.Model,), {
|
return type(name, (models.Model,), {
|
||||||
'Meta': meta,
|
'Meta': meta,
|
||||||
'__module__': klass.__module__,
|
'__module__': klass.__module__,
|
||||||
from_: models.ForeignKey(klass, related_name='%s+' % name),
|
from_: models.ForeignKey(klass, related_name='%s+' % name, db_tablespace=field.db_tablespace),
|
||||||
to: models.ForeignKey(to_model, related_name='%s+' % name)
|
to: models.ForeignKey(to_model, related_name='%s+' % name, db_tablespace=field.db_tablespace)
|
||||||
})
|
})
|
||||||
|
|
||||||
class ManyToManyField(RelatedField, Field):
|
class ManyToManyField(RelatedField, Field):
|
||||||
|
|
|
@ -219,9 +219,9 @@ parameters:
|
||||||
* :attr:`~django.db.models.Field.choices`
|
* :attr:`~django.db.models.Field.choices`
|
||||||
* :attr:`~django.db.models.Field.help_text`
|
* :attr:`~django.db.models.Field.help_text`
|
||||||
* :attr:`~django.db.models.Field.db_column`
|
* :attr:`~django.db.models.Field.db_column`
|
||||||
* :attr:`~django.db.models.Field.db_tablespace`: Currently only used with
|
* :attr:`~django.db.models.Field.db_tablespace`: Only for index creation, if the
|
||||||
the Oracle backend and only for index creation. You can usually ignore
|
backend supports :doc:`tablespaces </topics/db/tablespaces>`. You can usually
|
||||||
this option.
|
ignore this option.
|
||||||
* :attr:`~django.db.models.Field.auto_created`: True if the field was
|
* :attr:`~django.db.models.Field.auto_created`: True if the field was
|
||||||
automatically created, as for the `OneToOneField` used by model
|
automatically created, as for the `OneToOneField` used by model
|
||||||
inheritance. For advanced use only.
|
inheritance. For advanced use only.
|
||||||
|
|
|
@ -646,49 +646,6 @@ The ``RETURNING INTO`` clause can be disabled by setting the
|
||||||
In this case, the Oracle backend will use a separate ``SELECT`` query to
|
In this case, the Oracle backend will use a separate ``SELECT`` query to
|
||||||
retrieve AutoField values.
|
retrieve AutoField values.
|
||||||
|
|
||||||
Tablespace options
|
|
||||||
------------------
|
|
||||||
|
|
||||||
A common paradigm for optimizing performance in Oracle-based systems is the
|
|
||||||
use of `tablespaces`_ to organize disk layout. The Oracle backend supports
|
|
||||||
this use case by adding ``db_tablespace`` options to the ``Meta`` and
|
|
||||||
``Field`` classes. (When you use a backend that lacks support for tablespaces,
|
|
||||||
Django ignores these options.)
|
|
||||||
|
|
||||||
.. _`tablespaces`: http://en.wikipedia.org/wiki/Tablespace
|
|
||||||
|
|
||||||
A tablespace can be specified for the table(s) generated by a model by
|
|
||||||
supplying the ``db_tablespace`` option inside the model's ``class Meta``.
|
|
||||||
Additionally, you can pass the ``db_tablespace`` option to a ``Field``
|
|
||||||
constructor to specify an alternate tablespace for the ``Field``'s column
|
|
||||||
index. If no index would be created for the column, the ``db_tablespace``
|
|
||||||
option is ignored::
|
|
||||||
|
|
||||||
class TablespaceExample(models.Model):
|
|
||||||
name = models.CharField(max_length=30, db_index=True, db_tablespace="indexes")
|
|
||||||
data = models.CharField(max_length=255, db_index=True)
|
|
||||||
edges = models.ManyToManyField(to="self", db_tablespace="indexes")
|
|
||||||
|
|
||||||
class Meta:
|
|
||||||
db_tablespace = "tables"
|
|
||||||
|
|
||||||
In this example, the tables generated by the ``TablespaceExample`` model
|
|
||||||
(i.e., the model table and the many-to-many table) would be stored in the
|
|
||||||
``tables`` tablespace. The index for the name field and the indexes on the
|
|
||||||
many-to-many table would be stored in the ``indexes`` tablespace. The ``data``
|
|
||||||
field would also generate an index, but no tablespace for it is specified, so
|
|
||||||
it would be stored in the model tablespace ``tables`` by default.
|
|
||||||
|
|
||||||
Use the :setting:`DEFAULT_TABLESPACE` and :setting:`DEFAULT_INDEX_TABLESPACE`
|
|
||||||
settings to specify default values for the db_tablespace options.
|
|
||||||
These are useful for setting a tablespace for the built-in Django apps and
|
|
||||||
other applications whose code you cannot control.
|
|
||||||
|
|
||||||
Django does not create the tablespaces for you. Please refer to `Oracle's
|
|
||||||
documentation`_ for details on creating and managing tablespaces.
|
|
||||||
|
|
||||||
.. _`Oracle's documentation`: http://download.oracle.com/docs/cd/B19306_01/server.102/b14200/statements_7003.htm#SQLRF01403
|
|
||||||
|
|
||||||
Naming issues
|
Naming issues
|
||||||
-------------
|
-------------
|
||||||
|
|
||||||
|
|
|
@ -178,10 +178,11 @@ If ``True``, djadmin:`django-admin.py sqlindexes <sqlindexes>` will output a
|
||||||
|
|
||||||
.. attribute:: Field.db_tablespace
|
.. attribute:: Field.db_tablespace
|
||||||
|
|
||||||
The name of the database tablespace to use for this field's index, if this field
|
The name of the :doc:`database tablespace </topics/db/tablespaces>` to use for
|
||||||
is indexed. The default is the project's :setting:`DEFAULT_INDEX_TABLESPACE`
|
this field's index, if this field is indexed. The default is the project's
|
||||||
setting, if set, or the :attr:`~Field.db_tablespace` of the model, if any. If
|
:setting:`DEFAULT_INDEX_TABLESPACE` setting, if set, or the
|
||||||
the backend doesn't support tablespaces, this option is ignored.
|
:attr:`~Options.db_tablespace` of the model, if any. If the backend doesn't
|
||||||
|
support tablespaces for indexes, this option is ignored.
|
||||||
|
|
||||||
``default``
|
``default``
|
||||||
-----------
|
-----------
|
||||||
|
|
|
@ -73,8 +73,10 @@ Django quotes column and table names behind the scenes.
|
||||||
|
|
||||||
.. attribute:: Options.db_tablespace
|
.. attribute:: Options.db_tablespace
|
||||||
|
|
||||||
The name of the database tablespace to use for the model. If the backend
|
The name of the :doc:`database tablespace </topics/db/tablespaces>` to use
|
||||||
doesn't support tablespaces, this option is ignored.
|
for this model. The default is the project's :setting:`DEFAULT_TABLESPACE`
|
||||||
|
setting, if set. If the backend doesn't support tablespaces, this option is
|
||||||
|
ignored.
|
||||||
|
|
||||||
``get_latest_by``
|
``get_latest_by``
|
||||||
-----------------
|
-----------------
|
||||||
|
|
|
@ -864,7 +864,7 @@ DEFAULT_INDEX_TABLESPACE
|
||||||
Default: ``''`` (Empty string)
|
Default: ``''`` (Empty string)
|
||||||
|
|
||||||
Default tablespace to use for indexes on fields that don't specify
|
Default tablespace to use for indexes on fields that don't specify
|
||||||
one, if the backend supports it.
|
one, if the backend supports it (see :doc:`/topics/db/tablespaces`).
|
||||||
|
|
||||||
.. setting:: DEFAULT_TABLESPACE
|
.. setting:: DEFAULT_TABLESPACE
|
||||||
|
|
||||||
|
@ -874,7 +874,7 @@ DEFAULT_TABLESPACE
|
||||||
Default: ``''`` (Empty string)
|
Default: ``''`` (Empty string)
|
||||||
|
|
||||||
Default tablespace to use for models that don't specify one, if the
|
Default tablespace to use for models that don't specify one, if the
|
||||||
backend supports it.
|
backend supports it (see :doc:`/topics/db/tablespaces`).
|
||||||
|
|
||||||
.. setting:: DISALLOWED_USER_AGENTS
|
.. setting:: DISALLOWED_USER_AGENTS
|
||||||
|
|
||||||
|
|
|
@ -405,6 +405,8 @@ Django 1.4 also includes several smaller improvements worth noting:
|
||||||
code are slightly emphasized. This change makes it easier to scan a stacktrace
|
code are slightly emphasized. This change makes it easier to scan a stacktrace
|
||||||
for issues in user code.
|
for issues in user code.
|
||||||
|
|
||||||
|
* :doc:`Tablespace support </topics/db/tablespaces>` in PostgreSQL.
|
||||||
|
|
||||||
* Customizable names for :meth:`~django.template.Library.simple_tag`.
|
* Customizable names for :meth:`~django.template.Library.simple_tag`.
|
||||||
|
|
||||||
* In the documentation, a helpful :doc:`security overview </topics/security>`
|
* In the documentation, a helpful :doc:`security overview </topics/security>`
|
||||||
|
|
|
@ -17,4 +17,5 @@ model maps to a single database table.
|
||||||
sql
|
sql
|
||||||
transactions
|
transactions
|
||||||
multi-db
|
multi-db
|
||||||
|
tablespaces
|
||||||
optimization
|
optimization
|
||||||
|
|
|
@ -0,0 +1,73 @@
|
||||||
|
===========
|
||||||
|
Tablespaces
|
||||||
|
===========
|
||||||
|
|
||||||
|
A common paradigm for optimizing performance in database systems is the use of
|
||||||
|
`tablespaces`_ to organize disk layout.
|
||||||
|
|
||||||
|
.. _`tablespaces`: http://en.wikipedia.org/wiki/Tablespace
|
||||||
|
|
||||||
|
.. warning::
|
||||||
|
Django does not create the tablespaces for you. Please refer to your
|
||||||
|
database engine's documentation for details on creating and managing
|
||||||
|
tablespaces.
|
||||||
|
|
||||||
|
|
||||||
|
Declaring tablespaces for tables
|
||||||
|
--------------------------------
|
||||||
|
|
||||||
|
A tablespace can be specified for the table generated by a model by supplying
|
||||||
|
the :attr:`~django.db.models.Options.db_tablespace` option inside the model's
|
||||||
|
``class Meta``. This option also affects tables automatically created for
|
||||||
|
:class:`~django.db.models.ManyToManyField`\ s in the model.
|
||||||
|
|
||||||
|
You can use the :setting:`DEFAULT_TABLESPACE` setting to specify a default value
|
||||||
|
for :attr:`~django.db.models.Options.db_tablespace`. This is useful for setting
|
||||||
|
a tablespace for the built-in Django apps and other applications whose code you
|
||||||
|
cannot control.
|
||||||
|
|
||||||
|
Declaring tablespaces for indexes
|
||||||
|
---------------------------------
|
||||||
|
|
||||||
|
You can pass the :attr:`~django.db.models.Field.db_tablespace` option to a
|
||||||
|
``Field`` constructor to specify an alternate tablespace for the ``Field``'s
|
||||||
|
column index. If no index would be created for the column, the option is
|
||||||
|
ignored.
|
||||||
|
|
||||||
|
You can use the :setting:`DEFAULT_INDEX_TABLESPACE` setting to specify
|
||||||
|
a default value for :attr:`~django.db.models.Field.db_tablespace`.
|
||||||
|
|
||||||
|
If :attr:`~django.db.models.Field.db_tablespace` isn't specified and you didn't
|
||||||
|
set :setting:`DEFAULT_INDEX_TABLESPACE`, the index is created in the same
|
||||||
|
tablespace as the tables.
|
||||||
|
|
||||||
|
An example
|
||||||
|
----------
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
class TablespaceExample(models.Model):
|
||||||
|
name = models.CharField(max_length=30, db_index=True, db_tablespace="indexes")
|
||||||
|
data = models.CharField(max_length=255, db_index=True)
|
||||||
|
edges = models.ManyToManyField(to="self", db_tablespace="indexes")
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
db_tablespace = "tables"
|
||||||
|
|
||||||
|
In this example, the tables generated by the ``TablespaceExample`` model (i.e.
|
||||||
|
the model table and the many-to-many table) would be stored in the ``tables``
|
||||||
|
tablespace. The index for the name field and the indexes on the many-to-many
|
||||||
|
table would be stored in the ``indexes`` tablespace. The ``data`` field would
|
||||||
|
also generate an index, but no tablespace for it is specified, so it would be
|
||||||
|
stored in the model tablespace ``tables`` by default.
|
||||||
|
|
||||||
|
Database support
|
||||||
|
----------------
|
||||||
|
|
||||||
|
PostgreSQL and Oracle support tablespaces. SQLite and MySQL don't.
|
||||||
|
|
||||||
|
When you use a backend that lacks support for tablespaces, Django ignores all
|
||||||
|
tablespace-related options.
|
||||||
|
|
||||||
|
.. versionchanged:: 1.4
|
||||||
|
Since Django 1.4, the PostgreSQL backend supports tablespaces.
|
|
@ -0,0 +1,32 @@
|
||||||
|
from django.db import models
|
||||||
|
|
||||||
|
# Since the test database doesn't have tablespaces, it's impossible for Django
|
||||||
|
# to create the tables for models where db_tablespace is set. To avoid this
|
||||||
|
# problem, we mark the models as unmanaged, and temporarily revert them to
|
||||||
|
# managed during each tes. See setUp and tearDown -- it isn't possible to use
|
||||||
|
# setUpClass and tearDownClass because they're called before Django flushes the
|
||||||
|
# tables, so Django attempts to flush a non-existing table.
|
||||||
|
|
||||||
|
class ScientistRef(models.Model):
|
||||||
|
name = models.CharField(max_length=50)
|
||||||
|
|
||||||
|
class ArticleRef(models.Model):
|
||||||
|
title = models.CharField(max_length=50, unique=True)
|
||||||
|
code = models.CharField(max_length=50, unique=True)
|
||||||
|
authors = models.ManyToManyField(ScientistRef, related_name='articles_written_set')
|
||||||
|
reviewers = models.ManyToManyField(ScientistRef, related_name='articles_reviewed_set')
|
||||||
|
|
||||||
|
class Scientist(models.Model):
|
||||||
|
name = models.CharField(max_length=50)
|
||||||
|
class Meta:
|
||||||
|
db_tablespace = 'tbl_tbsp'
|
||||||
|
managed = False
|
||||||
|
|
||||||
|
class Article(models.Model):
|
||||||
|
title = models.CharField(max_length=50, unique=True)
|
||||||
|
code = models.CharField(max_length=50, unique=True, db_tablespace='idx_tbsp')
|
||||||
|
authors = models.ManyToManyField(Scientist, related_name='articles_written_set')
|
||||||
|
reviewers = models.ManyToManyField(Scientist, related_name='articles_reviewed_set', db_tablespace='idx_tbsp')
|
||||||
|
class Meta:
|
||||||
|
db_tablespace = 'tbl_tbsp'
|
||||||
|
managed = False
|
|
@ -0,0 +1,92 @@
|
||||||
|
import copy
|
||||||
|
|
||||||
|
from django.db import connection
|
||||||
|
from django.db import models
|
||||||
|
from django.db.models.loading import cache
|
||||||
|
from django.core.management.color import no_style
|
||||||
|
from django.test import TestCase, skipIfDBFeature, skipUnlessDBFeature
|
||||||
|
|
||||||
|
from models import Article, ArticleRef, Scientist, ScientistRef
|
||||||
|
|
||||||
|
# Automatically created models
|
||||||
|
Authors = Article._meta.get_field('authors').rel.through
|
||||||
|
Reviewers = Article._meta.get_field('reviewers').rel.through
|
||||||
|
|
||||||
|
# We can't test the DEFAULT_TABLESPACE and DEFAULT_INDEX_TABLESPACE settings
|
||||||
|
# because they're evaluated when the model class is defined. As a consequence,
|
||||||
|
# @override_settings doesn't work.
|
||||||
|
|
||||||
|
def sql_for_table(model):
|
||||||
|
return '\n'.join(connection.creation.sql_create_model(model, no_style())[0])
|
||||||
|
|
||||||
|
def sql_for_index(model):
|
||||||
|
return '\n'.join(connection.creation.sql_indexes_for_model(model, no_style()))
|
||||||
|
|
||||||
|
|
||||||
|
class TablespacesTests(TestCase):
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
# The unmanaged models need to be removed after the test in order to
|
||||||
|
# prevent bad interactions with other tests (proxy_models_inheritance).
|
||||||
|
self.old_app_models = copy.deepcopy(cache.app_models)
|
||||||
|
self.old_app_store = copy.deepcopy(cache.app_store)
|
||||||
|
|
||||||
|
for model in Article, Authors, Reviewers, Scientist:
|
||||||
|
model._meta.managed = True
|
||||||
|
|
||||||
|
def tearDown(self):
|
||||||
|
for model in Article, Authors, Reviewers, Scientist:
|
||||||
|
model._meta.managed = False
|
||||||
|
|
||||||
|
cache.app_models = self.old_app_models
|
||||||
|
cache.app_store = self.old_app_store
|
||||||
|
cache._get_models_cache = {}
|
||||||
|
|
||||||
|
def assertNumContains(self, haystack, needle, count):
|
||||||
|
real_count = haystack.count(needle)
|
||||||
|
self.assertEqual(real_count, count, "Found %d instances of '%s', "
|
||||||
|
"expected %d" % (real_count, needle, count))
|
||||||
|
|
||||||
|
@skipUnlessDBFeature('supports_tablespaces')
|
||||||
|
def test_tablespace_for_model(self):
|
||||||
|
# 1 for the table + 1 for the index on the primary key
|
||||||
|
self.assertNumContains(sql_for_table(Scientist).lower(), 'tbl_tbsp', 2)
|
||||||
|
|
||||||
|
@skipIfDBFeature('supports_tablespaces')
|
||||||
|
def test_tablespace_ignored_for_model(self):
|
||||||
|
# No tablespace-related SQL
|
||||||
|
self.assertEqual(sql_for_table(Scientist),
|
||||||
|
sql_for_table(ScientistRef).replace('ref', ''))
|
||||||
|
|
||||||
|
@skipUnlessDBFeature('supports_tablespaces')
|
||||||
|
def test_tablespace_for_indexed_field(self):
|
||||||
|
# 1 for the table + 1 for the primary key + 1 for the index on name
|
||||||
|
self.assertNumContains(sql_for_table(Article).lower(), 'tbl_tbsp', 3)
|
||||||
|
# 1 for the index on reference
|
||||||
|
self.assertNumContains(sql_for_table(Article).lower(), 'idx_tbsp', 1)
|
||||||
|
|
||||||
|
@skipIfDBFeature('supports_tablespaces')
|
||||||
|
def test_tablespace_ignored_for_indexed_field(self):
|
||||||
|
# No tablespace-related SQL
|
||||||
|
self.assertEqual(sql_for_table(Article),
|
||||||
|
sql_for_table(ArticleRef).replace('ref', ''))
|
||||||
|
|
||||||
|
@skipUnlessDBFeature('supports_tablespaces')
|
||||||
|
def test_tablespace_for_many_to_many_field(self):
|
||||||
|
# The join table of the ManyToManyField always goes to the tablespace
|
||||||
|
# of the model.
|
||||||
|
self.assertNumContains(sql_for_table(Authors).lower(), 'tbl_tbsp', 2)
|
||||||
|
self.assertNumContains(sql_for_table(Authors).lower(), 'idx_tbsp', 0)
|
||||||
|
# The ManyToManyField declares no db_tablespace, indexes for the two
|
||||||
|
# foreign keys in the join table go to the tablespace of the model.
|
||||||
|
self.assertNumContains(sql_for_index(Authors).lower(), 'tbl_tbsp', 2)
|
||||||
|
self.assertNumContains(sql_for_index(Authors).lower(), 'idx_tbsp', 0)
|
||||||
|
|
||||||
|
# The join table of the ManyToManyField always goes to the tablespace
|
||||||
|
# of the model.
|
||||||
|
self.assertNumContains(sql_for_table(Reviewers).lower(), 'tbl_tbsp', 2)
|
||||||
|
self.assertNumContains(sql_for_table(Reviewers).lower(), 'idx_tbsp', 0)
|
||||||
|
# The ManyToManyField declares db_tablespace, indexes for the two
|
||||||
|
# foreign keys in the join table go to this tablespace.
|
||||||
|
self.assertNumContains(sql_for_index(Reviewers).lower(), 'tbl_tbsp', 0)
|
||||||
|
self.assertNumContains(sql_for_index(Reviewers).lower(), 'idx_tbsp', 2)
|
Loading…
Reference in New Issue