[sqlalchemy] Behavior question with association proxy with custom collection class
I was exploring the association proxy example in the documentation and then explored the use of a mapped collection as the custom collection class with mixed results. When attempting to append, an AttributeError _AssociationDict object has no attribute append occurred. Then, I tried subclassing MappedCollection, created my own append method and have SQLAlchemy instrument it but the results were the same. Here's the code I was testing it with: from sqlalchemy import Boolean, Column, ForeignKey, Integer, String, Table from sqlalchemy.orm import relation from sqlalchemy.orm.collections import mapped_collection, MappedCollection, collection from sqlalchemy.ext.associationproxy import association_proxy from turbogears.database import metadata, session users_table = Table('users', metadata, Column('id', Integer, primary_key=True), Column('name', String(64)) ) keywords_table = Table('keywords', metadata, Column('id', Integer, primary_key=True), Column('keyword', String(64)) ) userkeywords_table = Table('userkeywords', metadata, Column('user_id', Integer, ForeignKey(users.id), primary_key=True), Column('keyword_id', Integer, ForeignKey(keywords.id), primary_key=True) ) def _create_uk(keyword): return UserKeyword(keyword=keyword) class User(object): def __init__(self, id, name): self.id = id self.name = name keywords = association_proxy('user_keywords', 'keyword', creator=_create_uk) class Keyword(object): def __init__(self, id, keyword): self.id = id self.keyword = keyword def __repr__(self): return 'Keyword(%s)' % repr(self.keyword) class UserKeyword(object): def __init__(self, user=None, keyword=None): self.user = user self.keyword = keyword session.mapper(Keyword, keywords_table) session.mapper(User, users_table, properties={ 'user_keywords':relation(UserKeyword) }) session.mapper(UserKeyword, userkeywords_table, properties={ 'user':relation(User), 'keyword':relation(Keyword) }) user = User('1', 'number') kw1 = Keyword('0', 'zero') user.user_keywords.append(UserKeyword(user, kw1)) for kw in (Keyword('1', 'one'), Keyword('2', 'two'), Keyword('3', 'three')): user.keywords.append(kw) Portion of code changed with mapped collection (which won't work): session.mapper(User, users_table, properties={ #'user_keywords':relation(UserKeyword) 'user_keywords':relation(UserKeyword, collection_class=mapped_collection(lambda item: item.keyword.id)) }) Code for customized collection (also won't work): class MyCollection(MappedCollection): def __init__(self, keyfunc=lambda item: item.id): MappedCollection.__init__(self, keyfunc=keyfunc) @collection.appender def append(self, item): MappedCollection.set(self, item) @collection.remover def remove(self, item): MappedCollection.remove(self, item) u_collection = lambda: MyCollection(keyfunc=lambda item: item.keyword.id) session.mapper(User, users_table, properties={ #'user_keywords':relation(UserKeyword) 'user_keywords':relation(UserKeyword, collection_class=u_collection) }) --~--~-~--~~~---~--~~ 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 [EMAIL PROTECTED] For more options, visit this group at http://groups.google.com/group/sqlalchemy?hl=en -~--~~~~--~~--~--~---
[sqlalchemy] Re: Behavior question with association proxy with custom collection class
I assume a getset_factory is needed for the association proxy. Any examples? On Feb 21, 8:38 am, Ronald Lew [EMAIL PROTECTED] wrote: I was exploring the association proxy example in the documentation and then explored the use of a mapped collection as the custom collection class with mixed results. When attempting to append, an AttributeError _AssociationDict object has no attribute append occurred. Then, I tried subclassing MappedCollection, created my own append method and have SQLAlchemy instrument it but the results were the same. Here's the code I was testing it with: from sqlalchemy import Boolean, Column, ForeignKey, Integer, String, Table from sqlalchemy.orm import relation from sqlalchemy.orm.collections import mapped_collection, MappedCollection, collection from sqlalchemy.ext.associationproxy import association_proxy from turbogears.database import metadata, session users_table = Table('users', metadata, Column('id', Integer, primary_key=True), Column('name', String(64)) ) keywords_table = Table('keywords', metadata, Column('id', Integer, primary_key=True), Column('keyword', String(64)) ) userkeywords_table = Table('userkeywords', metadata, Column('user_id', Integer, ForeignKey(users.id), primary_key=True), Column('keyword_id', Integer, ForeignKey(keywords.id), primary_key=True) ) def _create_uk(keyword): return UserKeyword(keyword=keyword) class User(object): def __init__(self, id, name): self.id = id self.name = name keywords = association_proxy('user_keywords', 'keyword', creator=_create_uk) class Keyword(object): def __init__(self, id, keyword): self.id = id self.keyword = keyword def __repr__(self): return 'Keyword(%s)' % repr(self.keyword) class UserKeyword(object): def __init__(self, user=None, keyword=None): self.user = user self.keyword = keyword session.mapper(Keyword, keywords_table) session.mapper(User, users_table, properties={ 'user_keywords':relation(UserKeyword)}) session.mapper(UserKeyword, userkeywords_table, properties={ 'user':relation(User), 'keyword':relation(Keyword) }) user = User('1', 'number') kw1 = Keyword('0', 'zero') user.user_keywords.append(UserKeyword(user, kw1)) for kw in (Keyword('1', 'one'), Keyword('2', 'two'), Keyword('3', 'three')): user.keywords.append(kw) Portion of code changed with mapped collection (which won't work): session.mapper(User, users_table, properties={ #'user_keywords':relation(UserKeyword) 'user_keywords':relation(UserKeyword, collection_class=mapped_collection(lambda item: item.keyword.id)) }) Code for customized collection (also won't work): class MyCollection(MappedCollection): def __init__(self, keyfunc=lambda item: item.id): MappedCollection.__init__(self, keyfunc=keyfunc) @collection.appender def append(self, item): MappedCollection.set(self, item) @collection.remover def remove(self, item): MappedCollection.remove(self, item) u_collection = lambda: MyCollection(keyfunc=lambda item: item.keyword.id) session.mapper(User, users_table, properties={ #'user_keywords':relation(UserKeyword) 'user_keywords':relation(UserKeyword, collection_class=u_collection) }) --~--~-~--~~~---~--~~ 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 [EMAIL PROTECTED] For more options, visit this group at http://groups.google.com/group/sqlalchemy?hl=en -~--~~~~--~~--~--~---
[sqlalchemy] Collection class using OrderedDict and MappedCollection
I am creating a Collection class using the OrderedDict and MappedCollection with primary key id as the key index. The problem, as noted in the docs, is that the key should be an immutable field. Since I am using a primary key, the value will change when I am instantiating a new object and adding it to the collection. The code illustrates my concept: class Collection(OrderedDict, MappedCollection): def __init__(self, *args, **kwargs): MappedCollection.__init__(self, keyfunc=lambda item: item.id) OrderedDict.__init__(self, *args, **kwargs) def refresh(self, *args, **kwargs): Updates all keys based on the keyfunc and each current value dict_copy = self.copy() self.clear() for item in dict_copy.values(): MappedCollection.set(self, item) class Parent(Base): pass class Child(Base): pass session.mapper(class_=Child, local_table=child_table) session.mapper(class_=Parent, local_table=parent_table, properties={'childs':relation(Child, backref='parent', collection_class=ChildCollection)}) some_collection = ChildCollection() new_child = Child(id=None, data='foo') some_collection.set(new_child) # key is None, id is None session.save(some_collection.values()) # save the child # at this point, key is still None, but id is 1 some_collection.refresh() # key will be 1. # I would like the refresh behavior to be invoked during/after a flush. Now, if I saved the Child under the Parent, then the key index would have been updated automatically like so: my_parent = Parent Parent.childs.set(new_child) session.save(Parent) # The childs index will be 1 --~--~-~--~~~---~--~~ 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 [EMAIL PROTECTED] For more options, visit this group at http://groups.google.com/group/sqlalchemy?hl=en -~--~~~~--~~--~--~---
[sqlalchemy] Overriding mapper relation
I have a customer table which has a 1-to-n relation with a phone table. The phone table has the following columns: integer id, string number, and boolean is_fax. Is there a way to override the phones collection so I can return a boolean if the customer contains at least 1 phone record with a is_fax set to True. For example: class Customer: pass class Phone: pass session.mapper(Customer, customers_table, properties={'phones':relation(Phone, backref='customers'}) my_customer = Customer.query.filter_by(id=1).first() # I want it to return True if at least one phone in the list has is_fax = True # so I'm thinking of somehow wrapping or overriding the python list class my_customer.phones.has_fax() --~--~-~--~~~---~--~~ 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 [EMAIL PROTECTED] For more options, visit this group at http://groups.google.com/group/sqlalchemy?hl=en -~--~~~~--~~--~--~---
[sqlalchemy] Using column_property for flagging purpose
I am having issues creating a read-only column using column_property. I have a phone table that has the columns: id, country_code, number, and deleted. I want to have an international column which will be set to True or False (or 1 or 0) depending on the value of the country_code. Provided below is the snippet of code to work with: phone_table = Table('phones', metadata, Column('id', Integer, primary_key=True), Column('country_code', String(5)), Column('number', String(20)), Column('deleted', Boolean, default=False), ) class Phone(object): pass # international gets set to True or None which isn't intended # also the session is from turbogears.database import session session.mapper(Phone, phone_table, properties={ 'international':column_property((phone_table.c.country_code=='1').label('international')) }) I'm not sure if this is a Turbogears issue or SQLAlchemy issue but the international field is always None when I do the following: I instantiate a Phone object, populate the attributes, session.save the instantiated Phone object, session.flush, and then query the new Phone object. --~--~-~--~~~---~--~~ 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 [EMAIL PROTECTED] For more options, visit this group at http://groups.google.com/group/sqlalchemy?hl=en -~--~~~~--~~--~--~---