summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMike Bayer <mike_mp@zzzcomputing.com>2008-07-09 20:38:35 +0000
committerMike Bayer <mike_mp@zzzcomputing.com>2008-07-09 20:38:35 +0000
commit5d375cd730fa0a89cb6684df47b2ae10cc217f57 (patch)
treeab10e8b156e543e9b365c45d41a889ea22d59aa9
parentff9c5007a87c830fb763b43b451db3e4f002c31f (diff)
downloadsqlalchemy-5d375cd730fa0a89cb6684df47b2ae10cc217f57.tar.gz
- Declarative supports a __table_args__ class variable, which
is either a dictionary, or tuple of the form (arg1, arg2, ..., {kwarg1:value, ...}) which contains positional + kw arguments to be passed to the Table constructor. [ticket:1096]
-rw-r--r--CHANGES7
-rw-r--r--doc/build/content/plugins.txt16
-rw-r--r--lib/sqlalchemy/ext/declarative.py32
-rw-r--r--test/ext/declarative.py18
4 files changed, 62 insertions, 11 deletions
diff --git a/CHANGES b/CHANGES
index 8d83e7916..814260120 100644
--- a/CHANGES
+++ b/CHANGES
@@ -83,6 +83,13 @@ CHANGES
If you'd like them to return datetime objects anyway despite
their accepting strings as input, make a TypeDecorator around
String - SQLA doesn't encourage this pattern.
+
+- extensions
+ - Declarative supports a __table_args__ class variable, which
+ is either a dictionary, or tuple of the form
+ (arg1, arg2, ..., {kwarg1:value, ...}) which contains positional
+ + kw arguments to be passed to the Table constructor.
+ [ticket:1096]
0.5beta1
========
diff --git a/doc/build/content/plugins.txt b/doc/build/content/plugins.txt
index 6e941cb9d..5f795d497 100644
--- a/doc/build/content/plugins.txt
+++ b/doc/build/content/plugins.txt
@@ -171,11 +171,21 @@ As an alternative to `__tablename__`, a direct `Table` construct may be used. T
Column('name', String(50))
)
-This is the preferred approach when using reflected tables, as below:
+Other table-based attributes include `__table_args__`, which is
+either a dictionary as in:
{python}
- class MyClass(Base):
- __table__ = Table('my_table', Base.metadata, autoload=True)
+ class MyClass(Base)
+ __tablename__ = 'sometable'
+ __table_args__ = {'mysql_engine':'InnoDB'}
+
+or a dictionary-containing tuple in the form
+`(arg1, arg2, ..., {kwarg1:value, ...})`, as in:
+
+ {python}
+ class MyClass(Base)
+ __tablename__ = 'sometable'
+ __table_args__ = (ForeignKeyConstraint(['id'], ['remote_table.id']), {'autoload':True})
Mapper arguments are specified using the `__mapper_args__` class variable. Note that the column objects declared on the class are immediately
usable, as in this joined-table inheritance example:
diff --git a/lib/sqlalchemy/ext/declarative.py b/lib/sqlalchemy/ext/declarative.py
index e69c5f232..cd7efbc17 100644
--- a/lib/sqlalchemy/ext/declarative.py
+++ b/lib/sqlalchemy/ext/declarative.py
@@ -146,10 +146,19 @@ added to the mapping just like a regular mapping to a table::
Column('name', String(50))
)
-This is the preferred approach when using reflected tables, as below::
+Other table-based attributes include ``__table_args__``, which is
+either a dictionary as in::
- class MyClass(Base):
- __table__ = Table('my_table', Base.metadata, autoload=True)
+ class MyClass(Base)
+ __tablename__ = 'sometable'
+ __table_args__ = {'mysql_engine':'InnoDB'}
+
+or a dictionary-containing tuple in the form
+``(arg1, arg2, ..., {kwarg1:value, ...})``, as in::
+
+ class MyClass(Base)
+ __tablename__ = 'sometable'
+ __table_args__ = (ForeignKeyConstraint(['id'], ['remote_table.id']), {'autoload':True})
Mapper arguments are specified using the ``__mapper_args__`` class variable.
Note that the column objects declared on the class are immediately usable, as
@@ -237,11 +246,20 @@ def _as_declarative(cls, classname, dict_):
if '__table__' not in cls.__dict__:
if '__tablename__' in cls.__dict__:
tablename = cls.__tablename__
+
+ table_args = cls.__dict__.get('__table_args__')
+ if isinstance(table_args, dict):
+ args, table_kw = (), table_args
+ elif isinstance(table_args, tuple):
+ args = table_args[0:-1]
+ table_kw = table_args[-1]
+ else:
+ args, table_kw = (), {}
+
autoload = cls.__dict__.get('__autoload__')
if autoload:
- table_kw = {'autoload': True}
- else:
- table_kw = {}
+ table_kw['autoload'] = True
+
cols = []
for key, c in our_stuff.iteritems():
if isinstance(c, ColumnProperty):
@@ -253,7 +271,7 @@ def _as_declarative(cls, classname, dict_):
_undefer_column_name(key, c)
cols.append(c)
cls.__table__ = table = Table(tablename, cls.metadata,
- *cols, **table_kw)
+ *(tuple(cols) + tuple(args)), **table_kw)
else:
table = cls.__table__
diff --git a/test/ext/declarative.py b/test/ext/declarative.py
index ebe608c32..21947b1e6 100644
--- a/test/ext/declarative.py
+++ b/test/ext/declarative.py
@@ -2,7 +2,7 @@ import testenv; testenv.configure_for_tests()
from sqlalchemy.ext import declarative as decl
from testlib import sa, testing
-from testlib.sa import MetaData, Table, Column, Integer, String, ForeignKey
+from testlib.sa import MetaData, Table, Column, Integer, String, ForeignKey, ForeignKeyConstraint
from testlib.sa.orm import relation, create_session
from testlib.testing import eq_
from testlib.compat import set
@@ -255,7 +255,23 @@ class DeclarativeTest(testing.TestBase, testing.AssertsExecutionResults):
sa.exc.ArgumentError,
"Mapper Mapper|User|users could not assemble any primary key",
define)
+
+ def test_table_args(self):
+ class Foo(Base):
+ __tablename__ = 'foo'
+ __table_args__ = {'mysql_engine':'InnoDB'}
+ id = Column('id', Integer, primary_key=True)
+
+ assert Foo.__table__.kwargs['mysql_engine'] == 'InnoDB'
+ class Bar(Base):
+ __tablename__ = 'bar'
+ __table_args__ = (ForeignKeyConstraint(['id'], ['foo.id']), {'mysql_engine':'InnoDB'})
+ id = Column('id', Integer, primary_key=True)
+
+ assert Bar.__table__.c.id.references(Foo.__table__.c.id)
+ assert Bar.__table__.kwargs['mysql_engine'] == 'InnoDB'
+
def test_expression(self):
class User(Base, ComparableEntity):
__tablename__ = 'users'