I would like users to have the ability to update their email address. I created a profile that has fields, but the email address is in the users table. I created a form that adds a custom form field and it works for update. However, I can't find a way to pre-populate this field on a REQUEST.GET.
# forms.py
class ProfileForm(forms.ModelForm):
class Meta:
model = Profile
fields = ('name', 'timezone')
class ProfileUpdateForm(ProfileForm):
email = forms.EmailField(max_length=254)
class Meta(ProfileForm.Meta):
fields = ProfileForm.Meta.fields ('email',)
# views.py
@login_required
@require_http_methods(["GET","POST"])
def profile_update_view(request):
context = {}
# Get the logged in users profile
profile_object = Profile.objects.get(user=request.user.id)
if request.method == 'GET':
profile_form = ProfileUpdateForm(None, instance=profile_object)
context["form"] = profile_form
# how can I add User.objects.get(id=request.user.id).email to the custom field
if request.method == 'POST':
profile_form = ProfileUpdateForm(request.POST or None, instance=profile_object)
context["form"] = profile_form
if profile_form.is_valid():
try:
# email address exists
user = User.objects.get(email=profile_form.cleaned_data.get('email'))
messages.error(request, 'Failed profile update. Email address already exists.')
except:
# email address available
# get user object
user = User.objects.get(id=request.user.id)
user.email = profile_form.cleaned_data.get('email')
# update user object
user.save()
profile_form.save()
messages.success(request, 'Successful profile update.')
return render(request, "profile.html", context)
CodePudding user response:
I tend to favour class-based views, and things like this are where they come into their own. The form:
class ProfileUpdateForm(forms.ModelForm):
class Meta:
model = Profile
fields = ('name', 'timezone')
email = forms.EmailField(max_length=254) #add non-model form field
And a class-based view. Handle the initial value for email in get_initial(), and updating of self.request.user in form_valid():
class ProfileUpdateView( UpdateView):
model = Profile
form_class = ProfileUpdateForm
template_name = 'profile.html' # profiles/update_profile.html would be better
# other declarations ...?
def get_initial(self):
initial = super().get_initial()
initial['email'] = self.request.user.email
return initial
# @transaction.atomic might be a good idea
def form_valid(self, form):
new_email = form.cleaned_data['email']
user = self.request.user
if user.email != new_email: # don't do a pointless non-update save
user.email = new_email
user.save()
return super().form_valid( form) # will save the profile
CodePudding user response:
# forms.py
def __init__(self, *args, **kwargs):
self.email = kwargs.pop("email")
super(ProfileUpdateForm, self).__init__(*args, **kwargs)
self.initial['email'] = self.email
# views.py
if request.method == 'GET':
profile_form = ProfileUpdateForm(None, instance=profile_object, email=request.user.email)
context["form"] = profile_form
if request.method == 'POST':
profile_form = ProfileUpdateForm(request.POST or None, instance=profile_object, email=request.POST.get('email'))
context["form"] = profile_form
PS, bookmark Classy Class-based Views, an invaluable resource