Ticket #12308: 12308-with-mysql-support-dont-use.patch

File 12308-with-mysql-support-dont-use.patch, 26.8 KB (added by aaugustin, 4 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>` for
     223      indexes. You 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
     67When you use a backend that lacks support for tablespaces, Django ignores all
     68tablespace-related options.
     69
     70Here is the current support matrix:
     71
     72=================== =================== ===========
     73Database            Tables              Indexes
     74=================== =================== ===========
     75SQLite              no                  no
     76PostgreSQL          yes                 yes
     77MySQL               partial, see below  no
     78Oracle              yes                 yes
     79=================== =================== ===================
     80
     81MySQL supports tablespaces since version 5.1.6. They're only useful in
     82combination with MySQL Cluster NDB.
     83
     84.. versionchanged:: 1.4
     85    Until Django 1.4, tablespaces were only supported by the Oracle backend.
  • 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 and MySQL.
     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 won'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    @skipUnlessDBFeature('supports_index_tablespaces')
     40    def test_tablespace_for_model(self):
     41        # 1 for the table + 1 for the index on the primary key
     42        self.assertNumContains(sql_for_table(Scientist), 'tbl_tbsp', 2)
     43
     44    @skipUnlessDBFeature('supports_tablespaces')
     45    @skipIfDBFeature('supports_index_tablespaces')
     46    def test_tablespace_for_model_without_index(self):
     47        # 1 for the table
     48        self.assertNumContains(sql_for_table(Scientist), 'tbl_tbsp', 1)
     49
     50    @skipIfDBFeature('supports_tablespaces')
     51    def test_tablespace_ignored_for_model(self):
     52        # No tablespace-related SQL
     53        self.assertEqual(sql_for_table(Scientist),
     54                         sql_for_table(ScientistRef).replace('ref', ''))
     55
     56    @skipUnlessDBFeature('supports_tablespaces')
     57    @skipUnlessDBFeature('supports_index_tablespaces')
     58    def test_tablespace_for_indexed_field(self):
     59        # 1 for the table + 1 for the primary key + 1 for the index on name
     60        self.assertNumContains(sql_for_table(Article), 'tbl_tbsp', 3)
     61        # 1 for the index on reference
     62        self.assertNumContains(sql_for_table(Article), 'idx_tbsp', 1)
     63
     64    @skipUnlessDBFeature('supports_tablespaces')
     65    @skipIfDBFeature('supports_index_tablespaces')
     66    def test_tablespace_for_indexed_field(self):
     67        # 1 for the table
     68        self.assertNumContains(sql_for_table(Article), 'tbl_tbsp', 1)
     69        self.assertNumContains(sql_for_table(Article), 'idx_tbsp', 0)
     70
     71    @skipIfDBFeature('supports_tablespaces')
     72    def test_tablespace_ignored_for_indexed_field(self):
     73        # No tablespace-related SQL
     74        self.assertEqual(sql_for_table(Article),
     75                         sql_for_table(ArticleRef).replace('ref', ''))
     76
     77    @skipUnlessDBFeature('supports_tablespaces')
     78    @skipUnlessDBFeature('supports_index_tablespaces')
     79    def test_tablespace_for_many_to_many_field(self):
     80        # The join table of the ManyToManyField always goes to the tablespace
     81        # of the model.
     82        self.assertNumContains(sql_for_table(Authors), 'tbl_tbsp', 2)
     83        self.assertNumContains(sql_for_table(Authors), 'idx_tbsp', 0)
     84        # The ManyToManyField declares no db_tablespace, indexes for the two
     85        # foreign keys in the join table go to the tablespace of the model.
     86        self.assertNumContains(sql_for_index(Authors), 'tbl_tbsp', 2)
     87        self.assertNumContains(sql_for_index(Authors), 'idx_tbsp', 0)
     88
     89        # The join table of the ManyToManyField always goes to the tablespace
     90        # of the model.
     91        self.assertNumContains(sql_for_table(Reviewers), 'tbl_tbsp', 2)
     92        self.assertNumContains(sql_for_table(Reviewers), 'idx_tbsp', 0)
     93        # The ManyToManyField declares db_tablespace, indexes for the two
     94        # foreign keys in the join table go to this tablespace.
     95        self.assertNumContains(sql_for_index(Reviewers), 'tbl_tbsp', 0)
     96        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/sqlite3/base.py

     
    5858    supports_unspecified_pk = True
    5959    supports_1000_query_parameters = False
    6060    supports_mixed_date_datetime_comparisons = False
     61    supports_index_tablespaces = False
    6162
    6263    def _supports_stddev(self):
    6364        """Confirm support for STDDEV and related stats functions
     
    7778        cursor.execute('DROP TABLE STDDEV_TEST')
    7879        return has_support
    7980
     81    def _supports_tablespaces(self):
     82        return False
     83
    8084class DatabaseOperations(BaseDatabaseOperations):
    8185    def date_extract_sql(self, lookup_type, field_name):
    8286        # sqlite doesn't support extract, so we fake it with the user-defined
     
    129133        # sql_flush() implementations). Just return SQL at this point
    130134        return sql
    131135
     136    def tablespace_sql(self, tablespace, inline=False, index=False):
     137        return ''
     138
    132139    def year_lookup_bounds(self, value):
    133140        first = '%s-01-01'
    134141        second = '%s-12-31 23:59:59.999999'
  • django/db/backends/mysql/base.py

     
    134134    supports_timezones = False
    135135    requires_explicit_null_ordering_when_grouping = True
    136136    allows_primary_key_0 = False
     137    supports_index_tablespaces = False
    137138
    138139    def _can_introspect_foreign_keys(self):
    139140        "Confirm support for introspected foreign keys"
     
    148149        cursor.execute('DROP TABLE INTROSPECT_TEST')
    149150        return result[1] != 'MyISAM'
    150151
     152    def _supports_tablespaces(self):
     153        "Confirm support for tablespaces"
     154        return self.connection.get_server_version() >= (5, 1, 6)
     155
    151156class DatabaseOperations(BaseDatabaseOperations):
    152157    compiler_module = "django.db.backends.mysql.compiler"
    153158
     
    232237        else:
    233238            return []
    234239
     240    def tablespace_sql(self, tablespace, inline=False, index=False):
     241        # MySQL doesn't support setting tablespaces for indexes, and it only
     242        # supports setting tablespaces for table since version 5.1.6
     243        if inline or index or self.connection.get_server_version() < (5, 1, 6):
     244            return ''
     245        return super(DatabaseOperations, self).tablespace_sql(tablespace,
     246                inline=inline, index=index)
     247
    235248    def value_to_db_datetime(self, value):
    236249        if value is None:
    237250            return None
  • django/db/backends/oracle/base.py

     
    324324    def start_transaction_sql(self):
    325325        return ''
    326326
    327     def tablespace_sql(self, tablespace, inline=False):
    328         return "%sTABLESPACE %s" % ((inline and "USING INDEX " or ""),
    329             self.quote_name(tablespace))
    330 
    331327    def value_to_db_datetime(self, value):
    332328        # Oracle doesn't support tz-aware datetimes
    333329        if getattr(value, 'tzinfo', None) is not None:
  • 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 for indexes?
     368    # Requires supports_tablespaces = True.
     369    supports_index_tablespaces = True
     370
    367371    # Features that need to be confirmed at runtime
     372
    368373    # Cache whether the confirmation has been performed.
    369374    _confirmed = False
    370375    supports_transactions = None
    371376    supports_stddev = None
    372377    can_introspect_foreign_keys = None
     378    # Does the backend support tablespaces for tables?
     379    supports_tablespaces = None
    373380
    374381    def __init__(self, connection):
    375382        self.connection = connection
     
    380387        self.supports_transactions = self._supports_transactions()
    381388        self.supports_stddev = self._supports_stddev()
    382389        self.can_introspect_foreign_keys = self._can_introspect_foreign_keys()
     390        self.supports_tablespaces = self._supports_tablespaces()
    383391
    384392    def _supports_transactions(self):
    385393        "Confirm support for transactions"
     
    410418        # which can't do it for MyISAM tables
    411419        return True
    412420
     421    def _supports_tablespaces(self):
     422        "Confirm support for tablespaces"
     423        # On MySQL, this depends on the version
     424        return True
    413425
     426
    414427class BaseDatabaseOperations(object):
    415428    """
    416429    This class encapsulates all backend-specific differences, such as the way
     
    693706            return "ROLLBACK;"
    694707        return "COMMIT;"
    695708
    696     def tablespace_sql(self, tablespace, inline=False):
     709    def tablespace_sql(self, tablespace, inline=False, index=False):
    697710        """
    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.
     711        Returns the SQL that will be used in a query to define the tablespace.
     712
     713        Returns '' if the backend doesn't support tablespaces.
     714
     715        If inline is True, the SQL is appended to a row; otherwise it's appended
     716        to the entire statement. If index is True, the statement creates an
     717        index; otherwise it creates a table.
     718
     719        SQL added to a row applies to the index created by this row. When inline
     720        is True, it implies that index is True, even if the caller doesn't pass
     721        the index parameter.
    700722        """
    701         return ''
     723        if inline:
     724            return "USING INDEX TABLESPACE %s" % self.quote_name(tablespace)
     725        else:
     726            return "TABLESPACE %s" % self.quote_name(tablespace)
    702727
    703728    def prep_for_like_query(self, x):
    704729        """Prepares a value for use in a LIKE query."""
  • 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, index=True)
     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, index=True)
     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