Home > Enterprise >  Populate custom field in Django form
Populate custom field in Django form

Time:11-04

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

  • Related