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.

Reply via email to