On 12/10/2015 10:21 AM, Michal Petrucha wrote:
> 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 first thing I don't understand is that the code you refer to is
locating the correct name dynamically.  So why does it matter?   You
aren't typing in the name of the table or class yourself.


Second thing is, you can pass the class-bound column to the
ForeignKey, sure, just as an object, not a string:

    ForeignKey(WhateverClass.id)

it just requires that you have WhateverClass already available.





> 
> 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/b
ase.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_ass
ociations/table_per_related.py
>
>
> 
[3]:
https://github.com/zzzeek/sqlalchemy/blob/rel_0_9/examples/generic_assoc
iations/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.

Reply via email to