On Thu, May 16, 2019 at 9:22 AM Marcel Zoll <[email protected]> wrote: >> >> >> it's the "functional at each level" part that I think goes beyond what >> is practical. When you run an operation on a superclass, and it >> expects to do ORM operations, it has to be referring to the ultimate >> mapped class. The ORM is designed with the idea that the concrete >> instantiation classes are the ones that are ultimately mapped and >> dealt with in terms of persistence. > > > Okay, that is something that I get. However, if you extend the baseclass > strictly hierarchical and only make one concrete class for each derived level > that you want to operate at (lets say each level isolated in a package), the > notion of an 'ultimate' derived class should be well defined, and so should > be programming-technically resolvable (So i understand sqlalchemy already > does some class-inspections under the hood, even though I do not know by > which mechanics that is governed): > I mean something like this (\/ and > should mean 'derives to'): > > --- level 0 --- > Base > \/ > OBJ01_Declared_lvl0 > OBJ01_Mapped_lvl0 > > --- level A --- > \/ > OBJ01_Extended_lvlA > OBJ01_Mapped_lvlA > > --- level B --- > \/ > OBJ01_Extended_lvlB > OBJ01_Mapped_lvlB > > > >> It should be apparent that it >> would be vastly more complicated to make it also "know" about all >> kinds of arbitrary subclasses. > > > You are correct, that from one derived concrete class knowing the identity of > another other derived concrete class of the object it should relate to > (relationship(<>)) is hard, and cannot be defined at the baseclass level > (possibly where you declare the table) alone. However, I also saw that > relationships can be specified by either giving the class of the to be > related to object or by its class-name (a string). As this name needs to be > resolved to some object at some point by inspection of the namespace (or > brute forcing it), cant this resolving not be delayed until this very > relationship is used? > A way to potentially resolve this could be that you would kind of use a > 'derived_level_Mixin' that you assign to all Mapped classes at each level; so > inspecting for this trait in your querying class and the class to be resulted > should make things uniquely identifiable. > > My Ideal solution would look so that all mapped would actually go by the same > class-name, however, by being in different modules they fully-qualified names > should still be unique. This would make it more convenient to use, as the > classes follow the same basic-interface, while the highest derived class in > the highest level package provides most functionality > > --- script1.py --- > from myproj_lvlA import Source > ... > session.add(Source('MySource')) > session.commit() > s = session.query(Source).first() > print(Source) > > --- script2.py --- > > from myproj_lvlB import Source #<< import from higher level module > ... > session.add(Source('MySource')) > session.commit() > s = session.query(Source).first() > print(Source) > s.move_to_loc_by_name('MyLocation') #<< functionality only accessible at > myprojB > > > >> >> How would you propose the identity >> map issue I illustrated before function? That is, if i query for >> Class_lvlA and later for Class_lvlB, what identity key should they >> have? If you say they should have the same identity key, what if >> both Class_lvlA and Class_lvlB perform an operation against the same >> Session - there is only one Class_<xyz> object in the identity map, >> suppose it is Class_lvlA, now Class_lvlB consults for its own class >> and gets the wrong answer. If you propose they should have >> individual identity keys, then how do these two classes consult for >> the same row in the identity map? > > > You are correct, that a session should not be expected to handle objects of > different level (Class_lvlA & Class_lvlB) at the same time, as this could > potentially lead to conflicts, also as I understand it is not allowed to map > the same table to multiple different, inherently distinct, classes at the > same time (which i think is good). I am not > > >> >> I appreciate that you are >> going for some particular level of purity in your design, however I >> believe there is some conflation here of separation of concerns vs. >> concrete instantiation patterns. > > > Yesterday, I found out some interesting properties, that one can make > declarations which use the sqlalchemy-metadata and declarative base, but > without visiting/importing the module in question this code is not actually > executed, resp. the definitions are not actually added to the metadata or the > mappers. It might be possible to exploit this to make a construct as depicted > above happen (i.e. not visiting/importing the modules declaring mappers for > all mapped classes below the current level). I am not sure if this will not > eventually violate some rules of good programming practice... > > Thanks Marcel >
I very much doubt you are going to find a way to get SQLAlchemy to do what you want automatically. I think you might be better off writing your classes *without* SQLAlchemy, and then have a separate mechanism that uses SA's classical mapping tools (https://docs.sqlalchemy.org/en/13/orm/mapping_styles.html#classical-mapping) to map them. You can inspect the classes and traverse the hierarchy in whatever way makes sense to you. Simon -- SQLAlchemy - The Python SQL Toolkit and Object Relational Mapper http://www.sqlalchemy.org/ To post example code, please provide an MCVE: Minimal, Complete, and Verifiable Example. See http://stackoverflow.com/help/mcve for a full description. --- You received this message because you are subscribed to the Google Groups "sqlalchemy" group. To unsubscribe from this group and stop receiving emails from it, send an email to [email protected]. To post to this group, send email to [email protected]. Visit this group at https://groups.google.com/group/sqlalchemy. To view this discussion on the web visit https://groups.google.com/d/msgid/sqlalchemy/CAFHwexeb9-1kvF1vGVt2Q31cjpmFkTGpBDst3drMnVq7zCV5gg%40mail.gmail.com. For more options, visit https://groups.google.com/d/optout.
