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.

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.

Reply via email to