On Feb 14, 2011, at 2:02 PM, Martijn Moeling wrote: > 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!!!!!!!!!
Yeah that's just not how "foreign keys" work in relational databases. A foreign key references one and only one table. What you're doing here is a rails-style polymophic association. You can use the code in examples/poly_assoc/poly_assoc.py, which doesn't use a "foreign key", but does the switching in Python code as to which table is joined using the tablename in the join condition. The recipe I gave you is nearly the same, it just adds one more table so that regular referential integrity can be used. > > # 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. > -- 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.