Django Tutorial Part 4: Django admin site - Learn web development

Django Tutorial Part 4: Django admin site
=========================================

* Previous
* Overview: Django
* Next

Now that we've created models for the LocalLibrary website, we'll use the Django Admin site to add some "real" book data. First we'll show you how to register the models with the admin site, then we'll show you how to login and create some data. At the end of the article we will show some of the ways you can further improve the presentation of the Admin site.

|  |  |
| --- | --- |
| Prerequisites: | First complete: Django Tutorial Part 3: Using models. |
| Objective: | To understand the benefits and limitations of the Django admin site, and use it to create some records for our models. |

Overview
--------

The Django admin *application* can use your models to automatically build a site area that you can use to create, view, update, and delete records. This can save you a lot of time during development, making it very easy to test your models and get a feel for whether you have the *right* data. The admin application can also be useful for managing data in production, depending on the type of website. The Django project recommends it only for internal data management (i.e. just for use by admins, or people internal to your organization), as the model-centric approach is not necessarily the best possible interface for all users, and exposes a lot of unnecessary detail about the models.

All the configuration required to include the admin application in your website was done automatically when you created the skeleton project (for information about actual dependencies needed, see the Django docs here). As a result, all you **must** do to add your models to the admin application is to *register* them. At the end of this article we'll provide a brief demonstration of how you might further configure the admin area to better display our model data.

After registering the models we'll show how to create a new "superuser", login to the site, and create some books, authors, book instances, and genres. These will be useful for testing the views and templates we'll start creating in the next tutorial.

Registering models
------------------

First, open **admin.py** in the catalog application (**/locallibrary/catalog/admin.py**). It currently looks like this — note that it already imports `django.contrib.admin`:

```python
from django.contrib import admin

# Register your models here.
```

Register the models by copying the following text into the bottom of the file. This code imports the models and then calls `admin.site.register` to register each of them.

```python
from .models import Author, Genre, Book, BookInstance, Language

admin.site.register(Book)
admin.site.register(Author)
admin.site.register(Genre)
admin.site.register(BookInstance)
admin.site.register(Language)
```

**Note:** The lines above assume that you accepted the challenge to create a model to represent the natural language of a book (see the models tutorial article)!

This is the simplest way of registering a model, or models, with the site. The admin site is highly customizable, and we'll talk more about the other ways of registering your models further down.

Creating a superuser
--------------------

In order to log into the admin site, we need a user account with *Staff* status enabled. In order to view and create records we also need this user to have permissions to manage all our objects. You can create a "superuser" account that has full access to the site and all needed permissions using **manage.py**.

Call the following command, in the same directory as **manage.py**, to create the superuser. You will be prompted to enter a username, email address, and *strong* password.

```bash
python3 manage.py createsuperuser
```

Once this command completes a new superuser will have been added to the database. Now restart the development server so we can test the login:

```bash
python3 manage.py runserver
```

Logging in and using the site
-----------------------------

To login to the site, open the */admin* URL (e.g. `http://127.0.0.1:8000/admin`) and enter your new superuser userid and password credentials (you'll be redirected to the *login* page, and then back to the */admin* URL after you've entered your details).

This part of the site displays all our models, grouped by installed application. You can click on a model name to go to a screen that lists all its associated records, and you can further click on those records to edit them. You can also directly click the **Add** link next to each model to start creating a record of that type.

![Admin Site - Home page](/en-US/docs/Learn/Server-side/Django/Admin_site/admin_home.png)

Click on the **Add** link to the right of *Books* to create a new book (this will display a dialog much like the one below). Note how the titles of each field, the type of widget used, and the `help_text` (if any) match the values you specified in the model.

Enter values for the fields. You can create new authors or genres by pressing the **+** button next to the respective fields (or select existing values from the lists if you've already created them). When you're done you can press **SAVE**, **Save and add another**, or **Save and continue editing** to save the record.

![Admin Site - Book Add](/en-US/docs/Learn/Server-side/Django/Admin_site/admin_book_add.png)

**Note:** At this point we'd like you to spend some time adding a few books, authors, languages, and genres (e.g. Fantasy) to your application. Make sure that each author and genre includes a couple of different books (this will make your list and detail views more interesting when we implement them later on in the article series).

When you've finished adding books, click on the **Home** link in the top bookmark to be taken back to the main admin page. Then click on the **Books** link to display the current list of books (or on one of the other links to see other model lists). Now that you've added a few books, the list might look similar to the screenshot below. The title of each book is displayed; this is the value returned in the Book model's `__str__()` method that we specified in the last article.

![Admin Site - List of book objects](/en-US/docs/Learn/Server-side/Django/Admin_site/admin_book_list.png)

From this list you can delete books by selecting the checkbox next to the book you don't want, selecting the *delete…* action from the *Action* drop-down list, and then pressing the **Go** button. You can also add new books by pressing the **ADD BOOK** button.

You can edit a book by selecting its name in the link. The edit page for a book, shown below, is almost identical to the "Add" page. The main differences are the page title (*Change book*) and the addition of **Delete**, **HISTORY** and **VIEW ON SITE** buttons (this last button appears because we defined the `get_absolute_url()` method in our model).

**Note:** Clicking the **VIEW ON SITE** button raises a `NoReverseMatch` exception because the `get_absolute_url()` method attempts to `reverse()` a named URL mapping ('book-detail') that has not yet been defined.
 We'll define a URL mapping and associated view in Django Tutorial Part 6: Generic list and detail views.

![Admin Site - Book Edit](/en-US/docs/Learn/Server-side/Django/Admin_site/admin_book_modify.png)

Now navigate back to the **Home** page (using the *Home* link in the breadcrumb trail) and then view the **Author** and **Genre** lists — you should already have quite a few created from when you added the new books, but feel free to add some more.

What you won't have is any *Book Instances*, because these are not created from Books (although you can create a `Book` from a `BookInstance` — this is the nature of the `ForeignKey` field). Navigate back to the *Home* page and press the associated **Add** button to display the *Add book instance* screen below. Note the large, globally unique Id, which can be used to separately identify a single copy of a book in the library.

![Admin Site - BookInstance Add](/en-US/docs/Learn/Server-side/Django/Admin_site/admin_bookinstance_add.png)

Create a number of these records for each of your books. Set the status as *Available* for at least some records and *On loan* for others. If the status is **not** *Available*, then also set a future *Due back* date.

That's it! You've now learned how to set up and use the administration site. You've also created records for `Book`, `BookInstance`, `Genre`, `Language` and `Author` that we'll be able to use once we create our own views and templates.

Advanced configuration
----------------------

Django does a pretty good job of creating a basic admin site using the information from the registered models:

* Each model has a list of individual records, identified by the string created with the model's `__str__()` method, and linked to detail views/forms for editing. By default, this view has an action menu at the top that you can use to perform bulk delete operations on records.
* The model detail record forms for editing and adding records contain all the fields in the model, laid out vertically in their declaration order.

You can further customize the interface to make it even easier to use. Some of the things you can do are:

* List views:
    + Add additional fields/information displayed for each record.
    + Add filters to select which records are listed, based on date or some other selection value (e.g. Book loan status).
    + Add additional options to the actions menu in list views and choose where this menu is displayed on the form.
* Detail views
    + Choose which fields to display (or exclude), along with their order, grouping, whether they are editable, the widget used, orientation etc.
    + Add related fields to a record to allow inline editing (e.g. add the ability to add and edit book records while you're creating their author record).

In this section we're going to look at a few changes that will improve the interface for our *LocalLibrary*, including adding more information to `Book` and `Author` model lists, and improving the layout of their edit views. We won't change the `Language` and `Genre` model presentation because they only have one field each, so there is no real benefit in doing so!

You can find a complete reference of all the admin site customization choices in The Django Admin site (Django Docs).

### Register a ModelAdmin class

To change how a model is displayed in the admin interface you define a ModelAdmin class (which describes the layout) and register it with the model.

Let's start with the `Author` model. Open **admin.py** in the catalog application (**/locallibrary/catalog/admin.py**). Comment out your original registration (prefix it with a #) for the `Author` model:

```python
# admin.site.register(Author)
```

Now add a new `AuthorAdmin` and registration as shown below.

```python
# Define the admin class
class AuthorAdmin(admin.ModelAdmin):
    pass

# Register the admin class with the associated model
admin.site.register(Author, AuthorAdmin)
```

Now we'll add `ModelAdmin` classes for `Book`, and `BookInstance`. We again need to comment out the original registrations:

```python
# admin.site.register(Book)
# admin.site.register(BookInstance)
```

Now to create and register the new models; for the purpose of this demonstration, we'll instead use the `@register` decorator to register the models (this does exactly the same thing as the `admin.site.register()` syntax):

```python
# Register the Admin classes for Book using the decorator
@admin.register(Book)
class BookAdmin(admin.ModelAdmin):
    pass

# Register the Admin classes for BookInstance using the decorator
@admin.register(BookInstance)
class BookInstanceAdmin(admin.ModelAdmin):
    pass
```

Currently all of our admin classes are empty (see `pass`) so the admin behavior will be unchanged! We can now extend these to define our model-specific admin behavior.

### Configure list views

The *LocalLibrary* currently lists all authors using the object name generated from the model `__str__()` method. This is fine when you only have a few authors, but once you have many you may end up having duplicates. To differentiate them, or just because you want to show more interesting information about each author, you can use list\_display to add additional fields to the view.

Replace your `AuthorAdmin` class with the code below. The field names to be displayed in the list are declared in a *tuple* in the required order, as shown (these are the same names as specified in your original model).

```python
class AuthorAdmin(admin.ModelAdmin):
    list_display = ('last\_name', 'first\_name', 'date\_of\_birth', 'date\_of\_death')
```

Now navigate to the author list in your website. The fields above should now be displayed, like so:

![Admin Site - Improved Author List](/en-US/docs/Learn/Server-side/Django/Admin_site/admin_improved_author_list.png)

For our `Book` model we'll additionally display the `author` and `genre`. The `author` is a `ForeignKey` field (one-to-many) relationship, and so will be represented by the `__str__()` value for the associated record. Replace the `BookAdmin` class with the version below.

```python
class BookAdmin(admin.ModelAdmin):
    list_display = ('title', 'author', 'display\_genre')
```

Unfortunately we can't directly specify the `genre` field in `list_display` because it is a `ManyToManyField` (Django prevents this because there would be a large database access "cost" in doing so). Instead we'll define a `display_genre` function to get the information as a string (this is the function we've called above; we'll define it below).

**Note:** Getting the `genre` may not be a good idea here, because of the "cost" of the database operation. We're showing you how because calling functions in your models can be very useful for other reasons — for example to add a *Delete* link next to every item in the list.

Add the following code into your `Book` model (**models.py**). This creates a string from the first three values of the `genre` field (if they exist) and creates a `short_description` that can be used in the admin site for this method.

```python
def display\_genre(self):
    """Create a string for the Genre. This is required to display genre in Admin."""
    return ', '.join(genre.name for genre in self.genre.all()[:3])

display_genre.short_description = 'Genre'
```

After saving the model and updated admin, open your website and go to the *Books* list page; you should see a book list like the one below:

![Admin Site - Improved Book List](/en-US/docs/Learn/Server-side/Django/Admin_site/admin_improved_book_list.png)

The `Genre` model (and the `Language` model, if you defined one) both have a single field, so there is no point creating an additional model for them to display additional fields.

**Note:** It is worth updating the `BookInstance` model list to show at least the status and the expected return date. We've added that as a challenge at the end of this article!

### Add list filters

 Once you've got a lot of items in a list, it can be useful to be able to filter which items are displayed.
 This is done by listing fields in the `list_filter` attribute.
 Replace your current `BookInstanceAdmin` class with the code fragment below.

```python
class BookInstanceAdmin(admin.ModelAdmin):
    list_filter = ('status', 'due\_back')
```

The list view will now include a filter box to the right. Note how you can choose dates and status to filter the values:

![Admin Site - BookInstance List Filters](/en-US/docs/Learn/Server-side/Django/Admin_site/admin_improved_bookinstance_list_filters.png)

### Organize detail view layout

By default, the detail views lay out all fields vertically, in their order of declaration in the model. You can change the order of declaration, which fields are displayed (or excluded), whether sections are used to organize the information, whether fields are displayed horizontally or vertically, and even what edit widgets are used in the admin forms.

**Note:** The *LocalLibrary* models are relatively simple so there isn't a huge need for us to change the layout; we'll make some changes anyway however, just to show you how.

#### Controlling which fields are displayed and laid out

Update your `AuthorAdmin` class to add the `fields` line, as shown below:

```python
class AuthorAdmin(admin.ModelAdmin):
    list_display = ('last\_name', 'first\_name', 'date\_of\_birth', 'date\_of\_death')

    fields = ['first\_name', 'last\_name', ('date\_of\_birth', 'date\_of\_death')]
```

The `fields` attribute lists just those fields that are to be displayed on the form, in order. Fields are displayed vertically by default, but will display horizontally if you further group them in a tuple (as shown in the "date" fields above).

In your website go to the author detail view — it should now appear as shown below:

![Admin Site - Improved Author Detail](/en-US/docs/Learn/Server-side/Django/Admin_site/admin_improved_author_detail.png)

**Note:** You can also use the `exclude` attribute to declare a list of attributes to be excluded from the form (all other attributes in the model will be displayed).

#### Sectioning the detail view

You can add "sections" to group related model information within the detail form, using the fieldsets attribute.

In the `BookInstance` model we have information related to what the book is (i.e. `name`, `imprint`, and `id`) and when it will be available (`status`, `due_back`). We can add these to our `BookInstanceAdmin` class as shown below, using the `fieldsets` property.

```python
@admin.register(BookInstance)
class BookInstanceAdmin(admin.ModelAdmin):
    list_filter = ('status', 'due\_back')

    fieldsets = (
        (None, {
            'fields': ('book', 'imprint', 'id')
        }),
        ('Availability', {
            'fields': ('status', 'due\_back')
        }),
    )
```

Each section has its own title (or `None`, if you don't want a title) and an associated tuple of fields in a dictionary — the format is complicated to describe, but fairly easy to understand if you look at the code fragment immediately above.

Now navigate to a book instance view in your website; the form should appear as shown below:

![Admin Site - Improved BookInstance Detail with sections](/en-US/docs/Learn/Server-side/Django/Admin_site/admin_improved_bookinstance_detail_sections.png)

### Inline editing of associated records

Sometimes it can make sense to be able to add associated records at the same time. For example, it may make sense to have both the book information and information about the specific copies you've got on the same detail page.

You can do this by declaring inlines, of type TabularInline (horizontal layout) or StackedInline (vertical layout, just like the default model layout). You can add the `BookInstance` information inline to our `Book` detail by specifying `inlines` in your `BookAdmin`:

```python
class BooksInstanceInline(admin.TabularInline):
    model = BookInstance

@admin.register(Book)
class BookAdmin(admin.ModelAdmin):
    list_display = ('title', 'author', 'display\_genre')

    inlines = [BooksInstanceInline]
```

Now navigate to a view for a `Book` in your website — at the bottom you should now see the book instances relating to this book (immediately below the book's genre fields):

![Admin Site - Book with Inlines](/en-US/docs/Learn/Server-side/Django/Admin_site/admin_improved_book_detail_inlines.png)

In this case all we've done is declare our tabular inline class, which just adds all fields from the *inlined* model. You can specify all sorts of additional information for the layout, including the fields to display, their order, whether they are read only or not, etc. (see TabularInline for more information).

**Note:** There are some painful limits in this functionality! In the screenshot above we have three existing book instances, followed by three placeholders for new book instances (which look very similar!). It would be better to have NO spare book instances by default and just add them with the **Add another Book instance** link, or to be able to just list the `BookInstance`s as non-readable links from here. The first option can be done by setting the `extra` attribute to `0` in `BooksInstanceInline` model, try it by yourself.

Challenge yourself
------------------

We've learned a lot in this section, so now it is time for you to try a few things.

1. For the `BookInstance` list view, add code to display the book, status, due back date, and id (rather than the default `__str__()` text).
2. Add an inline listing of `Book` items to the `Author` detail view using the same approach as we did for `Book`/`BookInstance`.
Summary
-------

That's it! You've now learned how to set up the administration site in both its simplest and improved form, how to create a superuser, and how to navigate the admin site and view, delete, and update records. Along the way you've created a bunch of Books, BookInstances, Genres, and Authors that we'll be able to list and display once we create our own view and templates.

Further reading
---------------

* Writing your first Django app, part 2: Introducing the Django Admin (Django docs)
* The Django Admin site (Django Docs)
* Previous
* Overview: Django
* Next


Django Tutorial Part 5: Creating our home page - Learn web development

Django Tutorial Part 5: Creating our home page
==============================================

* Previous
* Overview: Django
* Next

We're now ready to add the code that displays our first complete page — a home page for the LocalLibrary website. The home page will show the number of records we have for each model type and provide sidebar navigation links to our other pages. Along the way we'll gain practical experience in writing basic URL maps and views, getting records from the database, and using templates.

|  |  |
| --- | --- |
| Prerequisites: | Read the Django Introduction. Complete previous tutorial topics (including Django Tutorial Part 4: Django admin site). |
| Objective: | Learn to create simple URL maps and views (where no data is encoded in the URL), get data from models, and create templates. |

Overview
--------

After we defined our models and created some initial library records to work with, it's time to write the code that presents that information to users. The first thing we need to do is determine what information we want to display in our pages, and define the URLs to use for returning those resources. Then we'll create a URL mapper, views, and templates to display the pages.

The following diagram describes the main data flow, and the components required when handling HTTP requests and responses. As we already implemented the model, the main components we'll create are:

* URL mappers to forward the supported URLs (and any information encoded in the URLs) to the appropriate view functions.
* View functions to get the requested data from the models, create HTML pages that display the data, and return the pages to the user to view in the browser.
* Templates to use when rendering data in the views.

![Main data flow diagram: URL, Model, View & Template component required when handling HTTP requests and responses in a Django application. A HTTP request hits a Django server gets forwarded to the 'urls.py' file of the URLS component. The request is forwarded to the appropriate view. The view can read and write data from the Models 'models.py' file containing the code related to models. The view also accesses the HTML file template component. The view returns the response back to the user.](/en-US/docs/Learn/Server-side/Django/Home_page/basic-django.png)

As you'll see in the next section, we have 5 pages to display, which is too much information to document in a single article. Therefore, this article will focus on how to implement the home page, and we'll cover the other pages in a subsequent article. This should give you a good end-to-end understanding of how URL mappers, views, and models work in practice.

Defining the resource URLs
--------------------------

As this version of LocalLibrary is essentially read-only for end users, we just need to provide a landing page for the site (a home page), and pages that *display* list and detail views for books and authors.

The URLs that we'll need for our pages are:

* `catalog/` — The home (index) page.
* `catalog/books/` — A list of all books.
* `catalog/authors/` — A list of all authors.
* `catalog/book/<id>` — The detail view for a particular book, with a field primary key of `<id>` (the default). For example, the URL for the third book added to the list will be `/catalog/book/3`.
* `catalog/author/<id>` — The detail view for the specific author with a primary key field of `<id>`. For example, the URL for the 11th author added to the list will be `/catalog/author/11`.

The first three URLs will return the index page, books list, and authors list. These URLs do not encode any additional information, and the queries that fetch data from the database will always be the same. However, the results that the queries return will depend on the contents of the database.

By contrast the final two URLs will display detailed information about a specific book or author. These URLs encode the identity of the item to display (represented by `<id>` above). The URL mapper will extract the encoded information and pass it to the view, and the view will dynamically determine what information to get from the database. By encoding the information in the URL we will use a single set of a URL mapping, a view, and a template to handle all books (or authors).

**Note:** With Django, you can construct your URLs however you require — you can encode information in the body of the URL as shown above, or include `GET` parameters in the URL, for example `/book/?id=6`. Whichever approach you use, the URLs should be kept clean, logical, and readable, as recommended by the W3C.
 The Django documentation recommends encoding information in the body of the URL to achieve better URL design.

As mentioned in the overview, the rest of this article describes how to construct the index page.

Creating the index page
-----------------------

The first page we'll create is the index page (`catalog/`). The index page will include some static HTML, along with generated "counts" of different records in the database. To make this work we'll create a URL mapping, a view, and a template.

**Note:** It's worth paying a little extra attention in this section. Most of the information also applies to the other pages we'll create.

### URL mapping

When we created the skeleton website, we updated the **locallibrary/urls.py** file to ensure that whenever a URL that starts with `catalog/` is received, the *URLConf* module `catalog.urls` will process the remaining substring.

The following code snippet from **locallibrary/urls.py** includes the `catalog.urls` module:

```python
urlpatterns += [
    path('catalog/', include('catalog.urls')),
]
```

**Note:** Whenever Django encounters the import function `django.urls.include()`, it splits the URL string at the designated end character and sends the remaining substring to the included *URLconf* module for further processing.

 We also created a placeholder file for the *URLConf* module, named **/catalog/urls.py**.
 Add the following lines to that file:

```python
urlpatterns = [
    path('', views.index, name='index'),
]
```

The `path()` function defines the following:

* A URL pattern, which is an empty string: `''`. We'll discuss URL patterns in detail when working on the other views.
* A view function that will be called if the URL pattern is detected: `views.index`, which is the function named `index()` in the **views.py** file.

 The `path()` function also specifies a `name` parameter, which is a unique identifier for *this* particular URL mapping. You can use the name to "reverse" the mapper, i.e. to dynamically create a URL that points to the resource that the mapper is designed to handle.
 For example, we can use the name parameter to link to our home page from any other page by adding the following link in a template:

```django
<a href="{% url 'index' %}">Home</a>.
```

**Note:** We can hard code the link as in `<a href="/catalog/">Home</a>`), but if we change the pattern for our home page, for example, to `/catalog/index`) the templates will no longer link correctly. Using a reversed URL mapping is more robust.

### View (function-based)

A view is a function that processes an HTTP request, fetches the required data from the database, renders the data in an HTML page using an HTML template, and then returns the generated HTML in an HTTP response to display the page to the user. The index view follows this model — it fetches information about the number of `Book`, `BookInstance`, available `BookInstance` and `Author` records that we have in the database, and passes that information to a template for display.

Open **catalog/views.py** and note that the file already imports the render() shortcut function to generate an HTML file using a template and data:

```python
from django.shortcuts import render

# Create your views here.
```

Paste the following lines at the bottom of the file:

```python
from .models import Book, Author, BookInstance, Genre

def index(request):
    """View function for home page of site."""

    # Generate counts of some of the main objects
    num_books = Book.objects.all().count()
    num_instances = BookInstance.objects.all().count()

    # Available books (status = 'a')
    num_instances_available = BookInstance.objects.filter(status__exact='a').count()

    # The 'all()' is implied by default.
    num_authors = Author.objects.count()

    context = {
        'num\_books': num_books,
        'num\_instances': num_instances,
        'num\_instances\_available': num_instances_available,
        'num\_authors': num_authors,
    }

    # Render the HTML template index.html with the data in the context variable
    return render(request, 'index.html', context=context)
```

The first line imports the model classes that we'll use to access data in all our views.

The first part of the view function fetches the number of records using the `objects.all()` attribute on the model classes. It also gets a list of `BookInstance` objects that have a value of 'a' (Available) in the status field. You can find more information about how to access model data in our previous tutorial Django Tutorial Part 3: Using models > Searching for records.

At the end of the view function we call the `render()` function to create an HTML page and return the page as a response. This shortcut function wraps a number of other functions to simplify a very common use case. The `render()` function accepts the following parameters:

* the original `request` object, which is an `HttpRequest`.
* an HTML template with placeholders for the data.
* a `context` variable, which is a Python dictionary, containing the data to insert into the placeholders.

We'll talk more about templates and the `context` variable in the next section. Let's get to creating our template so we can actually display something to the user!

### Template

A template is a text file that defines the structure or layout of a file (such as an HTML page), it uses placeholders to represent actual content.

A Django application created using **startapp** (like the skeleton of this example) will look for templates in a subdirectory named '**templates**' of your applications. For example, in the index view that we just added, the `render()` function will expect to find the file ***index.html*** in **/locallibrary/catalog/templates/** and will raise an error if the file is not present.

You can check this by saving the previous changes and accessing `127.0.0.1:8000` in your browser - it will display a fairly intuitive error message: "`TemplateDoesNotExist at /catalog/`", and other details.

**Note:** Based on your project's settings file, Django will look for templates in a number of places, searching in your installed applications by default. You can find out more about how Django finds templates and what template formats it supports in the Templates section of the Django documentation.

#### Extending templates

The index template will need standard HTML markup for the head and body, along with navigation sections to link to the other pages of the site (which we haven't created yet), and to sections that display introductory text and book data.

Much of the HTML and navigation structure will be the same in every page of our site. Instead of duplicating boilerplate code on every page, you can use the Django templating language to declare a base template, and then extend it to replace just the bits that are different for each specific page.

 The following code snippet is a sample base template from a **base\_generic.html** file.
 We'll be creating the template for LocalLibrary shortly.
 The sample below includes common HTML with sections for a title, a sidebar, and main contents marked with the named `block` and `endblock` template tags.
 You can leave the blocks empty, or include default content to use when rendering pages derived from the template.

**Note:** Template *tags* are functions that you can use in a template to loop through lists, perform conditional operations based on the value of a variable, and so on. In addition to template tags, the template syntax allows you to reference variables that are passed into the template from the view, and use *template filters* to format variables (for example, to convert a string to lower case).

```django
<!DOCTYPE html>
<html lang="en">
  <head>
    {% block title %}
      <title>Local Library</title>
    {% endblock %}
  </head>
  <body>
    {% block sidebar %}
      <!-- insert default navigation text for every page -->
    {% endblock %}
    {% block content %}
      <!-- default content text (typically empty) -->
    {% endblock %}
  </body>
</html>
```

When defining a template for a particular view, we first specify the base template using the `extends` template tag — see the code sample below. Then we declare what sections from the template we want to replace (if any), using `block`/`endblock` sections as in the base template.

For example, the code snippet below shows how to use the `extends` template tag and override the `content` block. The generated HTML will include the code and structure defined in the base template, including the default content you defined in the `title` block, but the new `content` block in place of the default one.

```django
{% extends "base\_generic.html" %}

{% block content %}
  <h1>Local Library Home</h1>
  <p>
    Welcome to LocalLibrary, a website developed by
    <em>Mozilla Developer Network</em>!
  </p>
{% endblock %}
```

#### The LocalLibrary base template

We will use the following code snippet as the base template for the *LocalLibrary* website. As you can see, it contains some HTML code and defines blocks for `title`, `sidebar`, and `content`. We have a default title and a default sidebar with links to lists of all books and authors, both enclosed in blocks to be easily changed in the future.

**Note:** We also introduce two additional template tags: `url` and `load static`. These tags will be explained in following sections.

Create a new file **base\_generic.html** in **/locallibrary/catalog/templates/** and paste the following code to the file:

```django
<!DOCTYPE html>
<html lang="en">
  <head>
    {% block title %}
      <title>Local Library</title>
    {% endblock %}
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css"
 rel="stylesheet"
 integrity="sha384-T3c6CoIi6uLrA9TneNEoa7RxnatzjcDSCmG1MXxSR1GAsXEV/Dwwykc2MPK8M2HN"
 crossorigin="anonymous">
    <!-- Add additional CSS in static file -->
    {% load static %}
    <link rel="stylesheet" href="{% static 'css/styles.css' %}" />
  </head>
  <body>
    <div class="container-fluid">
      <div class="row">
        <div class="col-sm-2">
          {% block sidebar %}
            <ul class="sidebar-nav">
              <li><a href="{% url 'index' %}">Home</a></li>
              <li><a href="">All books</a></li>
              <li><a href="">All authors</a></li>
            </ul>
          {% endblock %}
        </div>
        <div class="col-sm-10 ">{% block content %}{% endblock %}</div>
      </div>
    </div>
  </body>
</html>
```

The template includes CSS from Bootstrap to improve the layout and presentation of the HTML page. Using Bootstrap (or another client-side web framework) is a quick way to create an attractive page that displays well on different screen sizes.

The base template also references a local CSS file (**styles.css**) that provides additional styling. Create a **styles.css** file in **/locallibrary/catalog/static/css/** and paste the following code in the file:

```css
.sidebar-nav {
  margin-top: 20px;
  padding: 0;
  list-style: none;
}
```

#### The index template

 Create a new HTML file **index.html** in **/locallibrary/catalog/templates/** and paste the following code in the file.
 This code extends our base template on the first line, and then replaces the default `content` block for the template.

```django
{% extends "base\_generic.html" %}

{% block content %}
  <h1>Local Library Home</h1>
  <p>
    Welcome to LocalLibrary, a website developed by
    <em>Mozilla Developer Network</em>!
  </p>
  <h2>Dynamic content</h2>
  <p>The library has the following record counts:</p>
  <ul>
    <li><strong>Books:</strong> {{ num\_books }}</li>
    <li><strong>Copies:</strong> {{ num\_instances }}</li>
    <li><strong>Copies available:</strong> {{ num\_instances\_available }}</li>
    <li><strong>Authors:</strong> {{ num\_authors }}</li>
  </ul>
{% endblock %}
```

 In the *Dynamic content* section we declare placeholders (*template variables*) for the information from the view that we want to include.
 The variables are enclosed with double brace (handlebars).

**Note:** You can easily recognize template variables and template tags (functions) - variables are enclosed in double braces (`{{ num_books }}`), and tags are enclosed in single braces with percentage signs (`{% extends "base_generic.html" %}`).

 The important thing to note here is that variables are named with the *keys* that we pass into the `context` dictionary in the `render()` function of our view (see sample below).
 Variables will be replaced with their associated *values* when the template is rendered.

```python
context = {
    'num\_books': num_books,
    'num\_instances': num_instances,
    'num\_instances\_available': num_instances_available,
    'num\_authors': num_authors,
}

return render(request, 'index.html', context=context)
```

#### Referencing static files in templates

Your project is likely to use static resources, including JavaScript, CSS, and images. Because the location of these files might not be known (or might change), Django allows you to specify the location in your templates relative to the `STATIC_URL` global setting. The default skeleton website sets the value of `STATIC_URL` to '`/static/`', but you might choose to host these on a content delivery network or elsewhere.

Within the template you first call the `load` template tag specifying "static" to add the template library, as shown in the code sample below. You can then use the `static` template tag and specify the relative URL to the required file.

```django
<!-- Add additional CSS in static file -->
{% load static %}
<link rel="stylesheet" href="{% static 'css/styles.css' %}" />
```

You can add an image into the page in a similar way, for example:

```django
{% load static %}
<img
 src="{% static 'catalog/images/local\_library\_model\_uml.png' %}"
 alt="UML diagram"
 style="width:555px;height:540px;" />
```

**Note:** The samples above specify where the files are located, but Django does not serve them by default. We configured the development web server to serve files by modifying the global URL mapper (**/locallibrary/locallibrary/urls.py**) when we created the website skeleton, but still need to enable file serving in production. We'll look at this later.

For more information on working with static files see Managing static files in the Django documentation.

#### Linking to URLs

The base template above introduced the `url` template tag.

```django
<li><a href="{% url 'index' %}">Home</a></li>
```

This tag accepts the name of a `path()` function called in your **urls.py** and the values for any arguments that the associated view will receive from that function, and returns a URL that you can use to link to the resource.

#### Configuring where to find the templates

 The location where Django searches for templates is specified in the `TEMPLATES` object in the **settings.py** file.
 The default **settings.py** (as created for this tutorial) looks something like this:

```python
TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': [],
        'APP\_DIRS': True,
        'OPTIONS': {
            'context\_processors': [
                'django.template.context\_processors.debug',
                'django.template.context\_processors.request',
                'django.contrib.auth.context\_processors.auth',
                'django.contrib.messages.context\_processors.messages',
            ],
        },
    },
]
```

The setting of `'APP_DIRS': True`, is the most important, as it tells Django to search for templates in a subdirectory of each application in the project, named "templates" (this makes it easier to group templates with their associated application for easy re-use).

We can also specify specific locations for Django to search for directories using `'DIRS': []` (but that isn't needed yet).

**Note:** You can find out more about how Django finds templates and what template formats it supports in the Templates section of the Django documentation.

What does it look like?
-----------------------

At this point we have created all required resources to display the index page. Run the server (`python3 manage.py runserver`) and open `http://127.0.0.1:8000/` in your browser. If everything is configured correctly, your site should look like the following screenshot.

![Index page for LocalLibrary website](/en-US/docs/Learn/Server-side/Django/Home_page/index_page_ok.png)

**Note:** The **All books** and **All authors** links will not work yet because the paths, views, and templates for those pages are not defined. We just inserted placeholders for those links in the `base_generic.html` template.

Challenge yourself
------------------

Here are a couple of tasks to test your familiarity with model queries, views, and templates.

1. The LocalLibrary base template includes a `title` block. Override this block in the index template and create a new title for the page.

**Note:** The section Extending templates explains how to create blocks and extend a block in another template.
2. Modify the view to generate counts for *genres* and *books* that contain a particular word (case insensitive), and pass the results to the `context`. You accomplish this in a similar way to creating and using `num_books` and `num_instances_available`. Then update the index template to include these variables.
Summary
-------

We just created the home page for our site — an HTML page that displays a number of records from the database and links to other yet-to-be-created pages. Along the way we learned fundamental information about URL mappers, views, querying the database with models, passing information to a template from a view, and creating and extending templates.

In the next article we'll build upon this knowledge to create the remaining four pages of our website.

See also
--------

* Writing your first Django app, part 3: Views and Templates (Django docs)
* URL dispatcher (Django docs)
* View functions (DJango docs)
* Templates (Django docs)
* Managing static files (Django docs)
* Django shortcut functions (Django docs)
* Previous
* Overview: Django
* Next


Django web application security - Learn web development

Django web application security
===============================

* Previous
* Overview: Django
* Next

Protecting user data is an essential part of any website design. We previously explained some of the more common security threats in the article Web security — this article provides a practical demonstration of how Django's in-built protections handle such threats.

|  |  |
| --- | --- |
| Prerequisites: |
 Read the Server-side programming "Website security" topic.
 Complete the Django tutorial topics up to (and including) at least Django Tutorial Part 9: Working with forms.
  |
| Objective: | To understand the main things you need to do (or not do) to secure your Django web application. |

Overview
--------

The Website security topic provides an overview of what website security means for server-side design, and some of the more common threats that you should protect against. One of the key messages in that article is that almost all attacks are successful when the web application trusts data from the browser.

**Warning:** The single most important lesson you can learn about website security is to **never trust data from the browser**. This includes `GET` request data in URL parameters, `POST` data, HTTP headers and cookies, user-uploaded files, etc. Always check and sanitize all incoming data. Always assume the worst.

The good news for Django users is that many of the more common threats are handled by the framework! The Security in Django (Django docs) article explains Django's security features and how to secure a Django-powered website.

Common threats/protections
--------------------------

Rather than duplicate the Django documentation here, in this article we'll demonstrate just a few of the security features in the context of our Django LocalLibrary tutorial.

### Cross site scripting (XSS)

XSS is a term used to describe a class of attacks that allow an attacker to inject client-side scripts *through* the website into the browsers of other users. This is usually achieved by storing malicious scripts in the database where they can be retrieved and displayed to other users, or by getting users to click a link that will cause the attacker's JavaScript to be executed by the user's browser.

Django's template system protects you against the majority of XSS attacks by escaping specific characters that are "dangerous" in HTML. We can demonstrate this by attempting to inject some JavaScript into our LocalLibrary website using the Create-author form we set up in Django Tutorial Part 9: Working with forms.

1. Start the website using the development server (`python3 manage.py runserver`).
2. Open the site in your local browser and login to your superuser account.
3. Navigate to the author-creation page (which should be at URL: `http://127.0.0.1:8000/catalog/author/create/`).
4. Enter names and date details for a new user, and then append the following text to the Last Name field:
 `<script>alert('Test alert');</script>`.

 ![Author Form XSS test](/en-US/docs/Learn/Server-side/Django/web_application_security/author_create_form_alert_xss.png)

**Note:** This is a harmless script that, if executed, will display an alert box in your browser. If the alert is displayed when you submit the record then the site is vulnerable to XSS threats.
5. Press **Submit** to save the record.
6. When you save the author it will be displayed as shown below. Because of the XSS protections the `alert()` should not be run. Instead the script is displayed as plain text.

 ![Author detail view XSS test](/en-US/docs/Learn/Server-side/Django/web_application_security/author_detail_alert_xss.png)

If you view the page HTML source code, you can see that the dangerous characters for the script tags have been turned into their harmless escape code equivalents (for example, `>` is now `>`)

```html
<h1>
  Author: Boon<script>alert('Test alert');</script>, David
  (Boonie)
</h1>
```

Using Django templates protects you against the majority of XSS attacks. However it is possible to turn off this protection, and the protection isn't automatically applied to all tags that wouldn't normally be populated by user input (for example, the `help_text` in a form field is usually not user-supplied, so Django doesn't escape those values).

It is also possible for XSS attacks to originate from other untrusted source of data, such as cookies, Web services or uploaded files (whenever the data is not sufficiently sanitized before including in a page). If you're displaying data from these sources, then you may need to add your own sanitization code.

### Cross site request forgery (CSRF) protection

CSRF attacks allow a malicious user to execute actions using the credentials of another user without that user's knowledge or consent. For example consider the case where we have a hacker who wants to create additional authors for our LocalLibrary.

**Note:** Obviously our hacker isn't in this for the money! A more ambitious hacker could use the same approach on other sites to perform much more harmful tasks (such as transferring money to their own accounts, and so on.)

 In order to do this, they might create an HTML file like the one below, which contains an author-creation form (like the one we used in the previous section) that is submitted as soon as the file is loaded.
 They would then send the file to all the Librarians and suggest that they open the file (it contains some harmless information, honest!). If the file is opened by any logged in librarian, then the form would be submitted with their credentials and a new author would be created.

```html
<html lang="en">
  <body onload="document.EvilForm.submit()">
    <form
 action="http://127.0.0.1:8000/catalog/author/create/"
 method="post"
 name="EvilForm">
      <table>
        <tr>
          <th><label for="id\_first\_name">First name:</label></th>
          <td>
            <input
 id="id\_first\_name"
 maxlength="100"
 name="first\_name"
 type="text"
 value="Mad"
 required />
          </td>
        </tr>
        <tr>
          <th><label for="id\_last\_name">Last name:</label></th>
          <td>
            <input
 id="id\_last\_name"
 maxlength="100"
 name="last\_name"
 type="text"
 value="Man"
 required />
          </td>
        </tr>
        <tr>
          <th><label for="id\_date\_of\_birth">Date of birth:</label></th>
          <td>
            <input id="id\_date\_of\_birth" name="date\_of\_birth" type="text" />
          </td>
        </tr>
        <tr>
          <th><label for="id\_date\_of\_death">Died:</label></th>
          <td>
            <input
 id="id\_date\_of\_death"
 name="date\_of\_death"
 type="text"
 value="12/10/2016" />
          </td>
        </tr>
      </table>
      <input type="submit" value="Submit" />
    </form>
  </body>
</html>
```

Run the development web server, and log in with your superuser account. Copy the text above into a file and then open it in the browser. You should get a CSRF error, because Django has protection against this kind of thing!

The way the protection is enabled is that you include the `{% csrf_token %}` template tag in your form definition. This token is then rendered in your HTML as shown below, with a value that is specific to the user on the current browser.

```html
<input
 type="hidden"
 name="csrfmiddlewaretoken"
 value="0QRWHnYVg776y2l66mcvZqp8alrv4lb8S8lZ4ZJUWGZFA5VHrVfL2mpH29YZ39PW" />
```

Django generates a user/browser specific key and will reject forms that do not contain the field, or that contain an incorrect field value for the user/browser.

To use this type of attack the hacker now has to discover and include the CSRF key for the specific target user. They also can't use the "scattergun" approach of sending a malicious file to all librarians and hoping that one of them will open it, since the CSRF key is browser specific.

Django's CSRF protection is turned on by default. You should always use the `{% csrf_token %}` template tag in your forms and use `POST` for requests that might change or add data to the database.

### Other protections

Django also provides other forms of protection (most of which would be hard or not particularly useful to demonstrate):

SQL injection protection

SQL injection vulnerabilities enable malicious users to execute arbitrary SQL code on a database, allowing data to be accessed, modified, or deleted irrespective of the user's permissions. In almost every case you'll be accessing the database using Django's querysets/models, so the resulting SQL will be properly escaped by the underlying database driver. If you do need to write raw queries or custom SQL then you'll need to explicitly think about preventing SQL injection.

Clickjacking protection

In this attack a malicious user hijacks clicks meant for a visible top level site and routes them to a hidden page beneath. This technique might be used, for example, to display a legitimate bank site but capture the login credentials in an invisible `<iframe>` controlled by the attacker. Django contains clickjacking protection in the form of the `X-Frame-Options middleware` which, in a supporting browser, can prevent a site from being rendered inside a frame.

Enforcing TLS/HTTPS

TLS/HTTPS can be enabled on the web server in order to encrypt all traffic between the site and browser, including authentication credentials that would otherwise be sent in plain text (enabling HTTPS is highly recommended). If HTTPS is enabled then Django provides a number of other protections you can use:

* `SECURE_PROXY_SSL_HEADER` can be used to check whether content is secure, even if it is incoming from a non-HTTP proxy.
* `SECURE_SSL_REDIRECT` is used to redirect all HTTP requests to HTTPS.
* Use HTTP Strict Transport Security (HSTS). This is an HTTP header that informs a browser that all future connections to a particular site should always use HTTPS. Combined with redirecting HTTP requests to HTTPS, this setting ensures that HTTPS is always used after a successful connection has occurred. HSTS may either be configured with `SECURE_HSTS_SECONDS` and `SECURE_HSTS_INCLUDE_SUBDOMAINS` or on the Web server.
* Use 'secure' cookies by setting `SESSION_COOKIE_SECURE` and `CSRF_COOKIE_SECURE` to `True`. This will ensure that cookies are only ever sent over HTTPS.

Host header validation

Use `ALLOWED_HOSTS` to only accept requests from trusted hosts.

There are many other protections, and caveats to the usage of the above mechanisms. While we hope that this has given you an overview of what Django offers, you should still read the Django security documentation.

Summary
-------

Django has effective protections against a number of common threats, including XSS and CSRF attacks. In this article we've demonstrated how those particular threats are handled by Django in our *LocalLibrary* website. We've also provided a brief overview of some of the other protections.

This has been a very brief foray into web security. We strongly recommend that you read Security in Django to gain a deeper understanding.

The next and final step in this module about Django is to complete the assessment task.

See also
--------

* Security in Django (Django docs)
* Server side website security (MDN)
* Securing your site (MDN)
* Previous
* Overview: Django
* Next