On Nov 8, 2017 1:09 PM, "Sven" <sven.du...@gmail.com> wrote:
Thank you for your answer. It is always very complete and interesting. *"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 .... :) )"* The solution with the set works with the specific code sample I gave but what about the other possible situations (when having a set is not possible) ? I think that I will possibly meet very different type of situations and I was more interested to know what would be the good way to proceed in general, not in particular cases. *"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."* Sorry, that was not what I meant. Until now, each object in memory in the program is stored with Pickle. Let's take an example : In my program, each instance of the class "Room" contains the list of the players located in this particular Room. But each instance of the class "Player" also contains the room where the player is. Here is a code to illustrate : class Player(): def __init__(self, name): self.name = name self.room = None def set_room(self, room): self.room = room def __repr__(self): return self.name class Room(): def __init__(self, name): self.name = name self.players = [] def add_player(self, player): self.players.append(player) def __repr__(self): return self.name room1 = Room("room1") player1 = Player("player1") player2 = Player("player2") # The room is stored in the player instances : player1.set_room(room1) player2.set_room(room1) # And the players are also stored in the room instance : room1.add_player(player1) room1.add_player(player2) print(room1.players) print(player1.room) print(player2.room) Result : >>> [player1, player2] room1 room1 >>> And I have this kind of relationships almost everywhere. For now, these objects are stored with Pickle. With Pickle, the relationships between classes doesn't matter. It just store the objects in a file as they are and Unpickle allow us to retrieve everything with just a few lines of code. But now, we are trying to change the save system and to use only SQLAlchemy. And I don't know exactly how I am supposed to configure my relationships because if backref or back_populates are used, the statement "player1.set_room(room1)" will populate room1.players and player1.room immediately. And the statement "room1.add_player(player1)" will do the same thing and I will have duplicates. Of course, in this specific example, I could use a set, but it's just a way to illustrate the problem that I will meet multiple times in different situations and with different collections. How many collection types do you have? All of the collections used by relationship () can support deduplication. Using a list class with an idempotent append() method is not a big deal. If python had better collection classes like native ordered sets that act like lists we'd probably not use list at all anymore. In this specific example, I could also just delete one of the statement, but : - the two statements are sometimes in different classes and different files. Is it not dirty to decide that one of the statements will be deleted, letting the other do all the work and populate the two attributes ? - it could be a lot of work because for most of relationships, I will have to determine where these statements are, why and when there are used, and think of a cleaner way to organize my code according to SQLAlchemy principles (just one modification start automatically the modification of the linked attribute in the other side). And there is a lot of classes... I think you are right with the fact that it would be maybe too complicated and a bit useless to use SQLAlchemy and still try to keep the model absolutly separated and independant from it. *"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."* So, I suppose that it is probably a bad idea to avoid to use backref and back_populates if it is not a well-traveled use case and if there can be some conflicts in many-to-many relations. So, the cleaner way to proceed would be to adapt all the classes and always keep only one modification statement per bidirectional relationship ? -- 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 sqlalchemy+unsubscr...@googlegroups.com. To post to this group, send email to sqlalchemy@googlegroups.com. 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 sqlalchemy+unsubscr...@googlegroups.com. To post to this group, send email to sqlalchemy@googlegroups.com. Visit this group at https://groups.google.com/group/sqlalchemy. For more options, visit https://groups.google.com/d/optout.