Django RelatedManager 的 .create() 用法?
Posted
技术标签:
【中文标题】Django RelatedManager 的 .create() 用法?【英文标题】:Django RelatedManager's .create() usage? 【发布时间】:2010-11-09 06:03:54 【问题描述】:我有两个模型:Play
和 PlayParticipant
,定义(部分)为:
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, '')
【问题讨论】:
【参考方案1】:我不明白您的第一个示例应该是一个错误吗?这种行为是完全直观的。您的 p 是一个 ID 为 2383 的 play,您正在调用其相关集的 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)
这是外壳输出:
>>> 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 频道。
【讨论】:
但他的帖子说:“我的一段代码有一个 id 为 2383 的 play p”。 @oggy:这是一个错字,已更正。抱歉 :-/ 你用的是什么版本的 Django? 在主干和 1.0.2 上测试,使用 sqlite3 后端。 我当时正在运行 Django 1.0.2 和 mysql 5.0.81...当我有机会时会自行重现,如果仍然可以重现,则提交错误报告。 感谢所有的帮助,奥吉 :)【参考方案2】:您应该在 Play 模型中使用与零个或多个参与者相关的 ManyToManyField。在该代码中,您将只是在做
play.players.add(player)
【讨论】:
嗯,不能,因为关系中有一个额外的字段 - 一个注释(更新的问题包括它)。示例等同于:djangoproject.com/documentation/models/m2m_intermediary 另外,我想弄清楚错误 是什么 而不是解决它(我使用 PlayParticipant.objects.create(...)) 【参考方案3】:这不是错误;检查documentation;特别是关于多对多关系的额外字段部分。它指定:
与普通的多对多字段不同,您不能使用
add
、create
或assignment
(即beatles.members = [...]
)来创建关系。创建这种类型关系的唯一方法是创建中间模型的实例。
【讨论】:
这不是多对多的关系,尤其是。不是带有属性的多对多,而是简单的一对多;该文档说明了具有属性的多对多关系的中间模型;您引用的部分与问题完全无关。【参考方案4】:我无法重现这种行为。使用类似的模型,我可以运行:
m = Manufacturer.objects.get(1)
p = m.product_set.create(name='23',category_id=1,price=23,delivery_cost=2)
我得到Product
的新实例p
,其p.manufacturer
外键等于m
。
这是在带有 PostgreSQL 的 Django-1.0.2 上;您使用哪个版本的 Django,以及哪个 SQL 后端?
尝试在其中一个上使用两个带有 ForeignKey 字段的新最小模型,这应该可以;然后使这些模型逐渐接近表现出失败行为的模型。通过这种方式,您可以隔离导致其行为不端的单个更改;这种变化是原因的关键。
【讨论】:
以上是关于Django RelatedManager 的 .create() 用法?的主要内容,如果未能解决你的问题,请参考以下文章
Django RelatedManager 的 .create() 用法?
django ORM中的RelatedManager(关联管理器)