【问题标题】:How to save Django unsaved model with one-to-many relationship如何使用一对多关系保存 Django 未保存的模型
【发布时间】: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


【解决方案1】:

通过调用将球队添加到未保存的联赛实例的任何尝试 League.teams.add(new_team) 因完整性错误而失败

如果我对您的理解正确,您正在尝试将Team 保存到数据库中,但没有填写联盟的外键。尝试将blank=True, null=True 添加到定义leagueTeam 模型的行中,从而允许在没有现有League 链接的情况下保存Team

league = models.ForeignKey(League,related_name="teams", blank=True, null=True)

但我首先认为如果没有第二个密钥的密钥,您将无法保存一个模型。如果不先明确说明,您无法将“无”保存到数据库中。

【讨论】:

  • 一个有趣的想法,但有一个要求是团队不应该在没有联赛的情况下存在,所以空白=真,空=真有点失败。我已根据此要求更新了我的问题。
  • 那你不是在尝试做不可能的事吗?您不能将不存在的模型(就数据库而言)的密钥保存到数据库。它应该如何保存尚不存在的东西?
  • 我希望有一种方法可以将球队添加到未保存的联赛中,并将完整性检查推迟到联赛被保存时。问题在于保存,添加调用正在查看数据库中的内容,它不应该用于我的目的。这有时被称为“前向引用”
  • 联赛必须有一个主键,然后才能设置任何与它有外键关系的东西。对由外键创建的反向关系的add 调用通过将您尝试的对象的外键字段设置为add 来工作。这不是完整性检查,而是数据库工作方式的逻辑要求。 Django 没有为以后自动填充的占位符提供接口。
  • 请注意,如果我执行 new_team.league = League,那没关系!未保存的 League 对象的主键已设置。 [模型使用自己的主键代替django默认pk]
猜你喜欢
  • 2015-07-02
  • 1970-01-01
  • 2017-12-16
  • 2018-07-05
  • 2014-11-21
  • 1970-01-01
  • 2010-10-05
  • 2011-07-12
  • 2015-10-11
相关资源
最近更新 更多