Michael, I have implemented your example into my code and although it sort of works, It does not fit into the whole system as expected, somehow I think it is way to complex for what I want. It should be much more simple....
In the basis I want a class Extra, in this example I'll use queries to define/explain the relationships Class User(Base): This class is global and loaded Id = 0 groups = [] Me = User(Id=5, Groups = [1,2,3,6]) class Extra(Base): __tablename__ = 'Extra' Id = Column(Integer, primary_key=True) # this is only to identify the EXTRA record Table = Column(Unicode(20)) TableId = Column(Integer) #ForeignKey to self.Table+'.Id' !!!!!!THIS IS MY REAL PROBLEM!!!!!!!!! # can @validates help out? I do not understand the use very well. OwnerID = Column(Integer, ForeignKey('UsersAndGroup.Id')) SomeRecord = Session.Query('self.Table').filter(str(self.Table.Id)+' == '+str(Self.TableId)).one() (Or this be a backref, seems even better) Read = Column(Boolean) Write = Column(Boolean) ....... = Column(what_ever_type) Class ExtraProperties(object): @declared_attr __table_args__(self): return (ForeignKeyConstaint(['Id',self.__tablename__],['Extra.TableId','Extra.Table']),{}) def Extras(self, Me) should be @declared_attr, # Not sure how to handle the reference to Me...... yet def Extras(self), return relation........ The Query..... return Session.query(Extra).filter( and_( Extra.Table == self.__tablename__, Extra.Id == self.Id, in_(Extra.OwnerId, Me.groups.append(Me.Id)) , Extra.Read==True).all() # in this case [1,2,3,6,5] , This can be done in the MapperExtension before_append def __del__(self) session.delete(Extra).filter( and_( Extra.Table == self.__tablename__, Extra.TableId == self.Id) # defines the cascade for deletion.... nothing more ,just Every Extra to this record Class SomeTable(Base, ExtraProperties) __tablename__ = 'SomeTable' Id = Column(Integer, primary_key=True) I have tried doing this but can not seem to set the relationship right. If manage to get the relation not to moan about determing primarykeys, I get NULL Identity errors on flush() in the commit.... The SomeTable could be a polymorphic inheritance or any basic table. As you might remember I even tried this with MapperExtension in the before_append and before_insert etc. but then I run into instance of <whatever> is deleted..... amongst others I might be on the wrong foot but spending 7 days to get such a stupid thing ..... It should not be hard. I could very well make wrapper functions for the Queries, but that does not help with Integrity of Extra records.... I want them to be deleted on SomeClass deletion... I still like the MapperExtrention approach where I can pythonically check the Extras.Read etc. SomeClass being Polymorphic or not does not seem to be relevant..... Martijn On Feb 14, 2011, at 14:04 , Martijn Moeling wrote: > Eric (and Michael), > > Thank you for your comments, I agree with you totally. > I am not much of a database guy and never have been. > During my education I did not pay much attention to those > lessons either, I was just interested in positive grades. > > I dropped the database stuff as quickly as possible and concentrated on > (OS) kernel and protocol related technologies. > > The case I am working on now requires a very (To me) complex datamodel with > complex relations. > Right now I have multiple polymorphic classes with both self reference and > references to each other. > Those references are polymorphic too!! > Now I had to make a class which had to reference all of the above with the > right cascading integrity. > To be honest this turned out way over my head not in the first place because > the SQLAlchemy learning > curve gets steeper and steeper when technologies have to be mixed to get > stuff working. > Me being not really interested in Databases during the first 33 years of my > experience in software development > is certainly a drawback in terms of understanding the SQLAlchemy > documentation. > If I do not know what a AssociationProxy is, I do not search for it but what > If I need it to get my problem out of the way? > > Michael has been a great help and I have been looking over this mailing list > to help him out answering the "simple" questions. > It turned out not that easy and I need a lot more knowledge about the > SQLALchemy internals. > > I have been an Open Source guy for a very long time and did work on many > things, I still remember the good old Linux-Kernel days and (although I am > the only user) I have made an adapter for running MOD_PYTHON code on top of > MOD_WSGI (as an alternative MP package). It is running my production code > made for MP on top of MOD_WSGI very well.... I personally like the way of > "the Request" object. > > If I can contribute to SA I will be happy to do so, I have the feeling I have > lightened up something which could be improved. That is a first step... (not > a big one :-) > > I have the feeling that SA is mainly a "German" project. Although I get > confused by the "working" hours of Michael, He never responded to my question > if he ever sleeps....... > The German names of people seem to make me think that, I am not sure though. > > German product turn out be be great and I love Germany for many reasons (I > even Worked in Germany). If I cannot afford a German made car, I'll walk!! > > as I said I am thinking about contributing in some manner to pay back for > being able to use SA and for the great help the users get from Michael and > others. > > > > > > > > > > On Feb 14, 2011, at 05:11 , Eric Ongerth wrote: > >> Polymorphic associations pop up a lot around here, don't they! I >> suppose it's partly because they would be so much more difficult to >> handle, or even come close to handling, conveniently, with most other >> ORM packages. >> >> Martijn, after running into the wall on polymorphic associations >> approximately once a year since Michael wrote that blog article, I >> finally got it all straight in my mind, and I realized there are two >> fundamental tricks to seeing the PA phenomenon clearly. One is learn >> to sense when it's around; it's almost like a certain smell in your >> code. There is a particular feeling that distinguishes it from other >> data modeling problems. Two, when you notice a polymorphic >> association pattern beginning to appear, attempt to think about the >> relations involved in the exact reverse direction. This sounds too >> trivial to be a real piece of advice, but it works every time for me. >> Each time I perceive a problem with a polymorphic association but then >> I reverse my perspective, the perceived problem vanishes. >> >> I could probably do just as well by binding a rug around my head or >> something, but that's just me. And I'm not going to find out. >> >> - Eric >> >> >> On Feb 13, 1:57 pm, Michael Bayer <mike...@zzzcomputing.com> wrote: >>> a polymorphic association is hard. that's why I have three examples of >>> them and soon a fourth. Though they are a subset of a larger batch of >>> "tricks" that I've been using in my own work with declarative for the past >>> year to automate lots of different kinds of patterns, perhaps there's a >>> learning curve but once three or four techniques are mastered they come >>> pretty easily. >>> >>> On Feb 13, 2011, at 4:35 PM, Martijn Moeling wrote: >>> >>>> Michael, >>> >>>> I looked at the code and I can not say more than that its very >>>> interesting, I have to see how it works and more importantly how It fits >>>> into my objects but it seems clear enough to do so. >>>> I really appreciate your work on SQLAlchemy and all the time you spend to >>>> help us "users" out. >>> >>>> Your solution is definitively one I could not have put together myself. >>>> Although I have tried. SQLAlchemy is so powerful that it is hard to find >>>> "the right options" for the job. >>> >>>> Thank you again! >>> >>>> Martijn >>> >>>> On Feb 13, 2011, at 21:19 , Michael Bayer wrote: >>> >>>>> On Feb 13, 2011, at 6:14 AM, Martijn Moeling wrote: >>> >>>>>> You are right in the misunderstood relation. >>> >>>>>> I see the primary key in extra to be wrong, extra should have it's own >>>>>> I'd column being an auto number. In extra it should be possible to have >>>>>> many records pointing to 1 ext variant. Sorry for that. >>> >>>>>> The extra, should also work with tables without a discriminator, there >>>>>> the link should be made to table name which is in my case always >>>>>> class.__name__ ...... On those tables, the relation needs to be >>>>>> different since on of the "local" columns, discriminator is not present >>>>>> and it somehow should be linked to __table name__ >>> >>>>> OK what you are trying to do is exactly a "polymorphic association". >>>>> The technique of placing "tablename" in the table of "related" records, >>>>> then using that "tablename" to indicate which parent table should be >>>>> matched at query time, is a common, but IMHO relationally incorrect >>>>> pattern. I blogged extensively about the Ruby on Rails approach, how to >>>>> duplicate Rails' approach in SQLAlchemy, and then an alternate system >>>>> which maintains referential integrity, four years ago >>>>> athttp://techspot.zzzeek.org/2007/05/29/polymorphic-associations-with-s.... >>> >>>>> That's a really old example and we're into 0.7 now, so I've created a new >>>>> version of the poly assoc example that uses declarative techniques and >>>>> the association proxy, which is attached. I'm going to further fix up >>>>> this example and add it to the distribution as a fourth example of >>>>> polymorphic association, which is in examples/poly_assoc/. >>> >>>>> Additionally I'd like the association proxy to work more smoothly in >>>>> queries so I've added ticket #2054 for some of those issues which weren't >>>>> accounted for when we first added any(), contains() operators to the >>>>> association proxy. >>> >>>>>> It is all part of the ACL examples it talked about walker, where extra >>>>>> must be seen as the ACL. That is where the mapper extension comes in.... >>> >>>>>> It is getting a "all technologies" mixed in situation >>> >>>>>> Verstuurd vanaf mijn iPad >>> >>>>>> Op Feb 12, 2011 om 17:05 heeft "Michael Bayer" >>>>>> <mike...@zzzcomputing.com> het volgende geschreven: >>> >>>>>>> OK I can show you the version of your code that does most of this but >>>>>>> there are some fundamental relational misunderstandings in this schema >>>>>>> if I am interpreting correctly. >>> >>>>>>> Extra: >>> >>>>>>> tableid tablename >>>>>>> ------- --------- >>>>>>> 1 ext1 >>>>>>> 2 ext1 >>>>>>> 3 ext2 >>>>>>> 4 ext2 >>>>>>> 5 ext3 >>> >>>>>>> ext1: >>> >>>>>>> id discriminator (-> FK to Extra.tableid, Extra.tablename) >>>>>>> -- ------------- >>>>>>> 1 ext1 >>>>>>> 2 ext1 >>>>>>> 3 ext2 >>>>>>> 4 ext2 >>>>>>> 5 ext3 >>> >>>>>>> ext2: >>> >>>>>>> id >>>>>>> -- >>>>>>> 3 >>>>>>> 4 >>> >>>>>>> ext3: >>> >>>>>>> id >>>>>>> -- >>> >>>>>>> 5 >>> >>>>>>> given ext1 ID #3, discriminator "ext2" - how can more than one Extra >>>>>>> row be referenced? Why is "extras" assumed to be one-to-many when it >>>>>>> can only be many-to-one ? >>> >>>>>>> On Feb 12, 2011, at 9:57 AM, Martijn Moeling wrote: >>> >>>>>>>> This whole thing is driving me crazy, What I want: >>> >>>>>>>> class Extra(Base): >>>>>>>> __tablename__ = "extra" >>>>>>>> # Primary key consists of two different columns !!! >>>>>>>> tableId = Column(Integer, primary_key=true) >>>>>>>> tablename = Column(Unicode(20), primary_key=True) >>> >>>>>>>> info = Column(........) #Not relevant >>> >>>>>>>> class ex1(Base): >>>>>>>> Id = Column(Integer, primary_key=True) >>>>>>>> discriminator = Column(Unicode(20)) >>> >>>>>>>> @declared_attr >>>>>>>> def __tablename__(self): >>>>>>>> return self.__name__.lower() >>> >>>>>>>> @declared_attr >>>>>>>> def __mapper_args__(self): >>>>>>>> if self.__name__ == 'ext1': >>>>>>>> return {'polymorphic_on': self.discriminator, >>>>>>>> 'polymorphic_identity':unicode(self.__name__.lower()), >>>>>>>> 'extension': FilePropertiesMapperExtension(), >>>>>>>> 'batch' : False} >>>>>>>> else: >>>>>>>> return {'polymorphic_identity':unicode(self.__name__.lower()), >>>>>>>> 'inherit_condition': self.Id == extra.Id, >>>>>>>> #needed for something else in this config (multiple self >>>>>>>> reference) >>>>>>>> 'extension': FilePropertiesMapperExtension(), >>>>>>>> #Needed for something else, not relevant for this sample >>>>>>>> 'batch' : False} >>>>>>>> # ,, ,, ,, ,, >>> >>>>>>>> # Set up foreignkey and relation to Extra.... >>>>>>>> __table_args__ = (ForeignKeyConstraint(['discriminator', 'Id'], >>>>>>>> ['extra.Table','extra.TableId']),{}) >>> >>>>>>>> extras = relation('Extra', cascade="all", >>>>>>>> lazy="dynamic" backref="owner") >>> >>>>>>>> .... >>>>>>>> .... >>> >>>>>>>> class ext2(ext1): >>>>>>>> Id = Column(Integer,ForeignKey('ext1.Id'), >>>>>>>> primary_key=True) >>>>>>>> ...... >>> >>>>>>>> class ext3(ext1): >>>>>>>> Id = Column(Integer,ForeignKey('ext1.Id'), >>>>>>>> primary_key=True) >>>>>>>> ..... >>> >>>>>>>> Now I want: >>> >>>>>>>> Ext2 = ext2() >>>>>>>> Extra_info = extra() >>>>>>>> Ext2.extras.append(Extra_Info) >>> >>>>>>>> Ext2.discriminator should be "ext2" >>>>>>>> Ext2.Id should be 1 for the first record >>> >>>>>>>> Extra_Info should be created in the database, with its columns : id >>>>>>>> set to the Ext2.id and tablename to Ext.discriminator ...... >>>>>>>> Extra_Info.owner would point to Ext2 >>> >>>>>>>> If Ext2 is deleted, all related extrainfo record would be delete too >>> >>>>>>>> if one Extra_Info is deleted, Extra_Info.owner should stay in place as >>>>>>>> well as all other related >>> >>>>>>>> Extra is many to one polymorhic version of ext1 >>> >>>>>>>> I hope this clarifies more what I want.... >>> >>>>>>>> I really need the @declared_attr way of doing stuff and that is not >>>>>>>> related to this question but might influence this question so I left >>>>>>>> it in...... >>> >>>>>>>> Martijn >>> >>>>>>>> On Feb 10, 2011, at 18:13 , Michael Bayer wrote: >>> >>>>>>>>> On Feb 10, 2011, at 4:20 AM, Martijn Moeling wrote: >>> >>>>>>>>>> Another small thing: >>> >>>>>>>>>> I took a look at: >>> >>>>>>>>>> ForeignKeyConstraint(['invoice_id', 'ref_num'], >>>>>>>>>> ['invoice.invoice_id', 'invoice.ref_num']) >>> >>>>>>>>>> Now for Polymorphic tables: >>> >>>>>>>>>> in baseclass: >>> >>>>>>>>>> baseclass.discriminator happens to be the __tablename__ of the >>>>>>>>>> polymorphic >>> >>>>>>>>>> ForeignKeyConstraint('['baseclass.disciminator', baseclass.Id'], >>>>>>>>>> ['someotherclass.tablename','someotherclass.tableId'] >>>>>>>>>> relationship('someotherclass', backref=baseclass, cascade="all", >>>>>>>>>> lazy="dynamic") >>> >>>>>>>>>> in someotheclass: >>> >>>>>>>>>> tablename = column(Unicode(20), primary_key=True) >>>>>>>>>> tableId = column(Integer, primary_key=True) >>> >>>>>>>>>> seems Ok to me. >>> >>>>>>>>>> Now I need to make someotherclass work with non-polymorphic tables >>>>>>>>>> too!! >>> >>>>>>>>>> anotherclass: >>>>>>>>>> Id = column(Integer, primary_key=True) >>>>>>>>>> ForeignKeyConstaint('[anotherclass.__tablename__,'anotherclass.Id'],['someotherclass.tablename','someotherclass.tableId']) >>>>>>>>>> relation('someotherclass', backref=baseclass, cascade="all", >>>>>>>>>> lazy="dynamic") >>> >>>>>>>>>> Is there any way to get this working without configuring it as >>>>>>>>>> polymorphic an do no Inhiritance, I do not want each anotherclass >>>>>>>>>> record to have a column discriminator with its own tablename! >>> >>>>>>>>>> or can I use anotherclass.__tablename__ in the ForeignKeyConstaint? >>> >>>>>>>>>> This has to do with the someotherclass being the "ACL" I talked >>>>>>>>>> about in a previous post if that gives extra info. I am trying to >>>>>>>>>> implement the MapperExtension.before_append where I need to refer to >>>>>>>>>> the "ACL" records in a way like: >>> >>>>>>>>>> for A in instance.ACL: >>>>>>>>>> ..... >>> >>>>>>>>> yeah, sorry, this use case continues to be 98% opaque to me. I >>>>>>>>> don't understand what you mean by "make someotherclass work with >>>>>>>>> non-polymorphic tables", a class is mapped in just one way, either >>>>>>>>> with or without a discriminator column. A single class can't be >>>>>>>>> mapped in both ways. If there's no discriminator, there's just one >>>>>>>>> class that can be used for returned rows. >>> >>>>>>>>> If you could create a small test that illustrates a mapping and an >>>>>>>>> expected result, perhaps I can attempt to find a way to get the ORM >>>>>>>>> behavior you're looking for. >>> >>>>>>>>> Your mapper extension would continue to be used normally with a >>>>>>>>> "dynamic" relationship since it uses query(cls) just like a regular >>>>>>>>> query. >>> >>>>>>>>> -- >>>>>>>>> You received this message because you are subscribed to the Google >>>>>>>>> Groups "sqlalchemy" >>> >>> ... >>> >>> read more ยป >> >> -- >> 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. >> > > -- > 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. > -- 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.