python - ModelForm 保存带有空字段的模型数据

标签 python django

我正在使用 Django 中的 ModelForm 为数据库中的模型构建一个编辑表单。表单中的每个字段都是可选的,因为用户可能只想编辑一个字段。

我遇到的问题是,当我在 View 中调用 save() 时,任何空字段都将保存在实例的原始值上(例如,如果我只输入新的 first_name last_nameecf_code 字段将在相应实例中保存一个空字符串。)

形式:

class EditPlayerForm(forms.ModelForm):

    class Meta:
        model = Player
        fields = ['first_name', 'last_name', 'ecf_code']

    def __init__(self, *args, **kwargs):
        super(EditPlayerForm, self).__init__(*args, **kwargs)
        self.fields['first_name'].required = False
        self.fields['last_name'].required = False
        self.fields['ecf_code'].required = False

View :

def view(request, player_pk = ''):

    edit_player_form = forms.EditPlayerForm(auto_id="edit_%s")

    if "edit_player_form" in request.POST:

        if not player_pk:

            messages.error(request, "No player pk given.")

        else:

            try:

                selected_player = Player.objects.get(pk = player_pk)

            except Player.DoesNotExist:

                messages.error(request, "The selected player could not be found in the database.")
                return redirect("players:management")

            else:

                edit_player_form = forms.EditPlayerForm(
                    request.POST,
                    instance = selected_player
                )

                if edit_player_form.is_valid():

                    player = edit_player_form.save()
                    messages.success(request, "The changes were made successfully.")
                    return redirect("players:management")

                else:
                    form_errors.convert_form_errors_to_messages(edit_player_form, request)

    return render(
        request,
        "players/playerManagement.html",
        {
            "edit_player_form": edit_player_form,
            "players": Player.objects.all(),
        }
    )

我尝试重写表单的 save() 方法来显式检查哪些字段在 POST 请求中具有值,但这似乎没有产生任何影响也有区别。

尝试重写保存方法:

def save(self, commit = True):

    # Tried this way to get instance as well
    # instance = super(EditPlayerForm, self).save(commit = False)

    self.cleaned_data = dict([ (k,v) for k,v in self.cleaned_data.items() if v != "" ])

    try:
        self.instance.first_name = self.cleaned_data["first_name"]
    except KeyError:
        pass

    try:
        self.instance.last_name = self.cleaned_data["last_name"]
    except KeyError:
        pass

    try:
        self.instance.ecf_code = self.cleaned_data["ecf_code"]
    except KeyError:
        pass


    if commit:
        self.instance.save()


    return self.instance

我也没有 Player 模型的任何默认值,因为文档说 ModeForm 将使用这些默认值作为表单提交中缺少的值。

编辑:

这是整个EditPlayerForm:

class EditPlayerForm(forms.ModelForm):


    class Meta:
        model = Player
        fields = ['first_name', 'last_name', 'ecf_code']

    def __init__(self, *args, **kwargs):
        super(EditPlayerForm, self).__init__(*args, **kwargs)
        self.fields['first_name'].required = False
        self.fields['last_name'].required = False
        self.fields['ecf_code'].required = False


    def save(self, commit = True):

        # If I print instance variables here they've already
        # been updated with the form values

        self.cleaned_data = [ k for k,v in self.cleaned_data.items() if v ]

        self.instance.save(update_fields = self.cleaned_data)

        if commit:

            self.instance.save()

        return self.instance

编辑:

好的,这就是解决方案,我想我应该把它放在这里,因为它可能对其他人有用(我当然从中学到了一些东西)。

事实证明,模型表单的 is_valid() 方法实际上对您传递到表单中的实例进行了更改,为 save() 做好了准备方法来保存它们。因此,为了解决这个问题,我扩展了表单的 clean() 方法:

 def clean(self):

    if not self.cleaned_data.get("first_name"):
        self.cleaned_data["first_name"] = self.instance.first_name

    if not self.cleaned_data.get("last_name"):
        self.cleaned_data["last_name"] = self.instance.last_name

    if not self.cleaned_data.get("ecf_code"):
        self.cleaned_data["ecf_code"] = self.instance.ecf_code

这基本上只是检查字段是否为空,如果字段为空,则用给定实例中的现有值填充它。 clean() 在使用新表单值设置实例变量之前被调用,因此这样,任何空字段实际上都会填充相应的现有实例数据。

最佳答案

您也许可以使用 update() 方法而不是 save() 或参数 update_field

self.instance.save(update_fields=['fields_to_update'])

仅使用非空值构建列表['fields_to_update']

它甚至应该与您尝试过的理解一起工作:

self.cleaned_data = [ k for k,v in self.cleaned_data.items() if v ]

self.instance.save(update_fields=self.cleaned_data)

编辑:

不重写保存方法(并在表单中注释掉此尝试):

not_empty_data = [ k for k,v in edit_player_form.cleaned_data.items() if v ]
print(not_empty_data)
player = edit_player_form.save(update_fields=not_empty_data)

关于python - ModelForm 保存带有空字段的模型数据,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45772137/

相关文章:

Python 分组

python - 在 `CheckConstraint` 中创建一个 `UniqueConstraint`

python - 如何自动填充相关问题

javascript - json 字符串和 django 模板的问题

python - 使用 imaplib 和 oauth 连接 Gmail

python - 如何在一个字符串中一次替换两个东西?

python - Sentry django 配置 - 记录器

django - 更新 Django 表单上的 forms.FileField

Django:按距离排序对象

python - 如何使用包含该模型查询集的列表序列化模型?