Learn Django

Delete Contact - Full Lesson

The last set of functionality to build is to allow contacts to be deleted. If you refer to the design, if the user clicks the x next to the contact they will be taken to a delete confirmation page. Follow these steps to build this functionality.

So far most of the views in the project have been FBVs, with the home page as the exception. Here, the delete functionality has been built using CBVs to provide you with some experience working with this type of view.

Step 1: Create the Contact CBV Mixin View

The first step is to create the Contact Mixin View. This view is simple - it defines a model to work with and an object name value. The reason why this view is created is so that it can be subclassed by other views, specifically the delete view. If we had other views that need to work with the Contacts model, then we would simply subclass this mixin.

Follow these steps to build the ContactMixin view.

  1. Open the /.../crmeasy/crmapp/contacts/views.py file
  2. Type in this view at the end of the file
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
from django.utils.decorators import method_decorator

class ContactMixin(object):
    model = Contact

    def get_context_data(self, **kwargs):
        kwargs.update({'object_name':'Contact'})
        return kwargs

    @method_decorator(login_required)
    def dispatch(self, *args, **kwargs):
        return super(ContactMixin, self).dispatch(*args, **kwargs)

Code Review

Line 3: This defines the class, gives it the name ContactMixin, and passes the object value.

Line 4: This defines the model attribute, which in this case is the Contact model.

Lines 6-8: This defines the get_context_data method. The purpose of this statement is to give the object_name variable the correct name.

Line 10: This checks to see if the user is logged in. If they aren't the user will be redirected to the login page.

Lines 11-12: This defines the dispatch method, which is required when creating a custom mixin.

Step 2: Create the DeleteContact View

Now it's time to create the view that will actually delete the contact. Follow these steps to do so.

  1. Open the /.../crmeasy/crmapp/contacts/views.py file
  2. Type in this view at the end of the file
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
from django.http import Http404
from django.views.generic.edit import DeleteView

class ContactDelete(ContactMixin, DeleteView):
    template_name = 'object_confirm_delete.html'

    def get_object(self, queryset=None):
        obj = super(ContactDelete, self).get_object()
        if not obj.owner == self.request.user:
            raise Http404
        account = Account.objects.get(id=obj.account.id)
        self.account = account
        return obj

    def get_success_url(self):
        return reverse(
            'crmapp.accounts.views.account_detail',
            args=(self.account.uuid,)
        )

Line 4: This defines the class name, and bases the class on the ContactMixin, and DeleteView mixin. The DeleteView mixin is one of the built-in views that makes it really easy to perform a delete.

Line 5: This defines the template that will be used to confirm the deletion. We're going to give the user a chance to cancel the request before actually performing the delete. Admittedly this isn't very AJAXy - this will be an area of improvement in our next iteration.

Line 7: As previously mentioned, CBVs provide customization hooks. Here we're overriding the get_object() method to complete some custom processing.

Line 8: This sets the obj object which will be required on the return statement.

Lines 9-10: Here we perform a quick check to see if the user is the object owner. If they aren't then we raise a 404 error.

Line 11: The application design specifies that when a user deletes a contact, they are directed back to the Account Detail page. Therefore we need to know what account the contact is related to. That's what this line does - it queries the Account model to find out which one the contact being deleted is/was related to.

Line 12: Here we attach the account object to the instance of this class.

Line 13: The obj object is then returned.

Lines 15-16: The DeleteView CBV has a get_success_url method that specifies the URL to redirect the user to when the object is deleted. Recall, we want to direct the user back to the Account Detail page, so we override this method and return the URL via the reverse method.

Step 3: Create the Object Delete Template

The ContactDelete view defined the object_confirm_delete.html template. We're going to build this template in such a way that it can be used as the confirmation template for any model (hint: it is the same template that will be used in the CommunicationDelete view coming up in the next chapter).

Follow these steps to build this template.

  1. Navigate to the /.../crmeasy/crmapp/templates folder
  2. In this folder create a file named object_confirm_delete.html
  3. Open this file in your IDE and type in the following code
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
{% extends 'base.html' %}
{% block title %}{{object_name}} Confirm delete?{% endblock %}

{% block content %}
    <div id="content-container" class="container p-none">
        <div class="side-p">
            <h3>Are you sure?</h3>
            <p>You're about to delete {{ object }}. Please confirm.</p>
            <form action="" method="post">
                {% csrf_token %}
                <input class="btn btn-link" 
                       type="button" value="Cancel" 
                       onclick="window.history.go(-1);"/>
                <input class="btn btn-danger" type="submit" value="Confirm"/>
            </form>
        </div>
    </div>
{% endblock %}

Code Review

This is a pretty straightforward template that consist of a form that is used to prompt the user on whether they want to delete the object or not. What's cool about this form is that we use generic object references which allows it to be used for multiple delete views.

Step 4: Update Links in Template

Open contact_item_view.html, locate the {# Contact Delete Link #} comment, and update the href attribute.

1
2
3
{# Contact Delete Link #}
<a class="cancel" 
   href="{{ contact.get_delete_url }}?account={{ account.id }}"></a>

Step 5: Add the Delete URL

Open the /.../crmeasy/crmapp/urls.py file and add the /delete/ URL configuration as shown below.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
from contacts.views import ContactDelete

# Contact related URLS
url(r'^contact/new/$',
    'crmapp.contacts.views.contact_cru', name='contact_new'
),
url(r'^contact/(?P<uuid>[\w-]+)/', include(contact_urls)),
url(r'^contact/(?P<pk>[\w-]+)/delete/$',
    ContactDelete.as_view(), name='contact_delete'
),

Step 6: Commit Changes

Execute these commands to commit your changes in Git.

1
2
3
4
5
# add files
(venv)$ git add .

# commit files
(venv)$ git commit -m "enabled delete contact"

Track your progress with a free account