Список внешних ключей экземпляра модели Django, теряющих согласованность при изменении состояния - PullRequest
3 голосов
/ 11 июня 2010

У меня есть модель, Match, с двумя внешними ключами:

class Match(model.Model):
   winner = models.ForeignKey(Player)
   loser = models.ForeignKey(Player)

Когда я повторяю цикл Match, я обнаруживаю, что каждый экземпляр модели использует уникальный объект для внешнего ключа. Это в конечном итоге кусает меня, потому что это вводит несогласованность, вот пример:

>>> 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
>>>

Я решил эту проблему так:

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

Мой вопрос: есть ли способ решить проблему более элегантно с помощью QuerySets без необходимости вызывать функцию сохранения в любой момент? Если нет, я бы хотел сделать решение более общим: как вы можете получить список внешних ключей для экземпляра модели или у вас есть лучшее общее решение для моей проблемы?

Пожалуйста, поправьте меня, если вы думаете, что я не понимаю, почему это происходит.

Ответы [ 4 ]

2 голосов
/ 01 ноября 2010

Это потому, что, насколько я могу судить, нет глобального кэша экземпляров модели, поэтому каждый запрос создает новые экземпляры, и ваши списки связанных объектов создаются лениво с использованием отдельных запросов.найдите, что select_related () достаточно умен, чтобы решить проблему в этом случае.Вместо кода вроде:

match = Match.objects.filter(...).get()

используйте:

match = Match.objects.select_related().filter(...).get()

Это создает все экземпляры атрибутов одновременно и может быть достаточно умным, чтобы повторно использовать экземпляры.В противном случае вам понадобится какой-то явный кеш (именно это и делает ваше решение).

Предупреждение: я сам удивлен таким поведением и не являюсь экспертом в этом.Я нашел этот пост во время поиска информации по этому вопросу в моем собственном коде.Я просто делюсь тем, что, как мне кажется, происходит, пытаясь понять ...

1 голос
/ 27 января 2011

Возможно, вы захотите проверить django-idmapper Он определяет SharedMemoryModel, так что в интерпретаторе есть только одна копия каждого экземпляра.

0 голосов
/ 27 января 2011

Я нашел хороший ответ на аналогичный вопрос, посмотрите здесь:

Модели Django: сохранить идентичность объекта по внешнему ключу, следуя

0 голосов
/ 11 июня 2010

Э-э, вы используете get_or_create () для записей игрока? Если нет, то вы, вероятно, создаете новые экземпляры идентичных (или почти идентичных) записей игрока в каждом матче. Это может привести к слезам и / или безумию.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...