Re: [sqlalchemy] Declarative Field Type 'Alias'

2011-08-06 Thread Wichert Akkerman

On 08/05/2011 10:46 PM, Mark Erbaugh wrote:

This is more of a Python issue than a SA issue, but I had trouble getting this to 
work. I did, but the code seems a little awkard to mesigh.  In addition to 
the requirements already, I also wanted toe default value to be a class level 
'constant'.  The problem, as I see it, is that since the class definition isn't 
complete, it's namespace isn't avaialble.  Since the default value 'constant' is a 
class data member, it would make sense if the function were a @classmethod, but I 
couldn't get python to accept:

class  Table(Base):

...

DEFAULT = 2

@classmethod
def CustomColumn(cls):
return Column(Integer, default=DEFAULT)


that should be cls.DEFAULT


...

field1 = CustomColumn()

Python complained 'classmethod object is not callable' on the last line above.


You can only call a class method on a class. In this case that would be 
Table.CustomColumn(). However since the Table class is not available at 
this point you can't do that. You can do this sort of thing with 
metaclasses, but I would not recommend going down that paht.




What I finally ended up with that works is:

class Table(Base):
...
DEFAULT = 2

def CustomColumn(default=DEFAULT):
return Column(Integer, default=default)

...

field1 = CustomColumn()


That looks like a pretty good solution.

Wichert.

--
You received this message because you are subscribed to the Google Groups 
sqlalchemy group.
To post to this group, send email to sqlalchemy@googlegroups.com.
To unsubscribe from this group, send email to 
sqlalchemy+unsubscr...@googlegroups.com.
For more options, visit this group at 
http://groups.google.com/group/sqlalchemy?hl=en.



[sqlalchemy] Declarative Field Type 'Alias'

2011-08-05 Thread Mark Erbaugh
In my application, some tables have several fields that need to have the same 
type and default value, i.e.:

field1 = Column(Integer, default=2)
field2 = Column(Integer, default=2)
...

Is there some way to refactor the Common(Integer, default=2), short of creating 
a custom column type?  I could see the possibility that in a future version of 
the application, I would want to globally change the column type or default 
value for all these fields at once.

So far, I've come up with creating a function that returns the column.

def common_field():
return Column(Integer, default=2)

field1 = common_field()
field2 = common_field()

Is there a better way?

Mark

-- 
You received this message because you are subscribed to the Google Groups 
sqlalchemy group.
To post to this group, send email to sqlalchemy@googlegroups.com.
To unsubscribe from this group, send email to 
sqlalchemy+unsubscr...@googlegroups.com.
For more options, visit this group at 
http://groups.google.com/group/sqlalchemy?hl=en.



Re: [sqlalchemy] Declarative Field Type 'Alias'

2011-08-05 Thread Michael Bayer

On Aug 5, 2011, at 1:36 PM, Mark Erbaugh wrote:

 In my application, some tables have several fields that need to have the same 
 type and default value, i.e.:
 
 field1 = Column(Integer, default=2)
 field2 = Column(Integer, default=2)
 ...
 
 Is there some way to refactor the Common(Integer, default=2), short of 
 creating a custom column type?  I could see the possibility that in a future 
 version of the application, I would want to globally change the column type 
 or default value for all these fields at once.
 
 So far, I've come up with creating a function that returns the column.
 
 def common_field():
   return Column(Integer, default=2)
 
 field1 = common_field()
 field2 = common_field()
 
 Is there a better way?

What's the issue with using a function to generate a Column of a certain 
pre-determined configuration (what are functions in a procedural language for 
if not this) ?  

FTR I use functions to generate prefab Column objects all the time and they are 
also intrinsic to the example application I've created for the SQLAlchemy book 
project (which is on a somewhat indefinite schedule at the moment, unless 
someone wants to help write) .

If the issue is that these tables need to have a certain series of completely 
fixed columns, i.e. same names and everything, here are a series of approaches 
for that depending on what you're doing.

1. Regular declarative ?  Use declarative mixins. 

class MyMixin(object):
 updated_at = Column(DateTime, onupdate=datetime.utcnow)

2. if I am using Table metadata directly (i.e. with declarative, __table__ = 
Table()), I'd typically use a function around Table:

def standard_table(*args, **kw):
return Table(*(args + [_standard_table_cols()]), **kw)

3. For all tables, use events:

@event.listens_for(Table, after_parent_attach)
def _table_standard_cols(table, metadata):
table.append_column(Column(DateTime, onupdate=datetime.utcnow))

4. Certain classes of tables...there's probably a nice way to combine the table 
events with a subset of table classes.   (tries...success !)

from sqlalchemy import *
from sqlalchemy import event
from sqlalchemy.schema import CreateTable
import datetime

class TableWithUTC(Table):
pass

@event.listens_for(TableWithUTC, after_parent_attach)
def _add_col(table, metadata):
table.append_column(Column('updated_at', DateTime, 
onupdate=datetime.datetime.utcnow))

m = MetaData()

t1 = Table('t1', m, Column('x', Integer))
t2 = TableWithUTC('t2', m, Column('x', Integer))
t3 = TableWithUTC('t3', m, Column('x', Integer))
t4 = Table('t4', m, Column('x', Integer))

assert t2.c.updated_at is not None
assert 'updated_at' not in t4.c

for name in 't1', 't2', 't3', 't4':
print CreateTable(m.tables[name])






-- 
You received this message because you are subscribed to the Google Groups 
sqlalchemy group.
To post to this group, send email to sqlalchemy@googlegroups.com.
To unsubscribe from this group, send email to 
sqlalchemy+unsubscr...@googlegroups.com.
For more options, visit this group at 
http://groups.google.com/group/sqlalchemy?hl=en.



Re: [sqlalchemy] Declarative Field Type 'Alias'

2011-08-05 Thread Mark Erbaugh

On Aug 5, 2011, at 3:51 PM, Michael Bayer wrote:

 On Aug 5, 2011, at 1:36 PM, Mark Erbaugh wrote:
 
 In my application, some tables have several fields that need to have the 
 same type and default value, i.e.:
 
 field1 = Column(Integer, default=2)
 field2 = Column(Integer, default=2)
 ...
 
 Is there some way to refactor the Common(Integer, default=2), short of 
 creating a custom column type?  I could see the possibility that in a future 
 version of the application, I would want to globally change the column type 
 or default value for all these fields at once.
 
 So far, I've come up with creating a function that returns the column.
 
 def common_field():
  return Column(Integer, default=2)
 
 field1 = common_field()
 field2 = common_field()
 
 Is there a better way?
 
 What's the issue with using a function to generate a Column of a certain 
 pre-determined configuration (what are functions in a procedural language for 
 if not this) ?  


No issue at all.  I just wanted to make sure I was doing it 'the right way'.  I 
just noticed that in several places, SA will let you pass in a class or an 
instance of a class and figures out what to do with it.  I thought that 
something like that might be working here.

Actually, there is a small issue with using a function: Where should the 
function live?  Obviously for some schema, this field type is used in multiple 
tables and belongs in a global namespace, but for others (as in my 
application), the field type is unique to an individual table. It would be nice 
if the function could live in the class's namespace.

This is more of a Python issue than a SA issue, but I had trouble getting this 
to work. I did, but the code seems a little awkard to me sigh.  In addition 
to the requirements already, I also wanted toe default value to be a class 
level 'constant'.  The problem, as I see it, is that since the class definition 
isn't complete, it's namespace isn't avaialble.  Since the default value 
'constant' is a class data member, it would make sense if the function were a 
@classmethod, but I couldn't get python to accept:

class  Table(Base):

...

DEFAULT = 2

@classmethod
def CustomColumn(cls):
return Column(Integer, default=DEFAULT)

...

field1 = CustomColumn()

Python complained 'classmethod object is not callable' on the last line above.

Next I tried changing that line to:

field1 = Table.CustomColumn()

Now Python complained 'Table' is not  defined

If I leave the @classmethod decroator off, I couldn't figure out how to 
reference the class level data DEFAULT.

Python complained on the return Column(... line ' global name DEFAULT is not 
defined.

What I finally ended up with that works is:

class Table(Base):
...
DEFAULT = 2

def CustomColumn(default=DEFAULT):
return Column(Integer, default=default)

...

field1 = CustomColumn()

Mark


-- 
You received this message because you are subscribed to the Google Groups 
sqlalchemy group.
To post to this group, send email to sqlalchemy@googlegroups.com.
To unsubscribe from this group, send email to 
sqlalchemy+unsubscr...@googlegroups.com.
For more options, visit this group at 
http://groups.google.com/group/sqlalchemy?hl=en.