[sqlalchemy] declarative - automatically add a primary key if the table doesn't have one

2010-09-22 Thread Yap Sok Ann
This is related to topic need 0.6_beta2-compat declarative meta
http://groups.google.com/group/sqlalchemy/browse_thread/thread/ae7cb9d2ab0b9cca

Prior to version 0.6, I use the following code to automatically add a
primary key if the table doesn't have one defined:

from sqlalchemy.ext.declarative import declarative_base,
DeclarativeMeta
from sqlalchemy.schema import Column
from sqlalchemy.types import Integer

class Meta(DeclarativeMeta):
def __init__(cls, classname, bases, dict_):
for attr in dict_.itervalues():
if isinstance(attr, Column) and attr.primary_key:
break
else:
dict_['id'] = Column(Integer, primary_key=True)
return super(Meta, cls).__init__(classname, bases, dict_)

Base = declarative_base(metaclass=Meta)

Of course, that doesn't work anymore in 0.6. The suggestion from the
aforementioned threads is to replace:

dict_['id'] = Column(Integer, primary_key=True)

with

cls.id = Column(Integer, primary_key=True)

Unfortunately, that alone doesn't work in this case. The problem is
that the Base class itself will be the first one to go through the
Meta.__init__() method, so the whole thing essentially becomes:

Base.id = Column(Integer, primary_key=True)

For it to work, I have to wrap the code in an if-block, i.e.

class Meta(DeclarativeMeta):
def __init__(cls, classname, bases, dict_):
if classname != 'Base':
for attr in dict_.itervalues():
if isinstance(attr, Column) and attr.primary_key:
break
else:
cls.id = Column(Integer, primary_key=True)
return super(Meta, cls).__init__(classname, bases, dict_)

which looks rather ugly. Is there a cleaner way to achieve this?

-- 
You received this message because you are subscribed to the Google Groups 
sqlalchemy group.
To post to this group, send email to sqlalch...@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 - automatically add a primary key if the table doesn't have one

2010-09-22 Thread Michael Bayer

On Sep 22, 2010, at 4:30 AM, Yap Sok Ann wrote:

 This is related to topic need 0.6_beta2-compat declarative meta
 http://groups.google.com/group/sqlalchemy/browse_thread/thread/ae7cb9d2ab0b9cca
 
 Prior to version 0.6, I use the following code to automatically add a
 primary key if the table doesn't have one defined:
 
 from sqlalchemy.ext.declarative import declarative_base,
 DeclarativeMeta
 from sqlalchemy.schema import Column
 from sqlalchemy.types import Integer
 
 class Meta(DeclarativeMeta):
def __init__(cls, classname, bases, dict_):
for attr in dict_.itervalues():
if isinstance(attr, Column) and attr.primary_key:
break
else:
dict_['id'] = Column(Integer, primary_key=True)
return super(Meta, cls).__init__(classname, bases, dict_)
 
 Base = declarative_base(metaclass=Meta)
 
 Of course, that doesn't work anymore in 0.6. The suggestion from the
 aforementioned threads is to replace:
 
 dict_['id'] = Column(Integer, primary_key=True)
 
 with
 
 cls.id = Column(Integer, primary_key=True)
 
 Unfortunately, that alone doesn't work in this case. The problem is
 that the Base class itself will be the first one to go through the
 Meta.__init__() method, so the whole thing essentially becomes:
 
 Base.id = Column(Integer, primary_key=True)
 
 For it to work, I have to wrap the code in an if-block, i.e.
 
 class Meta(DeclarativeMeta):
def __init__(cls, classname, bases, dict_):
if classname != 'Base':
for attr in dict_.itervalues():
if isinstance(attr, Column) and attr.primary_key:
break
else:
cls.id = Column(Integer, primary_key=True)
return super(Meta, cls).__init__(classname, bases, dict_)
 
 which looks rather ugly. Is there a cleaner way to achieve this?

I didn't think metaclasses were supposed to be pretty ?Checking that you're 
not the base is pretty standard metaclass stuff.  If the hardcoded name 
is the issue, you can look in bases:

if object not in bases:
 
or something more generic:

for k in cls.__mro__[1:]:
if isinstance(k, Meta):
# you're a Base subclass



 
 -- 
 You received this message because you are subscribed to the Google Groups 
 sqlalchemy group.
 To post to this group, send email to sqlalch...@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.
 

-- 
You received this message because you are subscribed to the Google Groups 
sqlalchemy group.
To post to this group, send email to sqlalch...@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.