Thanks very much for that detailed explanation which has proved very 
helpful.

In the end it turns out that the particular construct I need is the simple:

mapper(MyClass, table, properties={
     "timeunits": synonym("time_units")
})

coupled with a data-descriptor for 'timeunits' on the object class which 
translates to and from the database-backed attribute.


Careful reading of the docs here: 
http://www.sqlalchemy.org/docs/04/sqlalchemy_orm.html#docstrings_sqlalchemy.orm_modfunc_synonym
 
sheds further light. I'd like to suggest that the first and fourth 
paragraph of that entry infer exactly the opposite meaning.

Paragraph 1: "Set up name as a synonym to another mapped property."
Paragraph 4: "name refers to the name of the existing mapped property, 
which can be any other MapperProperty including column-based properties 
and relations."

Paragraph 1 implies that the name passed to synonym is the name of the 
synonym. This is not actually the case. It is the entity to which the 
synonym refers.

Anyway.. thanks very much for your help on this. Problem solved and I'm 
very grateful for the time and trouble you took, Micheal. Look forward 
to another happy installation of SQLAlchemy here in London.

Regards,

Toby Bradshaw
Senior Networking Engineer,
Ideawork 3d, London, UK.

Michael Bayer wrote:
> On Jan 26, 2009, at 1:29 PM, Toby Bradshaw wrote:
>
>   
>> Michael Bayer wrote:
>>     
>>> also your example should read like this:
>>>
>>> a = session.query(A).all()[0]
>>> print a.time_units
>>> a.time_units = 1
>>> print a.time_units
>>> #print A.timeunits
>>> #print A.time_units
>>>
>>>       
>> Huh ? time_units is the column name in the database. I want to refer  
>> to
>> that column through the attribute 'timeunits'. I also want to use
>> descriptors to do extra work when setting that attribute. The synonym
>> api docs say:
>>
>> *def synonym(/name/, /map_column=False/, /descriptor=None/, / 
>> proxy=False/)*
>> Set up name as a synonym to another mapped property.
>>
>> So when I say:
>>
>> mapper(A, table_A, properties = {
>> "time_units" : synonym("timeunits", map_column = True)
>> })
>>
>>
>> Am I not saying 'create an alias to column 'time_units' in table_A and
>> call it 'timeunits' ??
>>     
>
> I think your confusion is focused on the concept of SQLAlchemy  
> instrumented descriptors, as it seems you're expecting the SQLAlchemy  
> column-mapped descriptor to "wrap" an existing descriptor.   This is  
> not how it works.     SQLAlchemy does not populate instance state  
> using getattr()/setattr(), in the default case it populates __dict__  
> directly. The dictionary which it uses can be wrapped with a user- 
> defined "proxying" dictionary but that's not an API you need to get  
> involved with.    By moving all low-level operations to __dict__ and  
> all in-python operations to instrumented descriptors, the separation  
> of event-producing attribute access and direct en-masse state access  
> is clear, and the very high-volume activity of populating object state  
> is performed without the overhead of setattr() or event production.
>
> The "synonym" model is provided so that a user-defined descriptor and  
> a SQLAlchemy-column mapped descriptor can co-exist, but instead of  
> being wrapped, they use different names.   So usage of the model  
> means:  one descriptor maps to the column and is entirely generated by  
> SQLAlchemy, the other is your custom descriptor and SQLAlchemy places  
> a proxy around it to provide class-level behavior like Foo.bar ==  
> somevalue (which you also might want to customize, but that's a  
> different issue).   Your custom descriptor is the public face of the  
> attribute, and communicates with the value that exists in the database  
> using the column-mapped descriptor, which is usually treated as  
> private.   Symmetric set/get behavior is provided by the user-defined  
> descriptor as the sole public interface.
>
> So since you'd like to refer to the *translated* attribute as  
> "timeunits", i think you'd want to configure this way:
> mapper(MyClass, table, properties={
>      "timeunits": synonym("time_units")
> })
>
> class MyClass(object):
>      ...
>      timeunits = property(_get, _set)
>
> mapper(MyClass, table, properties={
>      "_timeunits":table.c.time_units,
>      "timeunits": synonym("_timeunits")
> })
>
> which will map the original "time_units" column to the mapped  
> attribute "_timeunits", and the "timeunits" descriptor will provide  
> class-level comparison behavior (i.e. MyClass.timeunits == 5).   the  
> map_column flag does not apply here since you are naming your  
> descriptor something different than the original mapped column.  The  
> column-mapped attribute "_timeunits"  is generally treated as  
> "private" within the application space since it represents directly  
> the "raw" data that is populated/retrieved to/from the database.
>
> you can also leave "time_units" mapped under its own name:
>
> mapper(MyClass, table, properties={
> mapper(MyClass, table, properties={
>      "timeunits": synonym("time_units")
> })
>      "timeunits": synonym("time_units")
> })
>
> in which case your descriptor would communicate raw values to/from the  
> "time_units" attribute, which is mapped automatically to its own name.
>
> Also consider that direct translation of a single column can be  
> accomplished at the Table level using a custom TypeDecorator.   If you  
> went with that route, there would be no need to use synonym() or  
> custom descriptors.
>
>
>
>
> > mapper(MyClass, table, properties={
>      "timeunits": synonym("time_units")
> })
>
>   

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