List of Django model instance foreign keys losing consistency during state changes.
- by Joshua
I have model, Match, with two foreign keys:
class Match(model.Model):
winner = models.ForeignKey(Player)
loser = models.ForeignKey(Player)
When I loop over Match I find that each model instance uses a unique object for the foreign key. This ends up biting me because it introduces inconsistency, here is an example:
>>> def print_elo(match_list):
... for match in match_list:
... print match.winner.id, match.winner.elo
... print match.loser.id, match.loser.elo
...
>>> print_elo(teacher_match_list)
4 1192.0000000000
2 1192.0000000000
5 1208.0000000000
2 1192.0000000000
5 1208.0000000000
4 1192.0000000000
>>> teacher_match_list[0].winner.elo = 3000
>>> print_elo(teacher_match_list)
4 3000 # Object 4
2 1192.0000000000
5 1208.0000000000
2 1192.0000000000
5 1208.0000000000
4 1192.0000000000 # Object 4
>>>
I solved this problem like so:
def unify_refrences(match_list):
"""Makes each unique refrence to a model instance non-unique.
In cases where multiple model instances are being used django creates a new
object for each model instance, even if it that means creating the same
instance twice. If one of these objects has its state changed any other
object refrencing the same model instance will not be updated. This method
ensure that state changes are seen. It makes sure that variables which hold
objects pointing to the same model all hold the same object.
Visually this means that a list of [var1, var2] whose internals look like so:
var1 --> object1 --> model1
var2 --> object2 --> model1
Will result in the internals being changed so that:
var1 --> object1 --> model1
var2 ------^
"""
match_dict = {}
for match in match_list:
try:
match.winner = match_dict[match.winner.id]
except KeyError:
match_dict[match.winner.id] = match.winner
try:
match.loser = match_dict[match.loser.id]
except KeyError:
match_dict[match.loser.id] = match.loser
My question: Is there a way to solve the problem more elegantly through the use of QuerySets without needing to call save at any point? If not, I'd like to make the solution more generic: how can you get a list of the foreign keys on a model instance or do you have a better generic solution to my problem?
Please correct me if you think I don't understand why this is happening.