On Jan 5, 2013, at 7:42 AM, Alexander Jacob wrote:

> @compiles(i18NColumnClause)
> def compile_i18n_column_clause(element, compiler, **kw):
>     return '%s_%s' % (element.name, GLOBAL_LANGUAGE)
>  
> # custom type
> class i18NType(sqlalchemy.types.TypeDecorator):
>     impl = sqlalchemy.types.Unicode
>     def column_expression(self, colexpr):
>         return i18NColumnClause(colexpr)
>  
> # test class for custom type
> class Country(Base):
>  
>     __tablename__ = 'country'
>     id = Column(Integer, primary_key=True)
>     iso2 = Column(String(2))
>     name = Column(i18NType(64))
>  
>     def __repr__(self):
>         return "<Country(%d/%s/%s)>" % (self.id, self.iso2, self.name)
>  


Interesting approach with the column_expression(), though that seems like it 
would circumvent the labeling behavior of the compiler and cause more complex 
expressions to fail.   The INSERT case might work if you also implemented 
bind_expression() but I'm not sure if that approach overall doesn't break too 
much of the existing compilation functionality.

A more direct route with @compiles would be to compile Column, but still 
tricky, in particular that the compilation process for a Column is very 
involved.   At the very least, for that to work it would have to be like this:

class i18NColumn(Column):   # note it has to be Column, not ColumnClause
   pass

@compiles(i18NColumn)
def compile(element, compiler, **kw):
    text = compile.visit_column(element, **kw)
    text = text.replace(element.name, '%s_%s' %(element.name, GLOBAL_LANGUAGE))
    return text

so that existing labeling rules are not circumvented.  but even that I'm not 
100% sure might not have some gotchas.    

Another variant on this would be to use the before_cursor_execute event to just 
do a search and replace on the SQL statement before it's passed to the DBAPI, I 
sometimes recommend that as well.  Giving the "fake" column a name that clearly 
indicates internationalization, like Column("name_<i18N>"), is a good way to 
give a statement filter a clear path to where those names would go. If you need 
this translation behavior everywhere, that might be the best approach.

Though here, there's a less intrusive way to get this behavior if ORM level is 
all you need which is by using hybrids:

class Country(Base):
    # ...
 
   name_de = Column(String)
   name_en = Column(String)

   @hybrid_property
   def name(self):
        return getattr(self, "name_%s" % GLOBAL_LANGUAGE)

   @name.setter
   def name(self, value):
       setattr(self, "name_%s" % GLOBAL_LANGUAGE, value)

the above can be generalized:

def make_hybrid(name):
   @hybrid_property
   def name_attr(self):
        return getattr(self, "%s_%s" % (name, GLOBAL_LANGUAGE))

   @name_attr.setter
   def name_attr(self, value):
       setattr(self, "%s_%s" % (name, GLOBAL_LANGUAGE), value)

   name_attr.__name__ = name
   return name_attr
  

-- 
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.

Reply via email to