【问题标题】:Django: Only update fields that have been changed in UpdateViewDjango:仅更新UpdateView中已更改的字段
【发布时间】:2013-08-22 23:52:29
【问题描述】:

我正在使用 UpdateView 来更新一系列字段。但是,我只希望将已修改的字段保存到数据库中。如果在更新过程中没有为字段提供值,我希望将以前的值用作默认值。如果为字段提供了新值,则只应更新该字段。我该怎么做呢?

#views.py
class AccountUpdate(UpdateView):
""" Updates an account; unchanged fields will not be updated."""
context_object_name = 'account'
form_class = UpdateForm
template_name = 'accounts/update_account.html'
success_url = '/accounts/home'

def get_object(self, queryset=None):
    return self.request.user

def form_valid(self, form):
    clean = form.cleaned_data
    #encrypt plain password
    form.instance.password = hash_password(clean['password'])
    context = {}
    self.object = context.update(clean, force_update=False)
    return super(AccountUpdate, self).form_valid(form)

#templates
{% extends 'base.html' %}
<title>{% block title %}Update Account{% endblock %}</title>
{% block content %}
{{ account.non_field_errors }}
<div class="errors" style="list-style-type: none;">
    {% if account.first_name.errors %}{{ account.first_name.errors }}{% endif %}
    {% if account.last_name.errors %}{{ account.last_name.errors }}{% endif %}
    {% if account.email.errors %}{{ account.email.errors }}{% endif %}
    {% if account.password.errors %}{{ account.password.errors }}{% endif %}
    {% if account.username.errors %}{{ account.username.errors }}{% endif %}
</div>
<form action="" name="edit" method="post">
    {% csrf_token %}
    <ul>
        <li>Fullname</li>
       <li> {{ form.first_name }}{{ form.last_name }}</li>
        <li>Email</li>
        <li>{{ form.email }}</li>
        <li>Password</li>
        <li>{{ form.password }}</li>
        <li>Username</li>
        <li>{{ form.username }}</li>
    </ul>
    <ul>
        <li><input type="submit" value="update account"></li>
    </ul>
</form>
<ul>
    <li class="nav"><a href="/accounts/">cancel changes</a></li>
</ul>
{% endblock %}

models.py 中还根据需要声明了所有字段。目前该表单仅在我为每个字段提供值时才有效。

【问题讨论】:

    标签: django django-forms django-class-based-views


    【解决方案1】:

    我在更新过程中使用自定义哈希来加密密码。当我访问编辑页面并点击更新按钮时,当前加密形式的旧密码被重新加密,因此丢失旧密码

    我会通过不在表单中包含 password 本身来处理这个问题。相反,我会添加一个新字段(类似于new_password)以允许输入新密码。然后,在您的 is_valid 方法中,将密码设置为该字段的哈希值(如果有内容)。

    您还应该使用sensitive value filtering 工具来防止用户密码出现在通过电子邮件发送的错误报告中。

    class UpdateForm(forms.ModelForm):
        class Meta:
            model = user
            fields = ('first_name', 'last_name', 'email', 'username')
        new_password = forms.CharField(required=False, widget=forms.widgets.PasswordInput)
    

    然后在你看来:

    @sensitive_variables('new_password')
    @sensitive_post_parameters('new_password')
    def form_valid(self, form):
        clean = form.cleaned_data
        new_password = clean.get('new_password')
        if new_password:
            #encrypt plain password
            form.instance.password = hash_password(new_password)
        return super(AccountUpdate, self).form_valid(form)
    

    【讨论】:

    • 感谢您的解决方案。根据您对 Rob 回答的评论,我想我将能够解决个别字段更新问题。完成后我会发布我的解决方案。谢谢!
    • 我不太确定您还有什么其他字段更新问题 - 如果没有更改,设置 first_name = "Joe" 应该是无害的。
    • 如果 update_form 预先填充了first_name = 'joe',但用户决定删除更新页面上该字段中的值并将其留空,我希望first_name 默认返回@987654330 @。很抱歉造成混乱。
    • 我明白了。这是使用通用视图更难设置的东西,至少如果您仍然允许某些字段合法地为空白的可能性。我想你可以遍历表单的 changed_data 名称,看看它们是否为空,如果是,则复制 self.object 版本的值。
    • if you're still allowing for the possibility of some of the fields legitimately being blank. 所有四个字段都是必需的。我还能继续循环吗?
    【解决方案2】:

    最简单的方法是使用已经存在的内容预先填充字段。 使用{{ account.name }} 或其他方式在模板上执行此操作。

    【讨论】:

    • 我已经用我的模板文件更新了这个问题。当我进入编辑页面时,表单已经预先填充了除密码字段之外的值(不知道为什么)但是当我尝试保存表单时,除非我填写所有空白字段
    • password 上尝试render_value=True。见:docs.djangoproject.com/en/dev/ref/forms/widgets/…
    • 好的,render_value=True 工作...唯一的问题是,我在更新过程中使用自定义哈希来加密密码。当我访问编辑页面并点击更新按钮时,当前加密形式的旧密码被重新加密,因此丢失了旧密码。另一方面,由于表单已经被预先填充,我该如何解决我最初的问题,即只更新更改的字段?
    • 我能想到的唯一方法是使用一系列 if-elif 语句将数据库中的每个字段与提交的值进行匹配,以查看它们是否不同,然后执行单个字段更新查询。 .这听起来乏味且不符合 Python 风格
    • 另外,您为什么在更新表单上显示密码?把它放在一个单独的表单上,或者如果用户没有更改他/她的密码,则让它为空。
    猜你喜欢
    • 1970-01-01
    • 2013-10-28
    • 2020-02-25
    • 2019-06-24
    • 2019-11-10
    • 1970-01-01
    • 2020-04-24
    • 2013-12-19
    • 1970-01-01
    相关资源
    最近更新 更多