2013-08-20 4 views
2

Я использую UpdateView для обновления ряда полей. Однако мне нужны только те поля, которые были изменены для сохранения в базе данных. Если в процессе обновления не было задано значение поля, я хочу, чтобы предыдущее значение использовалось как значение по умолчанию. Если для поля было предоставлено новое значение, то необходимо обновить только это поле. Как я могу это сделать?Django: обновлять поля, которые были изменены в 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. В настоящее время форма работает только в том случае, если я предоставляю значение для каждого поля.

ответ

5

Я использую собственный хэш во время процесса обновления для шифрования паролей. Когда я захожу на страницу редактирования и нажмите кнопку обновления, старый пароль в своем текущем зашифрованном виде получает перешифровывается, следовательно, теряет старый пароль

Я бы справиться с этим не включая 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) 
+0

Спасибо за это решение. Основываясь на вашем комментарии к ответу Роба, я думаю, что смогу решить проблему с отдельным полем. Я отправлю свое решение после завершения. Благодаря! – Staccato

+0

Я не совсем уверен, какую другую проблему с обновлением поля вы имеете - это должно быть безвредным для установки, скажем, 'first_name =« Joe », если он не изменился. –

+0

Если update_form предварительно заполнена 'first_name = 'joe'', но пользователь решает удалить значение в этом поле на странице обновления и оставить его пустым, я хочу, чтобы' first_name' по умолчанию возвращался на 'joe'. Извините за путаницу. – Staccato

0

Самый простой способ - предварительно заполнить поля тем, что уже есть. Сделайте это на шаблоне с {{ account.name }} или что угодно.

+0

Я обновил этот вопрос с моим файлом шаблона. когда я перехожу на страницу редактирования, форма уже заполнена значениями, кроме поля пароля (не знаю почему), но когда я пытаюсь сохранить форму, ничего не происходит, если я не заполню все пустые поля. – Staccato

+0

Попробуйте 'render_value = True' on 'password'. Смотрите: https://docs.djangoproject.com/en/dev/ref/forms/widgets/#django.forms.PasswordInput –

+0

Хорошо, render_value = True работал ... только проблема в том, что я использую пользовательский хеш во время процесса обновления для шифрования паролей. Когда я нахожусь на странице редактирования и нажимаю кнопку обновления, старый пароль в его текущей зашифрованной форме снова зашифровывается и, следовательно, потеряет старый пароль. С другой стороны, поскольку форма уже заполнена, как я могу решить мою первоначальную проблему только обновления измененных полей? – Staccato

Смежные вопросы