On Wed, Nov 8, 2017 at 5:05 AM, Sven <[email protected]> wrote: > Hello, > > I am actually working on my previous post about the OrderedDict and the None > values and I met new problems and new questions. I didn't found answers on > the Internet, so here I am ! > > As explained in the official documentation (or in the following topic : > https://groups.google.com/forum/#!msg/sqlalchemy/2dVQTvzmi84/8J8lGpLfw4EJ), > using backref or back_populates on relationship "sets up the > "synchronization" of the two directions, which consists of an event that > performs the complimentary set/append operation when an append/set occurs on > the other side". > > Here is the example gived by the topic previously mentionned : > > p = Parent('parent1') > c = Child('child1') > c.parent = p > p.children.append(c) > > > p's children will contain c twice. > > In deed, the "c.parent = p" operation results in the "append" on the other > side, and vice versa.
so the super-duper best way to fix for the above use case, if possible, would be to use collection_class=set rather than list. sets are all around better for relationship() and if I was writing SQLAlchemy today this would have been the default (back in python 2.3, sets were kind of an exotic feature .... :) ) > > In my case, I'm working on an existing project which contains a lot of > classes and the methods are already designed in order to add the objects on > the two sides. It is so because the program is using Pickle to persist > everything (my objectiv is to replace it by SQLAlchemy). Are you seeing objects that are being unpickled, and then are firing off SQLAlchemy events such that collections are being populated twice? That's not supposed to happen. Backrefs don't get in the way of normal pickling / unpickling of collections and attributes, that's how major functionality like the whole dogpile.cache example work. Otherwise, I'm not sure how pickling relates to the above code sample where ".append()" is being explicitly called. Of course, I could > adapt the code but it will be a lot of work and I don't like the idea that > my structures are automatically synchronized without explicit declarations. backref/back_populates are explicit declarations :) > Furthermore, what will happen if I decide, one day, to stop using SQLAlchemy > ? My code would be too dependent on the fonctionnalities provided by > SQLAlchemy. if you are using the ORM, then you're buying into the class-state management solution provided by the ORM as well. There are hooks to entirely replace this state management system with your own system, but building out on that while trying to make your class models completely agnostic of the fact that something has given them new attributes and features would be difficult (see http://docs.sqlalchemy.org/en/latest/_modules/examples/custom_attributes/custom_management.html for an illustration of these systems). The idea that an application model can be developed against an ORM and then be completely swapped out to not use an ORM without alterations to the usage of the model has long been a popular ideal but I don't think it has ever played out in practice. ORMs in all languages apply a lot of assumptions to a model, and in Python, this is even more prevalent since Python allows for all the great metaprogramming features which mean you aren't having to write getter/setters across all your models, among other things. If you truly are trying to build out an easy stepping stone out of ORMs later on, there are two design patterns that come to mind. One is that you don't change your model at all, and you instead create an entirely separate model that represents your database mapping. A mediation layer then transfers state between your "default" model and the ORM-enabled model. FWIW a large swath of Openstack, which I get paid to work on, works sort of this way. it's a common pattern that there is some kind of public-facing "API" model, e.g. the one that gets converted into JSON and such for services, and the internal "business" model that knows how to be persisted and is more application-specific. The other pattern is to not use the ORM and just use Core. This is also a very popular pattern, and a big reason SQLAlchemy Core exists is specifically to allow all of SQLAlchemy's great database features to be available to projects that aren't comfortable wiring the whole object model to SQLAlchemy, or projects that don't really use an OO-style object model in the first place. > > So, my questions are : > > 1) Is it feasible to avoid to use backref or back_populates ? Would it be a > bad idea to work without these fonctionnalities ? Will I face for example > inconsistent state of the program ? You can go this road for one-to-many and many-to-one although this is not a well-traveled use case. For a many-to-many with "secondary", there can still be some conflicts because the unit of work uses "backref" to look at the fact that the two sides represent the same collection to resolve duplicate events that occur on both sides. > 2) Is it possible to use back_populates and allow SQLAlchemy to detect that > it should not append something which was already inserted ? using collection_class=set is by far the easiest way to do this. > > > Thank you very much ! > > Regards, > > Sven > > > -- > 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. > For more options, visit https://groups.google.com/d/optout. -- 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. For more options, visit https://groups.google.com/d/optout.
