Использование Django RelatedManager .create ()? - PullRequest
2 голосов
/ 09 июля 2009

У меня есть две модели: Play и PlayParticipant, определенные (частично) как:

class PlayParticipant(models.Model):
    player = models.ForeignKey('Player')
    play = models.ForeignKey('Play')
    note = models.CharField(max_length=100, blank=True)

Часть моего кода имеет игру p с идентификатором 8581, и я хотел бы добавить к ней участников. Я пытаюсь использовать RelatedManager .create() для этого, например:

p.playparticipant_set.create(player_id=2383)

Из чего Джанго строит:

INSERT INTO `api_playparticipant` (`player_id`, `play_id`, `note`) VALUES (2383, 2383, '')

Это ошибка в Django, или я неправильно использую .create()?

Копирование-вставка оболочки для проверки работоспособности:

In [17]: p = Play.objects.get(id=8581)

In [18]: p.id
Out[18]: 8581L

In [19]: p.playparticipant_set.create(player_id=2383)
...
IntegrityError: (1452, 'Cannot add or update a child row: a foreign key constraint fails (`gc/api_playparticipant`, CONSTRAINT `play_id_refs_id_60804ffd462e0029` FOREIGN KEY (`play_id`) REFERENCES `api_play` (`id`))')

Из query.log:

5572 Query       INSERT INTO `api_playparticipant` (`player_id`, `play_id`, `note`) VALUES (2383, 2383, '')

Ответы [ 4 ]

3 голосов
/ 15 июля 2009

Я не понимаю, как ваш первый пример должен быть ошибкой? Такое поведение полностью интуитивно понятно. Ваш p - это play с идентификатором 2383, и вы вызываете метод create для его связанного набора. Вы также указываете дополнительное поле с именем player_id и присваивает ему значение 2383. Логично, что оба идентификатора игры будут 2383 (потому что это идентификатор игры, содержащей этот связанный набор) и этот идентификатор игрока также будет 2383 (потому что вы явно передали это значение в).

Ваш второй пример может показывать ошибку, но я не могу ее воспроизвести. Вот мои модели:

class Player(models.Model):
    name = models.CharField(max_length=100)

class Play(models.Model):
    title = models.CharField(max_length=100)

class PlayParticipant(models.Model):
    player = models.ForeignKey('Player')
    play = models.ForeignKey('Play')
    note = models.CharField(max_length=100, blank=True)

Вот вывод оболочки:

>>> player1 = Player.objects.create()
>>> player2 = Player.objects.create()
>>> player1.id
2
>>> player2.id
3
>>> play1 = Play.objects.create()
>>> play2 = Play.objects.create()
>>> play1.id
3
>>> play2.id
4
>>> pp1 = play1.playparticipant_set.create(player_id=2)
>>> pp1.play.id
3
>>> pp1.player.id
2

В любом случае, почему вы отправляете это в SO? У Django есть багтрекер, пара активных официальных списков рассылки и пара каналов IRC.

1 голос
/ 09 июля 2009

Вы должны использовать ManyToManyField в модели Play, которая относится к нулю или большему количеству участников. В этом коде вы просто делаете

play.players.add(player)
0 голосов
/ 18 июля 2009

Я не могу воспроизвести это поведение. С аналогичными моделями я могу запустить:

m = Manufacturer.objects.get(1)
p = m.product_set.create(name='23',category_id=1,price=23,delivery_cost=2)

и я получаю новый экземпляр p из Product, чей p.manufacturer внешний ключ равен m.

Это на Django-1.0.2 с PostgreSQL; какую версию Django вы используете и какой SQL-бэкэнд?

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

0 голосов
/ 15 июля 2009

Это не ошибка; проверьте документацию ; в частности, раздел Дополнительные поля для отношений "многие ко многим" . Указывает:

В отличие от обычных полей «многие ко многим», вы не можете использовать add, create или assignment (т. Е. beatles.members = [...]) для создания отношений.

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

...