Ticket #12308: 12308.patch

File 12308.patch, 22.8 KB (added by Aymeric Augustin, 13 years ago)
  • docs/index.txt

     
    6666      :doc:`Transactions <topics/db/transactions>` |
    6767      :doc:`Aggregation <topics/db/aggregation>` |
    6868      :doc:`Custom fields <howto/custom-model-fields>` |
    69       :doc:`Multiple databases <topics/db/multi-db>`
     69      :doc:`Multiple databases <topics/db/multi-db>` |
     70      :doc:`Tablespaces <topics/db/tablespaces>`
    7071
    7172    * **Other:**
    7273      :doc:`Supported databases <ref/databases>` |
  • docs/howto/custom-model-fields.txt

     
    218218    * :attr:`~django.db.models.Field.choices`
    219219    * :attr:`~django.db.models.Field.help_text`
    220220    * :attr:`~django.db.models.Field.db_column`
    221     * :attr:`~django.db.models.Field.db_tablespace`: Currently only used with
    222       the Oracle backend and only for index creation. You can usually ignore
    223       this option.
     221    * :attr:`~django.db.models.Field.db_tablespace`: Only for index creation,
     222      if the backend supports :doc:`tablespaces </topics/db/tablespaces>`. You
     223      can usually ignore this option.
    224224    * :attr:`~django.db.models.Field.auto_created`: True if the field was
    225225      automatically created, as for the `OneToOneField` used by model
    226226      inheritance. For advanced use only.
  • docs/topics/db/tablespaces.txt

     
     1===========
     2Tablespaces
     3===========
     4
     5A common paradigm for optimizing performance in database systems is the use of
     6`tablespaces`_ to organize disk layout.
     7
     8.. _`tablespaces`: http://en.wikipedia.org/wiki/Tablespace
     9
     10.. warning::
     11    Django does not create the tablespaces for you. Please refer to your
     12    database engine's documentation for details on creating and managing
     13    tablespaces.
     14
     15
     16Declaring tablespaces for tables
     17--------------------------------
     18
     19A tablespace can be specified for the table generated by a model by supplying
     20the :attr:`~django.db.models.Options.db_tablespace` option inside the model's
     21``class Meta``. This option also affects tables automatically created for
     22:class:`~django.db.models.ManyToManyField`\ s in the model.
     23
     24You can use the :setting:`DEFAULT_TABLESPACE` setting to specify a default value
     25for :attr:`~django.db.models.Options.db_tablespace`. These is useful for setting
     26a tablespace for the built-in Django apps and other applications whose code you
     27cannot control.
     28
     29Declaring tablespaces for indexes
     30---------------------------------
     31
     32You can pass the :attr:`~django.db.models.Field.db_tablespace` option to a
     33``Field`` constructor to specify an alternate tablespace for the ``Field``'s
     34column index. If no index would be created for the column, the option is
     35ignored.
     36
     37You can use the :setting:`DEFAULT_INDEX_TABLESPACE` setting to specify
     38a default value for :attr:`~django.db.models.Field.db_tablespace`.
     39
     40If :attr:`~django.db.models.Field.db_tablespace` isn't specified and you didn't
     41set :setting:`DEFAULT_INDEX_TABLESPACE`, the index is created in the same
     42tablespace as the tables.
     43
     44An example
     45----------
     46
     47.. code-block:: python
     48
     49    class TablespaceExample(models.Model):
     50        name = models.CharField(max_length=30, db_index=True, db_tablespace="indexes")
     51        data = models.CharField(max_length=255, db_index=True)
     52        edges = models.ManyToManyField(to="self", db_tablespace="indexes")
     53
     54        class Meta:
     55            db_tablespace = "tables"
     56
     57In this example, the tables generated by the ``TablespaceExample`` model (i.e.
     58the model table and the many-to-many table) would be stored in the ``tables``
     59tablespace. The index for the name field and the indexes on the many-to-many
     60table would be stored in the ``indexes`` tablespace. The ``data`` field would
     61also generate an index, but no tablespace for it is specified, so it would be
     62stored in the model tablespace ``tables`` by default.
     63
     64Database support
     65----------------
     66
     67PostgreSQL and Oracle support tablespaces. SQLite and MySQL don't.
     68
     69When you use a backend that lacks support for tablespaces, Django ignores all
     70tablespace-related options.
     71
     72.. versionchanged:: 1.4
     73    Since Django 1.4, the PostgreSQL backend supports tablespaces.
  • docs/topics/db/index.txt

     
    1717   sql
    1818   transactions
    1919   multi-db
     20   tablespaces
    2021   optimization
  • docs/releases/1.4.txt

     
    245245  code are slightly emphasized. This change makes it easier to scan a stacktrace
    246246  for issues in user code.
    247247
     248* :doc:`Tablespace support </topics/db/tablespaces>` in PostgreSQL.
     249
    248250* Customizable names for :meth:`~django.template.Library.simple_tag`.
    249251
    250252* In the documentation, a helpful :doc:`security overview </topics/security>`
  • docs/ref/models/fields.txt

     
    178178
    179179.. attribute:: Field.db_tablespace
    180180
    181 The name of the database tablespace to use for this field's index, if this field
    182 is indexed. The default is the project's :setting:`DEFAULT_INDEX_TABLESPACE`
    183 setting, if set, or the :attr:`~Field.db_tablespace` of the model, if any. If
    184 the backend doesn't support tablespaces, this option is ignored.
     181The name of the :doc:`database tablespace </topics/db/tablespaces>` to use for
     182this field's index, if this field is indexed. The default is the project's
     183:setting:`DEFAULT_INDEX_TABLESPACE` setting, if set, or the
     184:attr:`~Options.db_tablespace` of the model, if any. If the backend doesn't
     185support tablespaces for indexes, this option is ignored.
    185186
    186187``default``
    187188-----------
  • docs/ref/models/options.txt

     
    6666
    6767.. attribute:: Options.db_tablespace
    6868
    69     The name of the database tablespace to use for the model. If the backend
    70     doesn't support tablespaces, this option is ignored.
     69    The name of the :doc:`database tablespace </topics/db/tablespaces>` to use
     70    for this model. The default is the project's :setting:`DEFAULT_TABLESPACE`
     71    setting, if set. If the backend doesn't support tablespaces, this option is
     72    ignored.
    7173
    7274``get_latest_by``
    7375-----------------
  • docs/ref/databases.txt

     
    620620In this case, the Oracle backend will use a separate ``SELECT`` query to
    621621retrieve AutoField values.
    622622
    623 Tablespace options
    624 ------------------
    625 
    626 A common paradigm for optimizing performance in Oracle-based systems is the
    627 use of `tablespaces`_ to organize disk layout. The Oracle backend supports
    628 this use case by adding ``db_tablespace`` options to the ``Meta`` and
    629 ``Field`` classes.  (When you use a backend that lacks support for tablespaces,
    630 Django ignores these options.)
    631 
    632 .. _`tablespaces`: http://en.wikipedia.org/wiki/Tablespace
    633 
    634 A tablespace can be specified for the table(s) generated by a model by
    635 supplying the ``db_tablespace`` option inside the model's ``class Meta``.
    636 Additionally, you can pass the ``db_tablespace`` option to a ``Field``
    637 constructor to specify an alternate tablespace for the ``Field``'s column
    638 index. If no index would be created for the column, the ``db_tablespace``
    639 option is ignored::
    640 
    641     class TablespaceExample(models.Model):
    642         name = models.CharField(max_length=30, db_index=True, db_tablespace="indexes")
    643         data = models.CharField(max_length=255, db_index=True)
    644         edges = models.ManyToManyField(to="self", db_tablespace="indexes")
    645 
    646         class Meta:
    647             db_tablespace = "tables"
    648 
    649 In this example, the tables generated by the ``TablespaceExample`` model
    650 (i.e., the model table and the many-to-many table) would be stored in the
    651 ``tables`` tablespace. The index for the name field and the indexes on the
    652 many-to-many table would be stored in the ``indexes`` tablespace. The ``data``
    653 field would also generate an index, but no tablespace for it is specified, so
    654 it would be stored in the model tablespace ``tables`` by default.
    655 
    656 Use the :setting:`DEFAULT_TABLESPACE` and :setting:`DEFAULT_INDEX_TABLESPACE`
    657 settings to specify default values for the db_tablespace options.
    658 These are useful for setting a tablespace for the built-in Django apps and
    659 other applications whose code you cannot control.
    660 
    661 Django does not create the tablespaces for you. Please refer to `Oracle's
    662 documentation`_ for details on creating and managing tablespaces.
    663 
    664 .. _`Oracle's documentation`: http://download.oracle.com/docs/cd/B19306_01/server.102/b14200/statements_7003.htm#SQLRF01403
    665 
    666623Naming issues
    667624-------------
    668625
  • docs/ref/settings.txt

     
    857857Default: ``''`` (Empty string)
    858858
    859859Default tablespace to use for indexes on fields that don't specify
    860 one, if the backend supports it.
     860one, if the backend supports it (see :doc:`/topics/db/tablespaces`).
    861861
    862862.. setting:: DEFAULT_TABLESPACE
    863863
     
    867867Default: ``''`` (Empty string)
    868868
    869869Default tablespace to use for models that don't specify one, if the
    870 backend supports it.
     870backend supports it (see :doc:`/topics/db/tablespaces`).
    871871
    872872.. setting:: DISALLOWED_USER_AGENTS
    873873
  • tests/modeltests/tablespaces/tests.py

     
     1from django.db import connection
     2from django.db import models
     3from django.core.management.color import no_style
     4from django.test import TestCase, skipIfDBFeature, skipUnlessDBFeature
     5
     6from models import Article, ArticleRef, Scientist, ScientistRef
     7
     8# Automatically created models
     9Authors = Article._meta.get_field('authors').rel.through
     10Reviewers = Article._meta.get_field('reviewers').rel.through
     11
     12# We can't test the DEFAULT_TABLESPACE and DEFAULT_INDEX_TABLESPACE settings
     13# because they're evaluated when the model class is defined. As a consequence,
     14# @override_settings doesn't work.
     15
     16def sql_for_table(model):
     17    return '\n'.join(connection.creation.sql_create_model(model, no_style())[0])
     18
     19def sql_for_index(model):
     20    return '\n'.join(connection.creation.sql_indexes_for_model(model, no_style()))
     21
     22
     23class TablespacesTests(TestCase):
     24
     25    def setUp(self):
     26        for model in Article, Authors, Reviewers, Scientist:
     27            model._meta.managed = True
     28
     29    def tearDown(self):
     30        for model in Article, Authors, Reviewers, Scientist:
     31            model._meta.managed = False
     32
     33    def assertNumContains(self, haystack, needle, count):
     34        real_count = haystack.count(needle)
     35        self.assertEqual(real_count, count, "Found %d instances of '%s', "
     36                "expected %d" % (real_count, needle, count))
     37
     38    @skipUnlessDBFeature('supports_tablespaces')
     39    def test_tablespace_for_model(self):
     40        # 1 for the table + 1 for the index on the primary key
     41        self.assertNumContains(sql_for_table(Scientist), 'tbl_tbsp', 2)
     42
     43    @skipIfDBFeature('supports_tablespaces')
     44    def test_tablespace_ignored_for_model(self):
     45        # No tablespace-related SQL
     46        self.assertEqual(sql_for_table(Scientist),
     47                         sql_for_table(ScientistRef).replace('ref', ''))
     48
     49    @skipUnlessDBFeature('supports_tablespaces')
     50    def test_tablespace_for_indexed_field(self):
     51        # 1 for the table + 1 for the primary key + 1 for the index on name
     52        self.assertNumContains(sql_for_table(Article), 'tbl_tbsp', 3)
     53        # 1 for the index on reference
     54        self.assertNumContains(sql_for_table(Article), 'idx_tbsp', 1)
     55
     56    @skipIfDBFeature('supports_tablespaces')
     57    def test_tablespace_ignored_for_indexed_field(self):
     58        # No tablespace-related SQL
     59        self.assertEqual(sql_for_table(Article),
     60                         sql_for_table(ArticleRef).replace('ref', ''))
     61
     62    @skipUnlessDBFeature('supports_tablespaces')
     63    def test_tablespace_for_many_to_many_field(self):
     64        # The join table of the ManyToManyField always goes to the tablespace
     65        # of the model.
     66        self.assertNumContains(sql_for_table(Authors), 'tbl_tbsp', 2)
     67        self.assertNumContains(sql_for_table(Authors), 'idx_tbsp', 0)
     68        # The ManyToManyField declares no db_tablespace, indexes for the two
     69        # foreign keys in the join table go to the tablespace of the model.
     70        self.assertNumContains(sql_for_index(Authors), 'tbl_tbsp', 2)
     71        self.assertNumContains(sql_for_index(Authors), 'idx_tbsp', 0)
     72
     73        # The join table of the ManyToManyField always goes to the tablespace
     74        # of the model.
     75        self.assertNumContains(sql_for_table(Reviewers), 'tbl_tbsp', 2)
     76        self.assertNumContains(sql_for_table(Reviewers), 'idx_tbsp', 0)
     77        # The ManyToManyField declares db_tablespace, indexes for the two
     78        # foreign keys in the join table go to this tablespace.
     79        self.assertNumContains(sql_for_index(Reviewers), 'tbl_tbsp', 0)
     80        self.assertNumContains(sql_for_index(Reviewers), 'idx_tbsp', 2)
  • tests/modeltests/tablespaces/models.py

     
     1from django.db import models
     2
     3# Since the test database doesn't have tablespaces, it's impossible for Django
     4# to create the tables for models where db_tablespace is set. To avoid this
     5# problem, we mark the models as unmanaged, and temporarily revert them to
     6# managed during each test (see setUp and tearDown).
     7
     8class ScientistRef(models.Model):
     9    name = models.CharField(max_length=50)
     10
     11class ArticleRef(models.Model):
     12    title = models.CharField(max_length=50, unique=True)
     13    code = models.CharField(max_length=50, unique=True)
     14    authors = models.ManyToManyField(ScientistRef, related_name='articles_written_set')
     15    reviewers = models.ManyToManyField(ScientistRef, related_name='articles_reviewed_set')
     16
     17class Scientist(models.Model):
     18    name = models.CharField(max_length=50)
     19    class Meta:
     20        db_tablespace = 'tbl_tbsp'
     21        managed = False
     22
     23class Article(models.Model):
     24    title = models.CharField(max_length=50, unique=True)
     25    code = models.CharField(max_length=50, unique=True, db_tablespace='idx_tbsp')
     26    authors = models.ManyToManyField(Scientist, related_name='articles_written_set')
     27    reviewers = models.ManyToManyField(Scientist, related_name='articles_reviewed_set', db_tablespace='idx_tbsp')
     28    class Meta:
     29        db_tablespace = 'tbl_tbsp'
     30        managed = False
  • django/db/models/fields/related.py

     
    988988        'managed': managed,
    989989        'auto_created': klass,
    990990        'app_label': klass._meta.app_label,
     991        'db_tablespace': klass._meta.db_tablespace,
    991992        'unique_together': (from_, to),
    992993        'verbose_name': '%(from)s-%(to)s relationship' % {'from': from_, 'to': to},
    993994        'verbose_name_plural': '%(from)s-%(to)s relationships' % {'from': from_, 'to': to},
     
    996997    return type(name, (models.Model,), {
    997998        'Meta': meta,
    998999        '__module__': klass.__module__,
    999         from_: models.ForeignKey(klass, related_name='%s+' % name),
    1000         to: models.ForeignKey(to_model, related_name='%s+' % name)
     1000        from_: models.ForeignKey(klass, related_name='%s+' % name, db_tablespace=field.db_tablespace),
     1001        to: models.ForeignKey(to_model, related_name='%s+' % name, db_tablespace=field.db_tablespace)
    10011002    })
    10021003
    10031004class ManyToManyField(RelatedField, Field):
  • django/db/backends/oracle/base.py

     
    7878    supports_bitwise_or = False
    7979    can_defer_constraint_checks = True
    8080    ignores_nulls_in_unique_constraints = False
     81    supports_tablespaces = True
    8182
    8283class DatabaseOperations(BaseDatabaseOperations):
    8384    compiler_module = "django.db.backends.oracle.compiler"
     
    325326        return ''
    326327
    327328    def tablespace_sql(self, tablespace, inline=False):
    328         return "%sTABLESPACE %s" % ((inline and "USING INDEX " or ""),
    329             self.quote_name(tablespace))
     329        if inline:
     330            return "USING INDEX TABLESPACE %s" % self.quote_name(tablespace)
     331        else:
     332            return "TABLESPACE %s" % self.quote_name(tablespace)
    330333
    331334    def value_to_db_datetime(self, value):
    332335        # Oracle doesn't support tz-aware datetimes
  • django/db/backends/__init__.py

     
    364364    # date_interval_sql can properly handle mixed Date/DateTime fields and timedeltas
    365365    supports_mixed_date_datetime_comparisons = True
    366366
     367    # Does the backend support tablespaces? Default to False because it isn't
     368    # in the SQL standard.
     369    supports_tablespaces = False
     370
    367371    # Features that need to be confirmed at runtime
    368372    # Cache whether the confirmation has been performed.
    369373    _confirmed = False
     
    695699
    696700    def tablespace_sql(self, tablespace, inline=False):
    697701        """
    698         Returns the SQL that will be appended to tables or rows to define
    699         a tablespace. Returns '' if the backend doesn't use tablespaces.
     702        Returns the SQL that will be used in a query to define the tablespace.
     703
     704        Returns '' if the backend doesn't support tablespaces.
     705
     706        If inline is True, the SQL is appended to a row; otherwise it's appended
     707        to the entire CREATE TABLE or CREATE INDEX statement.
    700708        """
    701709        return ''
    702710
  • django/db/backends/postgresql_psycopg2/base.py

     
    7171    can_defer_constraint_checks = True
    7272    has_select_for_update = True
    7373    has_select_for_update_nowait = True
     74    supports_tablespaces = True
    7475
    7576
    7677class DatabaseWrapper(BaseDatabaseWrapper):
  • django/db/backends/postgresql_psycopg2/operations.py

     
    9999        else:
    100100            return []
    101101
     102    def tablespace_sql(self, tablespace, inline=False):
     103        if inline:
     104            return "USING INDEX TABLESPACE %s" % self.quote_name(tablespace)
     105        else:
     106            return "TABLESPACE %s" % self.quote_name(tablespace)
     107
    102108    def sequence_reset_sql(self, style, model_list):
    103109        from django.db import models
    104110        output = []
  • django/db/backends/postgresql_psycopg2/creation.py

     
    4444            db_table = model._meta.db_table
    4545            tablespace = f.db_tablespace or model._meta.db_tablespace
    4646            if tablespace:
    47                 sql = self.connection.ops.tablespace_sql(tablespace)
    48                 if sql:
    49                     tablespace_sql = ' ' + sql
    50                 else:
    51                     tablespace_sql = ''
     47                tablespace_sql = self.connection.ops.tablespace_sql(tablespace)
     48                if tablespace_sql:
     49                    tablespace_sql = ' ' + tablespace_sql
    5250            else:
    5351                tablespace_sql = ''
    5452
  • django/db/backends/creation.py

     
    5757            if tablespace and f.unique:
    5858                # We must specify the index tablespace inline, because we
    5959                # won't be generating a CREATE INDEX statement for this field.
    60                 field_output.append(self.connection.ops.tablespace_sql(tablespace, inline=True))
     60                tablespace_sql = self.connection.ops.tablespace_sql(tablespace, inline=True)
     61                if tablespace_sql:
     62                    field_output.append(tablespace_sql)
    6163            if f.rel:
    6264                ref_output, pending = self.sql_for_inline_foreign_key_references(f, known_models, style)
    6365                if pending:
     
    7476            full_statement.append('    %s%s' % (line, i < len(table_output)-1 and ',' or ''))
    7577        full_statement.append(')')
    7678        if opts.db_tablespace:
    77             full_statement.append(self.connection.ops.tablespace_sql(opts.db_tablespace))
     79            tablespace_sql = self.connection.ops.tablespace_sql(opts.db_tablespace)
     80            if tablespace_sql:
     81                full_statement.append(tablespace_sql)
    7882        full_statement.append(';')
    7983        final_output.append('\n'.join(full_statement))
    8084
     
    149153            qn = self.connection.ops.quote_name
    150154            tablespace = f.db_tablespace or model._meta.db_tablespace
    151155            if tablespace:
    152                 sql = self.connection.ops.tablespace_sql(tablespace)
    153                 if sql:
    154                     tablespace_sql = ' ' + sql
    155                 else:
    156                     tablespace_sql = ''
     156                tablespace_sql = self.connection.ops.tablespace_sql(tablespace)
     157                if tablespace_sql:
     158                    tablespace_sql = ' ' + tablespace_sql
    157159            else:
    158160                tablespace_sql = ''
    159161            i_name = '%s_%s' % (model._meta.db_table, self._digest(f.column))
Back to Top