Hello alchemists,

There's something that's been bugging me for a while now. I even asked
about it on [stackoverflow][1], but it didn't get much attention
there. It's been suggested to me on IRC that this mailing list might
be a better place for this question.

When you take a look at the [table_per_relation ORM example][2], you
can see that the argument passed to `ForeignKey` [here][3] is the
“raw” “tablename.column”. However, since the entire point of
declarative is to use higher-level constructs to abstract away some of
the lower-level SQL details, it would make sense to me to use `cls.id`
here instead. (I want this here declarative field to point to this
other declarative field, instead of saying, I want this declarative
field to point to this SQL column of that SQL table.)

The problem is, when you try to do that, you'll get the following
error:

    (env-tmp)koniiiik@parahippus /tmp $  python table_per_related.py 
    2015-10-20 13:05:44,366 INFO sqlalchemy.engine.base.Engine SELECT 
CAST('test plain returns' AS VARCHAR(60)) AS anon_1
    2015-10-20 13:05:44,366 INFO sqlalchemy.engine.base.Engine ()
    2015-10-20 13:05:44,367 INFO sqlalchemy.engine.base.Engine SELECT 
CAST('test unicode returns' AS VARCHAR(60)) AS anon_1
    2015-10-20 13:05:44,367 INFO sqlalchemy.engine.base.Engine ()
    2015-10-20 13:05:44,367 INFO sqlalchemy.engine.base.Engine PRAGMA 
table_info("supplier_address")
    2015-10-20 13:05:44,367 INFO sqlalchemy.engine.base.Engine ()
    2015-10-20 13:05:44,368 INFO sqlalchemy.engine.base.Engine PRAGMA 
table_info("customer")
    2015-10-20 13:05:44,368 INFO sqlalchemy.engine.base.Engine ()
    2015-10-20 13:05:44,368 INFO sqlalchemy.engine.base.Engine PRAGMA 
table_info("supplier")
    2015-10-20 13:05:44,368 INFO sqlalchemy.engine.base.Engine ()
    2015-10-20 13:05:44,368 INFO sqlalchemy.engine.base.Engine PRAGMA 
table_info("customer_address")
    2015-10-20 13:05:44,368 INFO sqlalchemy.engine.base.Engine ()
    Traceback (most recent call last):
      File "table_per_related.py", line 81, in <module>
        Base.metadata.create_all(engine)
      File "/tmp/env-tmp/lib/python3.4/site-packages/sqlalchemy/sql/schema.py", 
line 3431, in create_all
        tables=tables)
      File 
"/tmp/env-tmp/lib/python3.4/site-packages/sqlalchemy/engine/base.py", line 
1726, in _run_visitor
        conn._run_visitor(visitorcallable, element, **kwargs)
      File 
"/tmp/env-tmp/lib/python3.4/site-packages/sqlalchemy/engine/base.py", line 
1357, in _run_visitor
        **kwargs).traverse_single(element)
      File 
"/tmp/env-tmp/lib/python3.4/site-packages/sqlalchemy/sql/visitors.py", line 
120, in traverse_single
        return meth(obj, **kw)
      File "/tmp/env-tmp/lib/python3.4/site-packages/sqlalchemy/sql/ddl.py", 
line 713, in visit_metadata
        self.traverse_single(table, create_ok=True)
      File 
"/tmp/env-tmp/lib/python3.4/site-packages/sqlalchemy/sql/visitors.py", line 
120, in traverse_single
        return meth(obj, **kw)
      File "/tmp/env-tmp/lib/python3.4/site-packages/sqlalchemy/sql/ddl.py", 
line 732, in visit_table
        self.connection.execute(CreateTable(table))
      File 
"/tmp/env-tmp/lib/python3.4/site-packages/sqlalchemy/engine/base.py", line 841, 
in execute
        return meth(self, multiparams, params)
      File "/tmp/env-tmp/lib/python3.4/site-packages/sqlalchemy/sql/ddl.py", 
line 69, in _execute_on_connection
        return connection._execute_ddl(self, multiparams, params)
      File 
"/tmp/env-tmp/lib/python3.4/site-packages/sqlalchemy/engine/base.py", line 889, 
in _execute_ddl
        compiled = ddl.compile(dialect=dialect)
      File "<string>", line 1, in <lambda>
      File 
"/tmp/env-tmp/lib/python3.4/site-packages/sqlalchemy/sql/elements.py", line 
493, in compile
        return self._compiler(dialect, bind=bind, **kw)
      File "/tmp/env-tmp/lib/python3.4/site-packages/sqlalchemy/sql/ddl.py", 
line 27, in _compiler
        return dialect.ddl_compiler(dialect, self, **kw)
      File 
"/tmp/env-tmp/lib/python3.4/site-packages/sqlalchemy/sql/compiler.py", line 
199, in __init__
        self.string = self.process(self.statement, **compile_kwargs)
      File 
"/tmp/env-tmp/lib/python3.4/site-packages/sqlalchemy/sql/compiler.py", line 
222, in process
        return obj._compiler_dispatch(self, **kwargs)
      File 
"/tmp/env-tmp/lib/python3.4/site-packages/sqlalchemy/sql/visitors.py", line 80, 
in _compiler_dispatch
        return meth(self, **kw)
      File 
"/tmp/env-tmp/lib/python3.4/site-packages/sqlalchemy/sql/compiler.py", line 
2415, in visit_create_table
        const = self.create_table_constraints(table)
      File 
"/tmp/env-tmp/lib/python3.4/site-packages/sqlalchemy/sql/compiler.py", line 
2452, in create_table_constraints
        for constraint in constraints
      File 
"/tmp/env-tmp/lib/python3.4/site-packages/sqlalchemy/sql/compiler.py", line 
2450, in <genexpr>
        return ", \n\t".join(p for p in
      File 
"/tmp/env-tmp/lib/python3.4/site-packages/sqlalchemy/sql/compiler.py", line 
2458, in <genexpr>
        not getattr(constraint, 'use_alter', False)
      File 
"/tmp/env-tmp/lib/python3.4/site-packages/sqlalchemy/sql/compiler.py", line 
222, in process
        return obj._compiler_dispatch(self, **kwargs)
      File 
"/tmp/env-tmp/lib/python3.4/site-packages/sqlalchemy/sql/visitors.py", line 80, 
in _compiler_dispatch
        return meth(self, **kw)
      File 
"/tmp/env-tmp/lib/python3.4/site-packages/sqlalchemy/dialects/sqlite/base.py", 
line 835, in visit_foreign_key_constraint
        if local_table.schema != remote_table.schema:
    AttributeError: 'NoneType' object has no attribute 'schema'

As far as I understand, this is because the `id` class attribute of
`Supplier` does not get properly bound to its table; or at least, not
before it is picked up by the `declared_attr` in `HasAddresses`.
Several declarative constructs support passing callables for deferred
evaluation, but this doesn't work for the argument passed to
`ForeignKey`, since `ForeignKey` is a low-level constraint object, not
a declarative one.

Am I missing something here, or is there simply no way around mixing
“raw” SQL identifiers with higher-level declarative classes and
objects in this scenario?

Cheers,
Michal


[1]: http://stackoverflow.com/q/33235293/687488
[2]: 
https://github.com/zzzeek/sqlalchemy/blob/rel_0_9/examples/generic_associations/table_per_related.py
[3]: 
https://github.com/zzzeek/sqlalchemy/blob/rel_0_9/examples/generic_associations/table_per_related.py#L68

-- 
You received this message because you are subscribed to the Google Groups 
"sqlalchemy" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to sqlalchemy+unsubscr...@googlegroups.com.
To post to this group, send email to sqlalchemy@googlegroups.com.
Visit this group at http://groups.google.com/group/sqlalchemy.
For more options, visit https://groups.google.com/d/optout.

Attachment: signature.asc
Description: Digital signature

Reply via email to