Django管理员内联唯一约束违反编辑

时间:2019-03-07 13:19:22

标签: django django-admin

我有一个内联表格。相关模型具有唯一的共同约束(parent_id,数字)。我有一个有两个孩子的实体

parent_id | number |
        1 |      1 |
        1 |      2 |

我正在尝试通过一次操作将这些子级编辑为状态

parent_id | number |
        1 |      2 |
        1 |      3 |

保存时,我在第一个条目上有一个错误: Child with this parent_id and number already exists.

但是,如果我首先编辑第二个条目:

parent_id | number |
        1 |      1 |
        1 |      3 |

然后是第一个

parent_id | number |
        1 |      2 |
        1 |      3 |

在两个单独的操作中,效果很好。

ParentAdmin定义

class ParentAdmin(admin.ModelAdmin):
    form = BaseForm

    inlines = [LevelExerciseInline]

ChildInline定义

class ChildInline(admin.StackedInline):
    form = BaseForm

    model = Child
    extra = 3

1 个答案:

答案 0 :(得分:1)

在使用Django Admin内联时,情况并非如此:

  

我正在尝试通过一次操作将这些子级编辑为状态

内联是完整表格的一部分,将按照它们在表格中出现的顺序进行处理。因此,即使您“一次动作”更改它们,这意味着您在一种形式的POST期间更改它们,Django仍将一一保存这些相关对象:

列表中的第一个内联被保存,并且它尝试保存编号为2的parent_id 1,而数据库中仍然存在编号为2的parent_id 2。

具体地说,使用以下代码调用了formset.save()https://github.com/django/django/blob/master/django/forms/models.py#L655)。

注意:这里,“表单”是实际HTML表单的一部分(它只是变量的名称,请勿混淆)。

def save(self, commit=True):
    """Saves model instances for every form, adding and changing instances
    as necessary, and returns the list of instances.
    """
    if not commit:
        self.saved_forms = []

        def save_m2m():
            for form in self.saved_forms:
                form.save_m2m()
        self.save_m2m = save_m2m
    return self.save_existing_objects(commit) + self.save_new_objects(commit)

如您所见,调用save_m2m后,每个内联代码都会保存在循环中。数组按出现的顺序在表单中排序。

这与Django Admin无关,而更多的是关于它是否甚至可以在数据库级别上的问题。唯一可行的可能是事务,但即使如此-例如postgresql也不允许它,除非将约束设置为DEFERRED:

https://dba.stackexchange.com/questions/104987/avoid-unique-violation-in-atomic-transaction

Postgresql文档:https://www.postgresql.org/docs/current/sql-set-constraints.html

因此,要更改行为,您需要: