On Fri, Jul 12, 2019, at 11:20 AM, Michael P. McDonnell wrote:
> Hey Team - 
> 
> So I'm working on a relatively fun hierarchy that allows me to relate tasks 
> to games. 
> So I have 2 tables:
> 
> # A Generic Task Definition - not related to anything
> class Task_Definition(Base):
>  def __repr__(self):
>  return (
>  "<TaskDefinition id='" + str(self.id) + "' "
>  + "name='" + self.name + "'>")
>  __table__ = task_definition_table # has name, id, etc...
> 
> # and a Task Table - specific to a game:
> class Task(Base):
>  def __repr__(self):
>  return (
>  "<Task id='" + str(self.id) + "' name='" + self.name
>  + "' game_id='" + str(self.game_id)
>  + " task_definition_id=" + str(self.task_definition_id) + "'>")
>  __table__ = task_table # has game_id, start_dttm, end_dttm, etc...
> 
> So originally I had my task as a 
> __table__ = join(task_definition_table, task_table)
> 
> That allowed me to select a task, and see all of the task_definition 
> properties as one "Object"
> But the problem is: when I created a task - it wanted to create a new 
> task_definition at the same time, which is not what I wanted - given that 
> task_definitions are a generic that can be used anytime.
> 
> So then I created a task like this:
> class Task(Base):
>  def __repr__(self):
>  return (
>  "<Task id='" + str(self.id) + "' name='" + self.name
>  + "' game_id='" + str(self.game_id)
>  + " task_definition_id=" + str(self.task_definition_id) + "'>")
>  __table__ = task_table
>  task_definition_id = column_property(
>  task_definition_table.c.id,
>  task_definition_language_table.c.task_definition_id,
>  task_table.c.task_definition_id)
>  name = column_property(task_definition_language_table.c.name)
>  description = column_property(task_definition_language_table.c.description)
>  instructions = column_property(
>  task_definition_language_table.c.instructions)
> 
> That allowed me to insert properly - but then my selects were coming back 
> with tons of duplicate rows. 
> 
> When I played with the query - it was because it was doing a
> SELECT * from task, task_definition
> as opposed to a 
> select * from task JOIN task_definition...
> 
> Is there an easy way to force a join on select, and then a direct table 
> communication on insert?

So if you wanted to use column_property() like that, you would do it with a 
correlated select, as seen in the example at 
https://docs.sqlalchemy.org/en/13/orm/mapped_sql_expr.html#using-column-property.
 However, you have a whole bunch of them here and correlated selects aren't 
efficient from a SQL perspective. 

>From the ORM point of view, exactly what you want is available using 
>relationship() with lazy='joined':

class Task(Base):
 # ...

 description = relationship("TaskDefinition", lazy="joined")

But you don't want to say "mytask.description.name", OK. The data is in Python 
now so you can use all of Python's capabilities, in this case it would be to 
use descriptors:

class Task(Base):
 # ...

 @property
 def description(self):
 return self._description.description

 @description.setter # optional setter
 def description(self, value):
 self._description.description = value

 # etc ...

 _description = relationship("TaskDefinition", lazy="joined")


The above pattern is also available using the association proxy, which might be 
a little bit heavy-handed here, however is less code up front, association 
proxy is at 
https://docs.sqlalchemy.org/en/13/orm/extensions/associationproxy.html#:

from sqlalchemy.ext.associationproxy import association_proxy

class Task(Base):
 # ...
 description = association_proxy("_description", "description")

 # etc ...

 _description = relationship("TaskDefinition", lazy="joined")


hope this helps!





> 
> 
> -Mike
> 
> 

> --
>  SQLAlchemy - 
>  The Python SQL Toolkit and Object Relational Mapper
> 
> http://www.sqlalchemy.org/
> 
>  To post example code, please provide an MCVE: Minimal, Complete, and 
> Verifiable Example. See http://stackoverflow.com/help/mcve for a full 
> description.
>  --- 
>  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 https://groups.google.com/group/sqlalchemy.
>  To view this discussion on the web visit 
> https://groups.google.com/d/msgid/sqlalchemy/328f63b3-dda4-4b59-a85b-52846e319d53%40googlegroups.com
>  
> <https://groups.google.com/d/msgid/sqlalchemy/328f63b3-dda4-4b59-a85b-52846e319d53%40googlegroups.com?utm_medium=email&utm_source=footer>.
>  For more options, visit https://groups.google.com/d/optout.

-- 
SQLAlchemy - 
The Python SQL Toolkit and Object Relational Mapper

http://www.sqlalchemy.org/

To post example code, please provide an MCVE: Minimal, Complete, and Verifiable 
Example.  See  http://stackoverflow.com/help/mcve for a full description.
--- 
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 https://groups.google.com/group/sqlalchemy.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/sqlalchemy/9429f760-5845-47cf-92b6-dee34e9f0c1c%40www.fastmail.com.
For more options, visit https://groups.google.com/d/optout.

Reply via email to