Django RelatedManager的.create()用法?

时间:2009-07-09 02:51:56

标签: django orm django-models django-orm

我有两个模型:PlayPlayParticipant,定义为(部分):

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

我的一段代码有一个游戏p,其ID为8581,我想添加参与者。我正在尝试使用RelatedManager的.create()来执行此操作,例如:

p.playparticipant_set.create(player_id=2383)

Django从中构建:

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

这是Django中的错误,还是我误用了.create()

复制粘贴shell以进行健全性检查:

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 个答案:

答案 0 :(得分:3)

我不知道你的第一个例子怎么会是一个bug?这种行为是完全直观的。您的p是播放,ID为2383,您在其相关集上调用create方法。你还指定了一个名为 player_id 的额外字段,并给它一个2383的值。两个播放id都是2383(因为这是包含这个相关集的播放的id)是合乎逻辑的。并且该玩家ID也将是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)

这是shell输出:

>>> 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有一个bugtracker,一些活跃的官方邮件列表和几个IRC频道。

答案 1 :(得分:1)

您应该在Play模型中使用与零个或多个参与者相关的ManyToManyField。在那段代码中你只是在做

play.players.add(player)

答案 2 :(得分:0)

这不是一个错误;检查documentation;特别是关于多对多关系的额外字段的部分。它指定:

  

与普通的多对多字段不同,您无法使用addcreateassignment(即beatles.members = [...])来创建关系。

     

创建此类关系的唯一方法是创建中间模型的实例。

答案 3 :(得分:0)

我无法重现那种行为。使用类似的模型,我可以运行:

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

这是在带有PostgreSQL的Django-1.0.2上;你使用哪个版本的Django,以及哪个SQL后端?

尝试在其中一个上使用两个带有ForeignKey字段的新的最小模型,这应该可行;然后使这些模型逐渐接近表现出失败行为的模型。通过这种方式,您可以隔离使其行为不端的单一变更;这种变化是关键所在。