I am writing a book database, and ultimately a library system, in Django. When a book is created without a title set, the ISBN will be used to automatically fetch book data from WorldCat I have just created a form to add new books to the database, but it has no real error-handling. Also, as I am new to Django, I suspect I have put a lot of my code in the wrong place.

Improving error-handling is my main incentive, but any other improvements would be welcome.

The form, in forms.py:

class AddBookForm(ModelForm):

    """docstring for AddBookForm"""

    class Meta:
        model = Book
        fields = ['isbn']

The form view, in views.py:

# This defines the navbar
pages = [['Search', '/'], ['Add Book', '/add']]

def add_book(request):
    if request.method == 'POST':
        # create a form instance and populate it with data from the request:
        form = AddBookForm(request.POST)
        # check whether it's valid:
        if form.is_valid():
            # process the data in form.cleaned_data as required
            addedBook = form.save()
    # if a GET (or any other method) we'll create a blank form
        form = AddBookForm()

    # Highlights navbar entry
    context = {'pages': pages, 'form': form,}
    if 'addedBook' in locals():
        context['added'] = addedBook
        context['added'] = None
    return render(request, 'library/add.html', context)

The form template (add.html):

{% extends "library/base_site.html" %}
{% block title %}Add book{% endblock %}
{% block content %}
    {% if added %}
        <div class="alert alert-success" role="alert">
            <button type="button" class="close" data-dismiss="alert">
                <span aria-hidden="true">&times;</span>
                <span class="sr-only">Close</span>
            Succesfully added book "{{ added.title }}" by {{ added.author }} - ISBN {{ added.isbn }}
    {% endif %}
    <form role="form" method="post" action=".">
        {% csrf_token %}
        <div class="form-group">
            <label for="id_isbn">Isbn</label>
            <input id="id_isbn" class="form-control" maxlength="13" name="isbn" type="text" placeholder="Enter ISBN or scan barcode">
        <button type="submit" class="btn btn-default">Submit</button>
{% endblock %}

The entire project is available on GitHub.


1 Answer 1


This is a bit strange, and more complicated than it needs to be:

if 'addedBook' in locals():
    context['added'] = addedBook
    context['added'] = None

You could initialize addedBook = None, and simplify the above, and without using locals():

addedBook = None
# validation, possibly setting: addedBook = form.save()
context['added'] = addedBook

Needless to say, this "docstring" is useless:

"""docstring for AddBookForm"""

Error handling

Your current error handling is merely checking if the form is valid or not. And the form class is very basic, so only the standard validations will be applied, according to the underlying model, for example, non-integer values for an integer field will raise a validation error.

At the minimum, it would be good to tell the user about validation errors, if any. In the current code, if the form was not valid, it simply prints the same form again without giving the user a clue about what went wrong, which is not very user-friendly.

This page in the docs touches on the basics of form validation and includes examples of showing form validation errors:


This page is more detailed, and specific about Model forms:


I recommend you re-read them and:

  1. Add printing of form errors to the HTML output
  2. Add custom validation methods in the form class, if it makes sense for your use case
  • \$\begingroup\$ This is very helpful, thank you. Any ideas on error-handling? \$\endgroup\$
    – felixphew
    Sep 25, 2014 at 7:07
  • \$\begingroup\$ I added a section for that. \$\endgroup\$
    – janos
    Sep 25, 2014 at 7:55

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.