Question

I'm using an UpdateView to update a series of fields. However, I only want fields that have been modified to be saved to the database. If a value was not provided for a field during update process, I want the previous value to be used as the default. If a new value was provided for a field then only that field should be updated. How do I go about accomplishing this?

#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 %}

All the fields are also declared as required in models.py. Currently the form only works if i provide a value for each field.

Était-ce utile?

La solution

i'm using a custom hash during update process to encrypt passwords. When i visit the edit page and hit update button, the old password in its current encrypted form gets re-encrypted hence losing the old password

I would handle that by not including password itself in the form. Instead, I would add a new field (something like new_password) to allow entering a new password. Then, in your is_valid method, set the password to the hashed value of that field if there's content.

You should also use the sensitive value filtering tools to prevent user passwords from showing up in emailed error reports.

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)

And then in your view:

@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)

Autres conseils

The easiest way would be to pre-populate the fields with what's already there. Do this on the template with {{ account.name }} or whatever.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top