Python 表单使用Django交换数据库中的2个对象

Python 表单使用Django交换数据库中的2个对象,python,django,Python,Django,我是django的新手,在过去一个月左右的时间里,我一直在开发一个简单的应用程序,但我遇到了一个问题,我没有做到这一点。 我有一个名为WeeklyPlaylist的简单模型(来自我的models.py): 其中“位置”仅表示视频在播放列表中的位置。 我想让管理员能够通过上述模型的更改/更新表单(从my admin.py)将播放列表中一个视频的位置与同一播放列表中的另一个视频交换: 我正在为此对象定义自己的表单(仍然来自admin.py): 我的想法基本上是在WeeklyPlaylist模型的ch

我是django的新手,在过去一个月左右的时间里,我一直在开发一个简单的应用程序,但我遇到了一个问题,我没有做到这一点。 我有一个名为WeeklyPlaylist的简单模型(来自我的models.py):

其中“位置”仅表示视频在播放列表中的位置。 我想让管理员能够通过上述模型的更改/更新表单(从my admin.py)将播放列表中一个视频的位置与同一播放列表中的另一个视频交换:

我正在为此对象定义自己的表单(仍然来自admin.py):

我的想法基本上是在WeeklyPlaylist模型的change/update表单中向管理员提供一个额外的“select”html标记,管理员可以在其中输入当前视频播放列表中的新位置,并在相关的clean_uu方法中进行必要的检查,以确保所需的播放列表位置有效。 到现在为止,一直都还不错。现在,我的问题是:当管理员点击“保存”按钮时,我如何同时保存修改过的对象,以及与之交换位置的对象?我尝试在表单的save()方法中使用以下代码执行此操作:

def save(self, commit=True, *args, **kwargs):
    m = super(WeeklyPlaylistAdminForm, self).save(commit=False, *args, **kwargs)
    cleaned_data = self.cleaned_data
    swap_with_position = cleaned_data.get("swap_with_position")
    if commit:
        # select the database obj to swap position with
        other = WeeklyPlaylist.objects.get(sched__screen__name=m.sched.screen.name, sched__year__exact=m.sched.year, week=m.week, position=swap_with_position)
        m.position, other.position = other.position, m.position
        m.save()
        other.save()
    return m
这似乎很好,只是出于某种原因,commit总是false,即使在操作完成后保存了'm',这是我不理解的。但结果是,永远不会调用other.save(),如果我删除检查commit值的if语句,我将无法对WeeklyPlaylistAdminForm对象执行save(commit=False),这可能会很烦人。。。 那么,有什么建议可以帮助我吗? 非常感谢! 干杯
Adrien

当我在Django做过类似的事情时,我还没有实现专门与另一个类别交换的模型,而是对列表进行重新排序;因此,将顺序为5的元素移动到顺序为0的元素会将顺序在0到4之间的所有之前的元素向上移动,但是使用特定顺序的元素进行交换应该会容易得多

我会在进行任何修改之前存储模型的上一个位置,并在实际保存之前检测它是否在保存方法中发生了更改。如果它已更改,则我将保存当前模型,然后查找具有该位置和不具有当前位置的模型,并更新该模型以更正位置;希望以下代码有助于演示我的意思:

class WeeklyPlaylist(models.Model):
  def __init__(self, *args, **kwargs):
    super(WeeklyPlaylist, self).__init__(*args, **kwargs)
    self._position = int(self.position)

  def save(self, *args, **kwargs):
    super(WeeklyPlaylist, self).save(*args, **kwargs)

    # position has changed, so change the position of the element that held the new position now held by this element
    if int(self.position) != self._position:
      WeeklyPlaylist.objects.exclude(pk=self.pk).filter(
        position=self.position
      ).update(position=self._position)

当我在Django中做了类似的事情时,我没有实现专门与另一个类别交换的模型,而是对列表进行了重新排序;因此,将顺序为5的元素移动到顺序为0的元素会将顺序在0到4之间的所有之前的元素向上移动,但是使用特定顺序的元素进行交换应该会容易得多

我会在进行任何修改之前存储模型的上一个位置,并在实际保存之前检测它是否在保存方法中发生了更改。如果它已更改,则我将保存当前模型,然后查找具有该位置和不具有当前位置的模型,并更新该模型以更正位置;希望以下代码有助于演示我的意思:

class WeeklyPlaylist(models.Model):
  def __init__(self, *args, **kwargs):
    super(WeeklyPlaylist, self).__init__(*args, **kwargs)
    self._position = int(self.position)

  def save(self, *args, **kwargs):
    super(WeeklyPlaylist, self).save(*args, **kwargs)

    # position has changed, so change the position of the element that held the new position now held by this element
    if int(self.position) != self._position:
      WeeklyPlaylist.objects.exclude(pk=self.pk).filter(
        position=self.position
      ).update(position=self._position)

是否可以尝试删除.save()签名中的commit-kwarg并改为执行
commit=kwargs.get(“commit”,True)
?只是试图排除Django管理内部传递一个falsy第一个参数的可能性,该参数被分配给commit kwarg。我不认为会发生这种情况,但在深入研究之前需要排除。谢谢你的评论,AdamKG,我按照你说的做了,但结果是一样的,commit仍然设置为False…你能尝试删除.save()签名中的commit-kwarg并改为执行
commit=kwargs.get(“commit”,True)
吗?只是试图排除Django管理内部传递一个falsy第一个参数的可能性,该参数被分配给commit kwarg。我不认为会发生这种情况,但在深入研究之前需要排除。谢谢你的评论,AdamKG,我按照你说的做了,但结果是一样的,commit仍然设置为False…谢谢你的回复,Dominic,我想它应该会起作用,但我有点担心并发性问题:如果两个用户同时尝试更改同一对象的位置,会发生什么情况?多谢你的回复,Dominic,我想这应该行得通,但我有点担心并发性问题:如果两个用户同时尝试更改同一对象的位置,会发生什么情况?
def save(self, commit=True, *args, **kwargs):
    m = super(WeeklyPlaylistAdminForm, self).save(commit=False, *args, **kwargs)
    cleaned_data = self.cleaned_data
    swap_with_position = cleaned_data.get("swap_with_position")
    if commit:
        # select the database obj to swap position with
        other = WeeklyPlaylist.objects.get(sched__screen__name=m.sched.screen.name, sched__year__exact=m.sched.year, week=m.week, position=swap_with_position)
        m.position, other.position = other.position, m.position
        m.save()
        other.save()
    return m
class WeeklyPlaylist(models.Model):
  def __init__(self, *args, **kwargs):
    super(WeeklyPlaylist, self).__init__(*args, **kwargs)
    self._position = int(self.position)

  def save(self, *args, **kwargs):
    super(WeeklyPlaylist, self).save(*args, **kwargs)

    # position has changed, so change the position of the element that held the new position now held by this element
    if int(self.position) != self._position:
      WeeklyPlaylist.objects.exclude(pk=self.pk).filter(
        position=self.position
      ).update(position=self._position)