How to update User object without creating new one? - django

Following works fine in shell:
>>> from django.contrib.auth.models import User
>>> user=User.objects.get(pk=1)
>>> user.first_name = u'Some'
>>> user.last_name = u'Name'
>>> user.save()
>>> user.first_name
u'Some'
>>> user.last_name
u'Name'
Then I try to do the same with forms:
# forms.py
class UserForm(forms.ModelForm):
class Meta:
model = User
fields = ['first_name', 'last_name']
# views.py
def edit_names(request, template_name="registration/edit_names.html"):
if request.method == "POST":
form = UserForm(data=request.POST)
if form.is_valid():
user = form.save(commit=False)
user.save()
url = urlresolvers.reverse('my_account')
return HttpResponseRedirect(url)
else:
form = UserForm(instance=request.user)
page_title = _('Edit user names')
return render_to_response(template_name, locals(),
context_instance=RequestContext(request))
# edit_names.html
<form action="." method="post">{% csrf_token %}
<table>
{{ form.as_table }}
<tr><td colspan="2">
<input type="submit" />
</td></tr>
</table>
</form>
I open page in browser and see two fields First name and Last name. When I fill in the fields and submit the form I get the error:
Exception Type: IntegrityError
Exception Value: column username is not unique
I also tried to add ['username'] to fields list in UserForm. If I submit the form with my username (as request.user), the form displays errormessage:
User with this Username already exists.
If I change the username to some unique name, the new user with that username is being created.
The question is:
How can I update User object, not create new one?
Sorry for being so verbose, but I had hard search here and could not find the answer to my question.
BTW, these cases don't work for me:
Extending UserCreationForm to include email, first name, and last name
add field first_name and last_name in django-profile
How to create a UserProfile form in Django with first_name, last_name modifications?
EDIT:
As suggested #fceruti I just added on request.method == 'post' branch this:
form = UserForm(data=request.POST, instance=request.user)

Just add on request.method == 'post' branch this:
form = UserForm(data=request.POST, instance=request.user)

if request.method == "POST":
kwargs = { 'data' : request.POST }
try:
kwargs['instance'] = User.objects.get(username=request.POST['username'])
except:
pass
form = UserForm(kwargs**)
if form.is_valid():
user = form.save(commit=False)
...

Related

how to pass the username to the member who fill a form?

i have a form, and i want to pass the user to it to see which logged in user filled it.
this is my forms.py
from .models import UserInfo
from django import forms
class InfoForm(forms.ModelForm):
class Meta:
model = UserInfo
fields = ('name', 'age', 'male', 'female', 'height', 'weight',
'BMI', 'BFP', 'phone', 'r_g_weight', 'physical_ready', 'fitness',
'workour_sports', 'others', 'goal_expression', 'body_change',
'noob','low_pro','semi_pro','pro','motivation_level','goal_block',
'change_time','past_sports','injury','work','work_time','wakeup_time',
'work_start_time','sleep_time','daily','hard_to_wake','ready_to_work',
'life_situation','weight_feel','daily_jobs','health_ready','workout_period',
'what_sport','where_sport','home_sport','weekly_time','sport_dislike','daily_food',
'food_quantity','hunger','vitamins','rejims','vegetables','goal_rec',
'stop','rec','heart','chest','chest_month','dizzy','bones','blood','other_reason')
and this is my view, i asked for the user with request.user , but the field in db always is empty for username.
def userForm(request):
if request.method == "POST":
form = InfoForm(request.POST)
if form.is_valid():
form.user = request.user
form.save()
return redirect('profile')
else:
form = InfoForm()
context = {
'form':form
}
return render(request, 'fitness/user_form.html', context)
so i have user in my models which has foreign key to my account
user = models.ForeignKey(Account,on_delete=models.CASCADE, null=True, blank=True)
and this is my template:
<div class="container">
<form action="{% url 'user-form' %}" method="POST" enctype="multipart/form-data">
{% csrf_token %}
{{form.as_p}}
<input type="submit" value="submit">
</form>
</div>
The problem lies in the way you are saving your form. You set the user attribute on the form, instead of the actual model object. The following should fix your issue
def userForm(request):
if request.method == "POST":
form = InfoForm(request.POST)
if form.is_valid():
# dont commit the object to the database as we need to set the user
object = form.save(commit=False)
# set the user
object.user = request.user
# finally save the object now that the user has been set
object.save()
return redirect('profile')
else:
form = InfoForm()
context = {
'form':form
}
return render(request, 'fitness/user_form.html', context)

Django forms: Update a user's attributes without changing username

I'm trying to create a form that allows a user to update their username or avatar. The problem that I am running into is that if I update the profile picture without changing the username, the django form validation if form.is_valid() will recognize the form as invalid, since the username already exists in the database. I'm using an update view, though I'm not sure I've implemented it correctly.
When I try to update the avatar without changing the username, I get a page that says "Form is invalid" from the line: HttpResponse("Form is invalid"). Is there a workaround to remove the form validation? I have tried removing if form.is_valid(): but received the error 'User_form' object has no attribute 'cleaned_data'.
I feel like there has to be an easy way around this that I have not been able to find, as so many sites allow you to update only one attribute at a time.
Views.py
model = User
form = User_form
fields = ['username', 'avatar']
template_name_suffix = '_update_form'
def update_profile(request, user_id):
if request.method == "POST":
form = User_form(request.POST, request.FILES)
if form.is_valid():
user = User.objects.get(pk=user_id)
username = form.cleaned_data['username']
avatar = form.cleaned_data['avatar']
if username != user.username:
user.username = username
if avatar != user.avatar:
if avatar:
user.avatar = avatar
user.save()
return redirect('index')
else:
return HttpResponse("Form is invalid")
models.py
class User(AbstractUser):
followed_by = models.ManyToManyField("User", blank=True, related_name="following")
avatar = models.ImageField(upload_to='profilepics/', verbose_name='Avatar', null=True, blank=True)
class User_form(ModelForm):
class Meta:
model = User
fields = ['username', 'avatar']
user_update_form.html
<form action="/profile/{{user.id}}/update" method="post" enctype='multipart/form-data'>
{% csrf_token %}
{{ form.as_p }}
<input type="submit" value="Update">
</form>
You are doing too much work yourself. Django's ModelForms can not only create data, but update data as well. You pass the instance through the instance=… parameter:
from django.shortcuts import get_object_or_404
def update_profile(request, user_id):
user = get_object_or_404(User, pk=user_id)
if request.method == 'POST':
form = User_form(request.POST, request.FILES, instance=user)
if form.is_valid():
form.save()
return redirect('index')
else:
return HttpResponse('Form is invalid')
else:
form = User_form(instance=user)
return render(request, 'some_template.html', {'form': form})
For uniqness checks, it will exclude the instance when checking if the username already exists. So one can change the username, given the new username of course does not yet exists.

Saving Django user forms without changing the password

I'm maintaining a Django application and have encountered a bug where if a user edits their profile then their password is corrupted; it seems that set_password is not being used and so the password is set to an unencrypted value which is hardcoded in the form. It's not clear how I could change the existing setup to get around this nuisance, and would welcome any suggestions. The update code looks like this:
#login_required
def profile(request):
user = request.user
profile, created = UserProfile.objects.get_or_create(user=user)
if request.method == 'POST':
userform = UserForm(request.POST, instance=user)
profileform = ProfileForm(request.POST, instance=profile)
if profileform.is_valid():
profileform.save()
if userform.is_valid():
userform.save()
return redirect('user_profile_page')
else:
profileform = ProfileForm(instance=profile)
userform = UserForm(instance=user)
render(request, 'profiles/edit_profile.html', {'profileform': profileform, 'userform': userform})
return render(request, 'profiles/edit_profile.html', {'profileform': profileform, 'userform': userform})
Then, the userform which is causing the problem contains this odd-looking code:
class UserForm(forms.ModelForm):
class Meta:
model = User
exclude = ('last_login', 'date_joined', 'is_active', 'is_superuser', 'is_staff')
username = forms.CharField(widget=forms.TextInput(attrs={'readonly': 'readonly'}))
password = forms.CharField(widget=forms.PasswordInput(attrs={'readonly': 'readonly', 'value': '00000000000000000'}))
I'm not really sure what the value attr in password is meant to be doing. Anyway, I tried to modify this by adding the following to the UserForm:
def save(self, commit=True):
user = super(UserForm, self).save(commit=False)
password = self.cleaned_data["password"]
if len(password) > 0 and password != '00000000000000000':
user.set_password(self.cleaned_data["password"])
if commit:
user.save()
return user
I had no luck with this either, and if I simply omit the password field from the userform or the relevant html then the form does not validate.
<form method="post" action="" class="wide">
{% csrf_token %}
.....
<label for="id_password">Password:</label>
{{ userform.password }}
Can anyone suggest how this might be cleaned up?
Use a separate form for editing the password and remove it from this one. Add password to the exclude list and remove the field declaration.

Django Forms: Validation message not showing

Can anyone spot what I'm doing wrong in the following example. Validating messages are not appearing in my template when incorrect details are entered such as a invalid email address. The template is loading and there are no errors.
I'm excepting validation messages to be printed on page, however for some reason this has suddenly stop working. As you can see from the code example below I'm passing the form in the context back to the template. this used to work and today just stopped.
view.py
if request.method == 'POST':
form = RegistrationForm(request.POST)
if form.is_valid():
# If form has passed all validation checks then continue to save member.
user = User.objects.create_user(
username=form.cleaned_data['username'],
email=form.cleaned_data['email'],
password=form.cleaned_data['password']
)
user.save()
#member = User.get_profile()
#member.name = form.cleaned_data['name']
#member.save()
member = Member(
user=user,
name=form.cleaned_data['name']
)
member.save()
# Save is done redirect member to logged in page.
return HttpResponseRedirect('/profile')
else:
# If form is NOT valid then show the registration page again.
form = RegistrationForm()
context = {'form':form}
return render_to_response('pageRegistration.html', context,context_instance=RequestContext(request))
form.py
class RegistrationForm(ModelForm):
username = forms.CharField(label=(u'User Name'))
email = forms.EmailField(label=(u'Email'))
password = forms.CharField(label=(u'Password'), widget=forms.PasswordInput(render_value=False))
passwordConfirm = forms.CharField(label=(u'Confirm Password'), widget=forms.PasswordInput(render_value=False))
class Meta:
model = Member
# Don't show user drop down.
exclude = ('user',)
def clean_username(self):
username = self.cleaned_data['username']
try:
User.objects.get(username=username)
except User.DoesNotExist:
return username
raise forms.ValidationError("Username already taken.")
def clean(self):
try:
cleaned_data = super(RegistrationForm, self).clean()
password = cleaned_data.get("password")
passwordConfirm = cleaned_data.get('passwordConfirm')
if password != passwordConfirm:
raise forms.ValidationError("Password does not match, try again.")
return cleaned_data
except:
raise forms.ValidationError("Error")
pageRegistration.html
<form action="" method="POST">
{% csrf_token %}
{% if forms.errors %}
<p>
correct some stuff
</p>
{% endif %}
{{form}}
<br>
<input type="submit" value="submit">
</form>
Since, the form is not validate in the else clause your form variable is overriden with a new form where it looses all of the errors
if request.method == 'POST':
form = RegistrationForm(request.POST)
if form.is_valid():
# If form has passed all validation checks then continue to save member.
user = User.objects.create_user(
username=form.cleaned_data['username'],
email=form.cleaned_data['email'],
password=form.cleaned_data['password']
)
user.save()
#member = User.get_profile()
#member.name = form.cleaned_data['name']
#member.save()
member = Member(
user=user,
name=form.cleaned_data['name']
)
member.save()
# Save is done redirect member to logged in page.
return HttpResponseRedirect('/profile')
return render_to_response('pageRegistration.html', context,context_instance=RequestContext(request))
Updated for the CBV world.
This is what was causing the equivalent error for me:
class CreateView(generic.CreateView): # or generic.UpdateView
def get_context_data(self, **kwargs):
context_data = super(CreateView, self).get_context_data(**kwargs)
# context_data['form'] = self.form_class # << this was the problematic override
Perhaps the page is returning a new form every time it reloads. Check if the
context variable in views.py contains 'form' : form

I'm trying to save data from views

My forms.py file:
class RegisterForm(ModelForm):
"""This form lets people register as members."""
help_string = "Please choose a password that is at 6 characters long,"\
"and contains at least on speacial character or number"
First_Name = forms.CharField(max_length=50)
Last_Name = forms.CharField(max_length=50)
Username = forms.CharField(max_length=50)
Password = forms.CharField(max_length=50)
Confirm_Password = forms.CharField(max_length=50)
Email_Address = forms.EmailField()
Address = forms.CharField(widget=forms.Textarea)
def save(self, commit=True):
cd = self.cleaned_data
u = User.objects.create_user(
username=self.cleaned_data['Username'],
email=self.cleaned_data['Email_Address'],
password=self.cleaned_data['Password'],
)
u.is_staff = True
u.save()
u.First_Name = self.cleaned_data['First_Name']
u.Last_Name = self.cleaned_data['Last_Name']
m = self.instance
m.user = u
if not commit:
return [m, u]
u.save()
m.save()
return m
My views.py file:
def register(request):
if request.method == "POST":
form = RegisterForm(request.POST)
if form.is_valid():
try:
instance = form.save()
return HttpResponseRedirect('/registered/')
except:
return HttpResponseRedirect('/validation/')
else:
form = RegisterForm()
return render_to_response(
'homepage/register.html',
{'form':form,},
context_instance=RequestContext(request),
)
My register.html template:
<h4>Register</h4>
<form action="" method="POST">
<table border="0" cellpadding="1" cellspacing="1" id="eric">
<tr>
<td>{{ form.as_table }}</td>
</tr>
<tr>
<td></td>
<td>
<input type="submit" value="Create Account">
<input type="Reset" value="Clear"></td>
</tr>
</table>
</form>
The thing what it does in views.py is skip the try block and execute the except.
What should I do or change?
So, You are saving the data twice. And in your model definition username must be unique. So, throwing integrity error. You are saving data in
1.) Forms save
2.) again same data you are saving in Views.
My suggestion.
clean your data in the forms.
Remove save() from forms.
save form in views.
class RegisterForm(ModelForm):
"""This form lets people register as members."""
help_string = "Please choose a password that is at 6 characters long,"\
"and contains at least on speacial character or number"
First_Name = forms.CharField(max_length=50)
Last_Name = forms.CharField(max_length=50)
Username = forms.CharField(max_length=50)
Password = forms.CharField(max_length=50)
Confirm_Password = forms.CharField(max_length=50)
Email_Address = forms.EmailField()
Address = forms.CharField(widget=forms.Textarea)
def clean_name(self,):
username = self.cleaned_data['Username']
return username
def clean_email(self,):
email = self.cleaned_data['Email_Address']
param = {'email': email}
if dbapi.get_user(**param):
raise ValidationError('Email already registered')
return email
def clean_password(self,):
// your logic here
In views.
Not resembles your code
All values are dummy here You just fit according to your values
register_name should be the instance of your Form
username = register_form.cleaned_data['username']
email = register_form.cleaned_data['email']
password = register_form.cleaned_data['password']
name = register_form.cleaned_data['name']
# Create a user obj
user_obj = create_user(username, email, password) // to create a user_obj
# https://docs.djangoproject.com/en/dev/topics/auth/#creating-users
user_obj.first_name = 'xxxxxxxxx'
user_obj.last_name = 'xxxxxxxxxx'
user_obj.save()
Ok. I am writting here a create_user method:
from django.contrib.auth.models import User
def create_user(username, email, password):
# This will return the user_obj
return User.objects.create_user(username, email, password)
Since you are using ModelForm, I suggest you remove the 'except' in your registration function. It should look like this:
def register(request):
if request.method == "POST":
form = RegisterForm(request.POST)
if form.is_valid():
instance = form.save()
return HttpResponseRedirect('/registered/')
else:
form = RegisterForm()
return render_to_response(
'homepage/register.html',
{'form':form,},
context_instance=RequestContext(request),
)
The reason of removing the 'except' is that you are already using modelform and it provides you with form validations. You don't have to create a template telling the user that their input is invalid (that is if you are using /validation/ to tell the user that they have invalid input).