【发布时间】:2013-12-27 20:01:05
【问题描述】:
我在 2 个模型之间有一个 Django 1.5 一对多关系。它看起来像这样
class Team(models.Model):
class Meta:
league = models.ForeignKey(League,related_name="teams")
...
class League(models.Model):
...
每个联赛可以有一支或多支球队。我正在响应联赛相关 URL 上的 POST 请求,并且正在创建(或更新)联赛。只能通过联赛间接创建团队(即不支持团队的 POST),并且每个团队都必须有一个联赛。但是我无法让它正常工作。
在LeagueSerializer 中,我已覆盖from_native 并在那里解析json(我没有TeamSerializer)。当 full_clean() 出现验证错误时,我返回 None(来自 from_native())。在我看来,在调用LeagueSerializer.is_valid() 之后,我会检查LeagueSerializer.object 是否不是None,如果不是,我会调用LeagueSerializer.save()。当我不改变联赛中的球队时,这似乎很有效。这是来自views.py 的 sn-p(应 TankorSmash 的要求)
def league_submit(request):
if request.method == 'POST':
#pass the incoming post data to league serializer
serializer = LeagueSerializer(data=request.body)
if serializer.is_valid():
if serializer.object is None:
print "something went awry in from_native. invalid/bad data in post"
else:
print "things seemed to have been ok in from_native"
serializer.save()
通过调用 League.teams.add(new_team) 将团队添加到未保存的联赛实例的任何尝试都会失败并出现完整性错误
IntegrityError: (1452, 'Cannot add or update a child row: a foreign key constraint fails
如何使用一对多外键关系保存未保存的League?我想保持当前的处理流程。
编辑 - 从那以后,我找到了解决方法。
1.我必须暂时从 DB 关联一个 League 对象,以便调用 new_team.full_clean()。完成后,我设置 new_team.league = new_league。这样我就可以验证最终将与尚未在数据库中的 new_league 关联的 new_team。
2.为了将new_team传递给我的视图,我在League模型中引入了一个unsaved_objects非模型列表。视图在 League 对象上调用 save(),然后迭代 unsaved_objects 并在每个对象上调用 save。
这是我到目前为止所了解到的 - Django 1.5 没有提供一种方法让您创建一个新联赛、一个新球队并将球队与联赛相关联并在任何一个对象上调用一次保存(无论是序列化器或模型)来保存联盟,它与团队和团队的关系。 Django 需要先在联赛中保存,然后在团队中保存。
我将上述方法称为解决方法,因为它不能完全满足我的目的。例如,如果团队保存失败,DB 将已经处理了联赛保存,因此需要我在创建 new_league 时跟踪 (a) 以便我可以在更新现有联赛时删除新联赛 (b) 以前的联赛内容,以便我可以恢复到上一个联赛。如果我可以在 save() 调用中进行事务处理,那么就可以解决这个问题。
为临时联赛不断查询db是一种浪费。
【问题讨论】:
-
显示更多代码可能会有所帮助,我很难理解您的 LeageSerializer 解释。
-
您必须先保存您的
League实例,然后才能添加团队,因为pk仅通过保存League实例生成,而pk是关联团队所必需的带有特定的League。 -
@PeterDeGlopper - 如果我保存了联盟实例并且球队验证失败,如果联盟是在尝试处理帖子时刚刚创建的,我将不得不撤消联盟保存。此外,我无法清楚地看到这种实现的流程。请注意,我在 POST 处理程序中进行了一次保存,并且我不知道将多个模型实例从 from_native 传递回我的视图的方法。
-
您可以在验证步骤中使用球队将与联赛相关联的信息。验证联盟,但不要保存它。将未保存的
league对象传递给您的团队验证代码,并使用它而不是self.league。如果一切正常,保存联盟,然后保存每支球队(直接设置其 FK 字段或使用add)。 -
@PeterDeGlopper 我所有的验证都发生在来自_native 的 LeagueSerializer 中。我不确定您在这里提出什么建议,您可以为您的提案发布一个 sn-p 吗?
标签: python django django-models django-views