Allowing users to update and delete their profile

In this tutorial we will leverage Django's modelforms and views to let users update and delete their profile.

July 7, 2020, 10:57 a.m.
Themes: Authentication

We start with a project with a custom user model. Go to forms.py of your app (in our case called userauth). Add the following:

from django.forms import ModelForm

class CustomUserUpdateForm(ModelForm):
    class Meta:
        model = CustomUser
        fields = ['first_name', 'last_name', 'display_name', 'date_of_birth', 'address1', 'address2', 'zip_code', 'city', 'country', 'mobile_phone', 'additional_information', 'photo',]
        widgets = {'date_of_birth': forms.DateInput(attrs={'type':'date'})}

If your model is called different or has different fields, use these. Specify only the fields you need. The widget is a standard Django widget. In views.py add:

from django.views.generic.edit import UpdateView, DeleteView
from django.urls import reverse_lazy
from .models import CustomUser
from .forms import CustomUserUpdateForm

class CustomUserUpdateView(UpdateView):
    model = CustomUser
    form_class = CustomUserUpdateForm


class CustomUserDeleteView(DeleteView):
    model = CustomUser
    success_url = reverse_lazy('account_signup')

UpdateView and DeleteView are standard Django views that do exactly what their name says. The success_url of CustomUserDeleteView is from allauth. Now we have to connect these views to urls and templates. Add the following to your app's urls.py urlpatterns:

path('<int:pk>/update/', CustomUserUpdateView.as_view(template_name='account/update.html'), name='account_update'),
path('<int:pk>/delete/', CustomUserDeleteView.as_view(template_name='account/delete.html'), name='account_delete'),

When calling these urls, we will have to supply an integer parameter pk, which will obviously be the primary key of the user concerned. All that's left to do is creating the templates. We use the same styling as before. The important bit of the delete.html template is:

<form method="post">
    {% csrf_token %}
    <p>{% trans "Are you sure you want to delete the account" %} {{ object.email }}?</p>
    <button type="submit" class="btn btn-danger">{% trans "Delete" %}</button>
</form>

Just submitting the form is enough, Django does the rest. For update.html, the relevant part of the template is (shown in part):

<form method="post" action="{% url 'account_update' request.user.pk %}" enctype="multipart/form-data"  class="needs-validation" novalidate>
    {% csrf_token %}
    <div class="form-group">
        {% with field=form.display_name %}{% include "account/form_field.html" %}{% endwith %}
    </div>
    <div class="form-row">
        <div class="form-group col-md-6">
            {% with field=form.first_name %}{% include "account/form_field.html" %}{% endwith %}
        </div>
        <div class="form-group col-md-6">
            {% with field=form.last_name %}{% include "account/form_field.html" %}{% endwith %}
        </div>
    </div>

<!-- add more fields here -->

   <div class="form-group">
        {% with field=form.photo %}{% include "account/form_field.html" %}{% endwith %}
    </div>
    <button type="submit" class="btn btn-outline-primary">{% trans "Update" %}</button>
</form>

Also add a link at the bottom:

<div class="text-center py-2">
    <small>
        <a href="{% url 'account_delete' request.user.pk %}" class="text-muted">{% trans "Delete your account" %}</a>
    </small>
</div>

The form is submitted to the named url account_update with argument request.user.pk, after which the view takes over. The encoding enctype="multipart/form-data" is added to allow for a photo (ImageField) to be sent.

A logical place to allow users to update their profile is on a profile page. In a previous tutorial we have created one, which contained only first name and last name. Now we can add all other field of the model, by adding lines such as the following to the template:

<div class="row">
    <div class="col border">
        <small>{% trans "E-mail" %}:</small><br>
        {{ request.user.email }}
    </div>
    <div class="col border">
        <small>{% trans "Display name" %}:</small><br>
        {{ request.user.display_name }}
    </div>
</div>

At the bottom, add:

{% block card-footer %}
    <a href="{% url 'account_update' request.user.pk %}">{% trans "Update your account" %}</a>
{% endblock %}

If you haven't defined the block card-footer, just use the link in a relevant template.

Time to try this out. Start up the server, sign in as a user; you will be redirected to your profile page. Click the link at the bottom and update some fields. You can delete your account using the link at the bottom, which brings you back to the signup page.

If you want to know more on how to connect the user's account to his/her social accounts such as Google or LinkedIn for easier login, read on.

Comment on this article (sign in first or confirm by name and email below)