Django Tutorial Part 7: Sessions framework - Learn web development

Django Tutorial Part 7: Sessions framework
==========================================

* Previous
* Overview: Django
* Next

 This tutorial extends our LocalLibrary website, adding a session-based visit-counter to the home page.
 This is a relatively simple example, but it does show how you can use the session framework to provide persistent behavior for anonymous users in your own sites.

|  |  |
| --- | --- |
| Prerequisites: | Complete all previous tutorial topics, including Django Tutorial Part 6: Generic list and detail views |
| Objective: | To understand how sessions are used. |

Overview
--------

The LocalLibrary website we created in the previous tutorials allows users to browse books and authors in the catalog. While the content is dynamically generated from the database, every user will essentially have access to the same pages and types of information when they use the site.

 In a "real" library you may wish to provide individual users with a customized experience, based on their previous use of the site, preferences, etc.
 For example, you could hide warning messages that the user has previously acknowledged next time they visit the site, or store and respect their preferences (such as, the number of search results that they want to be displayed on each page).

The session framework lets you implement this sort of behavior, allowing you to store and retrieve arbitrary data on a per-site-visitor basis.

What are sessions?
------------------

All communication between web browsers and servers is via HTTP, which is *stateless*. The fact that the protocol is stateless means that messages between the client and server are completely independent of each other — there is no notion of "sequence" or behavior based on previous messages. As a result, if you want to have a site that keeps track of the ongoing relationships with a client, you need to implement that yourself.

Sessions are the mechanism used by Django (and most of the Internet) for keeping track of the "state" between the site and a particular browser. Sessions allow you to store arbitrary data per browser, and have this data available to the site whenever the browser connects. Individual data items associated with the session are then referenced by a "key", which is used both to store and retrieve the data.

Django uses a cookie containing a special *session id* to identify each browser and its associated session with the site. The actual session *data* is stored in the site database by default (this is more secure than storing the data in a cookie, where they are more vulnerable to malicious users). You can configure Django to store the session data in other places (cache, files, "secure" cookies), but the default location is a good and relatively secure option.

Enabling sessions
-----------------

Sessions were enabled automatically when we created the skeleton website (in tutorial 2).

The configuration is set up in the `INSTALLED_APPS` and `MIDDLEWARE` sections of the project file (**locallibrary/locallibrary/settings.py**), as shown below:

```python
INSTALLED_APPS = [
    # …
    'django.contrib.sessions',
    # …

MIDDLEWARE = [
    # …
    'django.contrib.sessions.middleware.SessionMiddleware',
    # …
```

Using sessions
--------------

 You can access the `session` attribute within a view from the `request` parameter (an `HttpRequest` passed in as the first argument to the view).
 This session attribute represents the specific connection to the current user (or to be more precise, the connection to the current *browser*, as identified by the session id in the browser's cookie for this site).

The `session` attribute is a dictionary-like object that you can read and write as many times as you like in your view, modifying it as wished. You can do all the normal dictionary operations, including clearing all data, testing if a key is present, looping through data, etc. Most of the time though, you'll just use the standard "dictionary" API to get and set values.

The code fragments below show how you can get, set, and delete some data with the key "`my_car`", associated with the current session (browser).

**Note:** One of the great things about Django is that you don't need to think about the mechanisms that tie the session to your current request in your view. If we were to use the fragments below in our view, we'd know that the information about `my_car` is associated only with the browser that sent the current request.

```python
# Get a session value by its key (e.g. 'my\_car'), raising a KeyError if the key is not present
my_car = request.session['my\_car']

# Get a session value, setting a default if it is not present ('mini')
my_car = request.session.get('my\_car', 'mini')

# Set a session value
request.session['my\_car'] = 'mini'

# Delete a session value
del request.session['my\_car']
```

The API also offers a number of other methods that are mostly used to manage the associated session cookie. For example, there are methods to test that cookies are supported in the client browser, to set and check cookie expiry dates, and to clear expired sessions from the data store. You can find out about the full API in How to use sessions (Django docs).

Saving session data
-------------------

By default, Django only saves to the session database and sends the session cookie to the client when the session has been *modified* (assigned) or *deleted*. If you're updating some data using its session key as shown in the previous section, then you don't need to worry about this! For example:

```python
# This is detected as an update to the session, so session data is saved.
request.session['my\_car'] = 'mini'
```

If you're updating some information *within* session data, then Django will not recognize that you've made a change to the session and save the data (for example, if you were to change "`wheels`" data inside your "`my_car`" data, as shown below). In this case you will need to explicitly mark the session as having been modified.

```python
# Session object not directly modified, only data within the session. Session changes not saved!
request.session['my\_car']['wheels'] = 'alloy'

# Set session as modified to force data updates/cookie to be saved.
request.session.modified = True
```

**Note:** You can change the behavior so the site will update the database/send cookie on every request by adding `SESSION_SAVE_EVERY_REQUEST = True` into your project settings (**locallibrary/locallibrary/settings.py**).

Simple example — getting visit counts
-------------------------------------

As a simple real-world example we'll update our library to tell the current user how many times they have visited the *LocalLibrary* home page.

Open **/locallibrary/catalog/views.py**, and add the lines that contain `num_visits` into `index()` (as shown below).

```python
def index(request):
    # …

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

    # Number of visits to this view, as counted in the session variable.
    num_visits = request.session.get('num\_visits', 0)
    request.session['num\_visits'] = num_visits + 1

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

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

Here we first get the value of the `'num_visits'` session key, setting the value to 0 if it has not previously been set. Each time a request is received, we then increment the value and store it back in the session (for the next time the user visits the page). The `num_visits` variable is then passed to the template in our context variable.

**Note:** We might also test whether cookies are even supported in the browser here (see How to use sessions for examples) or design our UI so that it doesn't matter whether or not cookies are supported.

Add the line shown at the bottom of the following block to your main HTML template (**/locallibrary/catalog/templates/index.html**) at the bottom of the "Dynamic content" section to display the `num_visits` context variable.

```django
<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>

<p>
  You have visited this page {{ num\_visits }} time{{ num\_visits|pluralize }}.
</p>
```

Note that we use the Django built-in template tag pluralize to add an "s" when the page has been visited multiple time**s**.

Save your changes and restart the test server. Every time you refresh the page, the number should update.

Summary
-------

You now know how easy it is to use sessions to improve your interaction with *anonymous* users.

In our next articles we'll explain the authentication and authorization (permission) framework, and show you how to support user accounts.

See also
--------

* How to use sessions (Django docs)
* Previous
* Overview: Django
* Next


Django Tutorial Part 3: Using models - Learn web development

Django Tutorial Part 3: Using models
====================================

* Previous
* Overview: Django
* Next

This article shows how to define models for the LocalLibrary website. It explains what a model is, how it is declared, and some of the main field types. It also briefly shows a few of the main ways you can access model data.

|  |  |
| --- | --- |
| Prerequisites: | Django Tutorial Part 2: Creating a skeleton website. |
| Objective: | To be able to design and create your own models, choosing fields appropriately. |

Overview
--------

Django web applications access and manage data through Python objects referred to as models. Models define the *structure* of stored data, including the field *types* and possibly also their maximum size, default values, selection list options, help text for documentation, label text for forms, etc. The definition of the model is independent of the underlying database — you can choose one of several as part of your project settings. Once you've chosen what database you want to use, you don't need to talk to it directly at all — you just write your model structure and other code, and Django handles all the dirty work of communicating with the database for you.

This tutorial shows how to define and access the models for the LocalLibrary website example.

Designing the LocalLibrary models
---------------------------------

Before you jump in and start coding the models, it's worth taking a few minutes to think about what data we need to store and the relationships between the different objects.

We know that we need to store information about books (title, summary, author, written language, category, ISBN) and that we might have multiple copies available (with globally unique id, availability status, etc.). We might need to store more information about the author than just their name, and there might be multiple authors with the same or similar names. We want to be able to sort information based on book title, author, written language, and category.

When designing your models, it makes sense to have separate models for every "object" (a group of related information). In this case, the obvious objects are books, book instances, and authors.

You might also want to use models to represent selection-list options (e.g. like a drop down list of choices), rather than hard coding the choices into the website itself — this is recommended when all the options aren't known up front or may change. Obvious candidates for models, in this case, include the book genre (e.g. Science Fiction, French Poetry, etc.) and language (English, French, Japanese).

Once we've decided on our models and field, we need to think about the relationships. Django allows you to define relationships that are one to one (`OneToOneField`), one to many (`ForeignKey`) and many to many (`ManyToManyField`).

With that in mind, the UML association diagram below shows the models we'll define in this case (as boxes).

![LocalLibrary Model UML with fixed Author multiplicity inside the Book class](/en-US/docs/Learn/Server-side/Django/Models/local_library_model_uml.svg)

We've created models for the book (the generic details of the book), book instance (status of specific physical copies of the book available in the system), and author. We have also decided to have a model for the genre so that values can be created/selected through the admin interface. We've decided not to have a model for the `BookInstance:status` — we've hardcoded the values (`LOAN_STATUS`) because we don't expect these to change. Within each of the boxes, you can see the model name, the field names, and types, and also the methods and their return types.

The diagram also shows the relationships between the models, including their *multiplicities*. The multiplicities are the numbers on the diagram showing the numbers (maximum and minimum) of each model that may be present in the relationship. For example, the connecting line between the boxes shows that Book and a Genre are related. The numbers close to the Genre model show that a book must have one or more Genres (as many as you like), while the numbers on the other end of the line next to the Book model show that a Genre can have zero or many associated books.

**Note:** The next section provides a basic primer explaining how models are defined and used. As you read it, consider how we will construct each of the models in the diagram above.

Model primer
------------

This section provides a brief overview of how a model is defined and some of the more important fields and field arguments.

### Model definition

Models are usually defined in an application's **models.py** file. They are implemented as subclasses of `django.db.models.Model`, and can include fields, methods and metadata. The code fragment below shows a "typical" model, named `MyModelName`:

```python
from django.db import models
from django.urls import reverse

class MyModelName(models.Model):
    """A typical class defining a model, derived from the Model class."""

    # Fields
    my_field_name = models.CharField(max_length=20, help_text='Enter field documentation')
    # …

    # Metadata
    class Meta:
        ordering = ['-my\_field\_name']

    # Methods
    def get\_absolute\_url(self):
        """Returns the URL to access a particular instance of MyModelName."""
        return reverse('model-detail-view', args=[str(self.id)])

    def \_\_str\_\_(self):
        """String for representing the MyModelName object (in Admin site etc.)."""
        return self.my_field_name
```

In the below sections we'll explore each of the features inside the model in detail:

#### Fields

A model can have an arbitrary number of fields, of any type — each one represents a column of data that we want to store in one of our database tables. Each database record (row) will consist of one of each field value. Let's look at the example seen below:

```python
my_field_name = models.CharField(max_length=20, help_text='Enter field documentation')
```

Our above example has a single field called `my_field_name`, of type `models.CharField` — which means that this field will contain strings of alphanumeric characters. The field types are assigned using specific classes, which determine the type of record that is used to store the data in the database, along with validation criteria to be used when values are received from an HTML form (i.e. what constitutes a valid value). The field types can also take arguments that further specify how the field is stored or can be used. In this case we are giving our field two arguments:

* `max_length=20` — States that the maximum length of a value in this field is 20 characters.
* `help_text='Enter field documentation'` — helpful text that may be displayed in a form to help users understand how the field is used.

 The field name is used to refer to it in queries and templates.
 Fields also have a label, which is specified using the `verbose_name` argument (with a default value of `None`).
 If `verbose_name` is not set, the label is created from the field name by replacing any underscores with a space, and capitalizing the first letter (for example, the field `my_field_name` would have a default label of *My field name* when used in forms).

The order that fields are declared will affect their default order if a model is rendered in a form (e.g. in the Admin site), though this may be overridden.

##### Common field arguments

The following common arguments can be used when declaring many/most of the different field types:

* help\_text: Provides a text label for HTML forms (e.g. in the admin site), as described above.
* verbose\_name: A human-readable name for the field used in field labels. If not specified, Django will infer the default verbose name from the field name.
* default: The default value for the field. This can be a value or a callable object, in which case the object will be called every time a new record is created.
* null: If `True`, Django will store blank values as `NULL` in the database for fields where this is appropriate (a `CharField` will instead store an empty string). The default is `False`.
* blank: If `True`, the field is allowed to be blank in your forms. The default is `False`, which means that Django's form validation will force you to enter a value. This is often used with `null=True`, because if you're going to allow blank values, you also want the database to be able to represent them appropriately.
* choices: A group of choices for this field. If this is provided, the default corresponding form widget will be a select box with these choices instead of the standard text field.
* unique:
 If `True`, ensures that the field value is unique across the database.
 This can be used to prevent duplication of fields that can't have the same values.
 The default is `False`.
* primary\_key:
 If `True`, sets the current field as the primary key for the model (A primary key is a special database column designated to uniquely identify all the different table records).
 If no field is specified as the primary key, Django will automatically add a field for this purpose.
 The type of auto-created primary key fields can be specified for each app in `AppConfig.default_auto_field` or globally in the `DEFAULT_AUTO_FIELD` setting.

**Note:** Apps created using **manage.py** set the type of the primary key to a BigAutoField.
 You can see this in the local library **catalog/apps.py** file:

```py
class CatalogConfig(AppConfig):
  default_auto_field = 'django.db.models.BigAutoField'
```

There are many other options — you can view the full list of field options here.

##### Common field types

The following list describes some of the more commonly used types of fields.

* CharField is used to define short-to-mid sized fixed-length strings. You must specify the `max_length` of the data to be stored.
* TextField is used for large arbitrary-length strings. You may specify a `max_length` for the field, but this is used only when the field is displayed in forms (it is not enforced at the database level).
* IntegerField is a field for storing integer (whole number) values, and for validating entered values as integers in forms.
* DateField and DateTimeField are used for storing/representing dates and date/time information (as Python `datetime.date` and `datetime.datetime` objects, respectively). These fields can additionally declare the (mutually exclusive) parameters `auto_now=True` (to set the field to the current date every time the model is saved), `auto_now_add` (to only set the date when the model is first created), and `default` (to set a default date that can be overridden by the user).
* EmailField is used to store and validate email addresses.
* FileField and ImageField are used to upload files and images respectively (the `ImageField` adds additional validation that the uploaded file is an image). These have parameters to define how and where the uploaded files are stored.
* AutoField is a special type of `IntegerField` that automatically increments. A primary key of this type is automatically added to your model if you don't explicitly specify one.
* ForeignKey is used to specify a one-to-many relationship to another database model (e.g. a car has one manufacturer, but a manufacturer can make many cars). The "one" side of the relationship is the model that contains the "key" (models containing a "foreign key" referring to that "key", are on the "many" side of such a relationship).
* ManyToManyField is used to specify a many-to-many relationship (e.g. a book can have several genres, and each genre can contain several books). In our library app we will use these very similarly to `ForeignKeys`, but they can be used in more complicated ways to describe the relationships between groups. These have the parameter `on_delete` to define what happens when the associated record is deleted (e.g. a value of `models.SET_NULL` would set the value to `NULL`).

There are many other types of fields, including fields for different types of numbers (big integers, small integers, floats), booleans, URLs, slugs, unique ids, and other "time-related" information (duration, time, etc.). You can view the full list here.

#### Metadata

You can declare model-level metadata for your Model by declaring `class Meta`, as shown.

```python
class Meta:
    ordering = ['-my\_field\_name']
```

One of the most useful features of this metadata is to control the *default ordering* of records returned when you query the model type. You do this by specifying the match order in a list of field names to the `ordering` attribute, as shown above. The ordering will depend on the type of field (character fields are sorted alphabetically, while date fields are sorted in chronological order). As shown above, you can prefix the field name with a minus symbol (-) to reverse the sorting order.

So as an example, if we chose to sort books like this by default:

```python
ordering = ['title', '-pubdate']
```

the books would be sorted alphabetically by title, from A-Z, and then by publication date inside each title, from newest to oldest.

Another common attribute is `verbose_name`, a verbose name for the class in singular and plural form:

```python
verbose_name = 'BetterName'
```

Other useful attributes allow you to create and apply new "access permissions" for the model (default permissions are applied automatically), allow ordering based on another field, or to declare that the class is "abstract" (a base class that you cannot create records for, and will instead be derived from to create other models).

Many of the other metadata options control what database must be used for the model and how the data is stored (these are really only useful if you need to map a model to an existing database).

The full list of metadata options are available here: Model metadata options (Django docs).

#### Methods

A model can also have methods.

**Minimally, in every model you should define the standard Python class method `__str__()` to return a human-readable string for each object.** This string is used to represent individual records in the administration site (and anywhere else you need to refer to a model instance). Often this will return a title or name field from the model.

```python
def \_\_str\_\_(self):
    return self.my_field_name
```

Another common method to include in Django models is `get_absolute_url()`, which returns a URL for displaying individual model records on the website (if you define this method then Django will automatically add a "View on Site" button to the model's record editing screens in the Admin site). A typical pattern for `get_absolute_url()` is shown below.

```python
def get\_absolute\_url(self):
    """Returns the URL to access a particular instance of the model."""
    return reverse('model-detail-view', args=[str(self.id)])
```

**Note:** Assuming you will use URLs like `/myapplication/mymodelname/2` to display individual records for your model (where "2" is the `id` for a particular record), you will need to create a URL mapper to pass the response and id to a "model detail view" (which will do the work required to display the record). The `reverse()` function above is able to "reverse" your URL mapper (in the above case named *'model-detail-view'*) in order to create a URL of the right format.

Of course to make this work you still have to write the URL mapping, view, and template!

You can also define any other methods you like, and call them from your code or templates (provided that they don't take any parameters).

### Model management

Once you've defined your model classes you can use them to create, update, or delete records, and to run queries to get all records or particular subsets of records. We'll show you how to do that in the tutorial when we define our views, but here is a brief summary.

#### Creating and modifying records

To create a record you can define an instance of the model and then call `save()`.

```python
# Create a new record using the model's constructor.
record = MyModelName(my_field_name="Instance #1")

# Save the object into the database.
record.save()
```

**Note:** If you haven't declared any field as a `primary_key`, the new record will be given one automatically, with the field name `id`. You could query this field after saving the above record, and it would have a value of 1.

You can access the fields in this new record using the dot syntax, and change the values. You have to call `save()` to store modified values to the database.

```python
# Access model field values using Python attributes.
print(record.id) # should return 1 for the first record.
print(record.my_field_name) # should print 'Instance #1'

# Change record by modifying the fields, then calling save().
record.my_field_name = "New Instance Name"
record.save()
```

#### Searching for records

You can search for records that match certain criteria using the model's `objects` attribute (provided by the base class).

**Note:** Explaining how to search for records using "abstract" model and field names can be a little confusing. In the discussion below, we'll refer to a `Book` model with `title` and `genre` fields, where genre is also a model with a single field `name`.

We can get all records for a model as a `QuerySet`, using `objects.all()`. The `QuerySet` is an iterable object, meaning that it contains a number of objects that we can iterate/loop through.

```python
all_books = Book.objects.all()
```

Django's `filter()` method allows us to filter the returned `QuerySet` to match a specified **text** or **numeric** field against particular criteria. For example, to filter for books that contain "wild" in the title and then count them, we could do the following.

```python
wild_books = Book.objects.filter(title__contains='wild')
number_wild_books = wild_books.count()
```

The fields to match and the type of match are defined in the filter parameter name, using the format: `field_name__match_type` (note the *double underscore* between `title` and `contains` above). Above we're filtering `title` with a case-sensitive match. There are many other types of matches you can do: `icontains` (case insensitive), `iexact` (case-insensitive exact match), `exact` (case-sensitive exact match) and `in`, `gt` (greater than), `startswith`, etc. The full list is here.

 In some cases, you'll need to filter on a field that defines a one-to-many relationship to another model (e.g. a `ForeignKey`). In this case, you can "index" to fields within the related model with additional double underscores.
 So for example to filter for books with a specific genre pattern, you will have to index to the `name` through the `genre` field, as shown below:

```python
# Will match on: Fiction, Science fiction, non-fiction etc.
books_containing_genre = Book.objects.filter(genre__name__icontains='fiction')
```

**Note:** You can use underscores (`__`) to navigate as many levels of relationships (`ForeignKey`/`ManyToManyField`) as you like.
 For example, a `Book` that had different types, defined using a further "cover" relationship might have a parameter name: `type__cover__name__exact='hard'.`

There is a lot more you can do with queries, including backwards searches from related models, chaining filters, returning a smaller set of values, etc. For more information, see Making queries (Django Docs).

Defining the LocalLibrary Models
--------------------------------

In this section we will start defining the models for the library. Open `models.py` (in /locallibrary/catalog/). The boilerplate at the top of the page imports the *models* module, which contains the model base class `models.Model` that our models will inherit from.

```python
from django.db import models

# Create your models here.
```

### Genre model

 Copy the `Genre` model code shown below and paste it into the bottom of your `models.py` file. This model is used to store information about the book category — for example whether it is fiction or non-fiction, romance or military history, etc.
 As mentioned above, we've created the genre as a model rather than as free text or a selection list so that the possible values can be managed through the database rather than being hard coded.

```python
from django.urls import reverse # Used to generate URLs by reversing the URL patterns

class Genre(models.Model):
    """Model representing a book genre."""
    name = models.CharField(
        max_length=200,
        unique=True,
        help_text="Enter a book genre (e.g. Science Fiction, French Poetry etc.)"
    )

    def \_\_str\_\_(self):
        """String for representing the Model object."""
        return self.name

    def get\_absolute\_url(self):
        """Returns the url to access a particular genre instance."""
        return reverse('genre-detail', args=[str(self.id)])
```

 The model has a single `CharField` field (`name`), which is used to describe the genre (this is limited to 200 characters and has some `help_text`).
 We've set this field to be unique (`unique=True`) because there should only be one record for each genre.

 After the field, we declare a `__str__()` method, which returns the name of the genre defined by a particular record. No verbose name has been defined, so the field will be called `Name` in forms.
 The final method, `get_absolute_url()` returns a URL that can be used to access a detail record for this model (for this to work, we will have to define a URL mapping that has the name `genre-detail`, and define an associated view and template).

### Book model

Copy the `Book` model below and again paste it into the bottom of your file. The `Book` model represents all information about an available book in a general sense, but not a particular physical "instance" or "copy" available for loan.

 The model uses a `CharField` to represent the book's `title` and `isbn`.
 For `isbn`, note how the first unnamed parameter explicitly sets the label as "ISBN" (otherwise, it would default to "Isbn"). We also set the parameter `unique` as `true` to ensure all books have a unique ISBN (the unique parameter makes the field value globally unique in a table).
 Unlike for the `isbn` (and the genre name), the `title` is not set to be unique, because it is possible for different books to have the same name.
 The model uses `TextField` for the `summary`, because this text may need to be quite long.

```python
class Book(models.Model):
    """Model representing a book (but not a specific copy of a book)."""
    title = models.CharField(max_length=200)
    author = models.ForeignKey('Author', on_delete=models.RESTRICT, null=True)
    # Foreign Key used because book can only have one author, but authors can have multiple books.
    # Author as a string rather than object because it hasn't been declared yet in file.

    summary = models.TextField(
        max_length=1000, help_text="Enter a brief description of the book")
    isbn = models.CharField('ISBN', max_length=13,
                            unique=True,
                            help_text='13 Character <a href="https://www.isbn-international.org/content/what-isbn'
                                      '">ISBN number</a>')

    # ManyToManyField used because genre can contain many books. Books can cover many genres.
    # Genre class has already been defined so we can specify the object above.
    genre = models.ManyToManyField(
        Genre, help_text="Select a genre for this book")

    def \_\_str\_\_(self):
        """String for representing the Model object."""
        return self.title

    def get\_absolute\_url(self):
        """Returns the URL to access a detail record for this book."""
        return reverse('book-detail', args=[str(self.id)])
```

The genre is a `ManyToManyField`, so that a book can have multiple genres and a genre can have many books. The author is declared as `ForeignKey`, so each book will only have one author, but an author may have many books (in practice a book might have multiple authors, but not in this implementation!)

In both field types the related model class is declared as the first unnamed parameter using either the model class or a string containing the name of the related model. You must use the name of the model as a string if the associated class has not yet been defined in this file before it is referenced! The other parameters of interest in the `author` field are `null=True`, which allows the database to store a `Null` value if no author is selected, and `on_delete=models.RESTRICT`, which will prevent the book's associated author being deleted if it is referenced by any book.

**Warning:** By default `on_delete=models.CASCADE`, which means that if the author was deleted, this book would be deleted too! We use `RESTRICT` here, but we could also use `PROTECT` to prevent the author being deleted while any book uses it or `SET_NULL` to set the book's author to `Null` if the record is deleted.

The model also defines `__str__()`, using the book's `title` field to represent a `Book` record. The final method, `get_absolute_url()` returns a URL that can be used to access a detail record for this model (we will have to define a URL mapping that has the name `book-detail`, and define an associated view and template).

### BookInstance model

Next, copy the `BookInstance` model (shown below) under the other models. The `BookInstance` represents a specific copy of a book that someone might borrow, and includes information about whether the copy is available or on what date it is expected back, "imprint" or version details, and a unique id for the book in the library.

Some of the fields and methods will now be familiar. The model uses:

* `ForeignKey` to identify the associated `Book` (each book can have many copies, but a copy can only have one `Book`). The key specifies `on_delete=models.RESTRICT` to ensure that the `Book` cannot be deleted while referenced by a `BookInstance`.
* `CharField` to represent the imprint (specific release) of the book.

```python
import uuid # Required for unique book instances

class BookInstance(models.Model):

    """Model representing a specific copy of a book (i.e. that can be borrowed from the library)."""
    id = models.UUIDField(primary_key=True, default=uuid.uuid4,
                          help_text="Unique ID for this particular book across whole library")
    book = models.ForeignKey('Book', on_delete=models.RESTRICT, null=True)
    imprint = models.CharField(max_length=200)
    due_back = models.DateField(null=True, blank=True)

    LOAN_STATUS = (
        ('m', 'Maintenance'),
        ('o', 'On loan'),
        ('a', 'Available'),
        ('r', 'Reserved'),
    )

    status = models.CharField(
        max_length=1,
        choices=LOAN_STATUS,
        blank=True,
        default='m',
        help_text='Book availability',
    )

    class Meta:
        ordering = ['due\_back']

    def \_\_str\_\_(self):
        """String for representing the Model object."""
        return f'{self.id} ({self.book.title})'
```

We additionally declare a few new types of field:

* `UUIDField` is used for the `id` field to set it as the `primary_key` for this model.
 This type of field allocates a globally unique value for each instance (one for every book you can find in the library).
* `DateField` is used for the `due_back` date (at which the book is expected to become available after being borrowed or in maintenance). This value can be `blank` or `null` (needed for when the book is available). The model metadata (`Class Meta`) uses this field to order records when they are returned in a query.
* `status` is a `CharField` that defines a choice/selection list. As you can see, we define a tuple containing tuples of key-value pairs and pass it to the choices argument. The value in a key/value pair is a display value that a user can select, while the keys are the values that are actually saved if the option is selected. We've also set a default value of 'm' (maintenance) as books will initially be created unavailable before they are stocked on the shelves.

The method `__str__()` represents the `BookInstance` object using a combination of its unique id and the associated `Book`'s title.

**Note:** A little Python:

* Starting with Python 3.6, you can use the string interpolation syntax (also known as f-strings): `f'{self.id} ({self.book.title})'`.
* In older versions of this tutorial, we were using a formatted string syntax, which is also a valid way of formatting strings in Python (e.g. `'{0} ({1})'.format(self.id,self.book.title)`).

### Author model

Copy the `Author` model (shown below) underneath the existing code in **models.py**.

```python
class Author(models.Model):
    """Model representing an author."""
    first_name = models.CharField(max_length=100)
    last_name = models.CharField(max_length=100)
    date_of_birth = models.DateField(null=True, blank=True)
    date_of_death = models.DateField('Died', null=True, blank=True)

    class Meta:
        ordering = ['last\_name', 'first\_name']

    def get\_absolute\_url(self):
        """Returns the URL to access a particular author instance."""
        return reverse('author-detail', args=[str(self.id)])

    def \_\_str\_\_(self):
        """String for representing the Model object."""
        return f'{self.last\_name}, {self.first\_name}'
```

All of the fields/methods should now be familiar. The model defines an author as having a first name, last name, and dates of birth and death (both optional). It specifies that by default the `__str__()` returns the name in *last name*, *firstname* order. The `get_absolute_url()` method reverses the `author-detail` URL mapping to get the URL for displaying an individual author.

Re-run the database migrations
------------------------------

All your models have now been created. Now re-run your database migrations to add them to your database.

```bash
python3 manage.py makemigrations
python3 manage.py migrate
```

Language model — challenge
--------------------------

Imagine a local benefactor donates a number of new books written in another language (say, Farsi). The challenge is to work out how these would be best represented in our library website, and then to add them to the models.

Some things to consider:

* Should "language" be associated with a `Book`, `BookInstance`, or some other object?
* Should the different languages be represented using model, a free text field, or a hard-coded selection list?

After you've decided, add the field. You can see what we decided on GitHub here.

Don't forget that after a change to your model, you should again re-run your database migrations to add the changes.

```bash
python3 manage.py makemigrations
python3 manage.py migrate
```

Summary
-------

In this article we've learned how models are defined, and then used this information to design and implement appropriate models for the *LocalLibrary* website.

At this point we'll divert briefly from creating the site, and check out the *Django Administration site*. This site will allow us to add some data to the library, which we can then display using our (yet to be created) views and templates.

See also
--------

* Writing your first Django app, part 2 (Django docs)
* Making queries (Django Docs)
* QuerySet API Reference (Django Docs)
* Previous
* Overview: Django
* Next


Django Tutorial Part 6: Generic list and detail views - Learn web development

Django Tutorial Part 6: Generic list and detail views
=====================================================

* Previous
* Overview: Django
* Next

This tutorial extends our LocalLibrary website, adding list and detail pages for books and authors. Here we'll learn about generic class-based views, and show how they can reduce the amount of code you have to write for common use cases. We'll also go into URL handling in greater detail, showing how to perform basic pattern matching.

|  |  |
| --- | --- |
| Prerequisites: | Complete all previous tutorial topics, including Django Tutorial Part 5: Creating our home page. |
| Objective: | To understand where and how to use generic class-based views, and how to extract patterns from URLs and pass the information to views. |

Overview
--------

In this tutorial we're going to complete the first version of the LocalLibrary website by adding list and detail pages for books and authors (or to be more precise, we'll show you how to implement the book pages, and get you to create the author pages yourself!)

The process is similar to creating the index page, which we showed in the previous tutorial. We'll still need to create URL maps, views, and templates. The main difference is that for the detail pages, we'll have the additional challenge of extracting information from patterns in the URL and passing it to the view. For these pages, we're going to demonstrate a completely different type of view: generic class-based list and detail views. These can significantly reduce the amount of view code needed, making them easier to write and maintain.

The final part of the tutorial will demonstrate how to paginate your data when using generic class-based list views.

Book list page
--------------

The book list page will display a list of all the available book records in the page, accessed using the URL: `catalog/books/`. The page will display a title and author for each record, with the title being a hyperlink to the associated book detail page. The page will have the same structure and navigation as all other pages in the site, and we can, therefore, extend the base template (**base\_generic.html**) we created in the previous tutorial.

### URL mapping

 Open **/catalog/urls.py** and copy in the line setting the path for `'books/'`, as shown below.
 Just as for the index page, this `path()` function defines a pattern to match against the URL (**'books/'**), a view function that will be called if the URL matches (`views.BookListView.as_view()`), and a name for this particular mapping.

```python
urlpatterns = [
    path('', views.index, name='index'),
    path('books/', views.BookListView.as_view(), name='books'),
]
```

As discussed in the previous tutorial the URL must already have matched `/catalog`, so the view will actually be called for the URL: `/catalog/books/`.

The view function has a different format than before — that's because this view will actually be implemented as a class. We will be inheriting from an existing generic view function that already does most of what we want this view function to do, rather than writing our own from scratch.

For Django class-based views we access an appropriate view function by calling the class method `as_view()`. This does all the work of creating an instance of the class, and making sure that the right handler methods are called for incoming HTTP requests.

### View (class-based)

We could quite easily write the book list view as a regular function (just like our previous index view), which would query the database for all books, and then call `render()` to pass the list to a specified template. Instead, however, we're going to use a class-based generic list view (`ListView`) — a class that inherits from an existing view. Because the generic view already implements most of the functionality we need and follows Django best-practice, we will be able to create a more robust list view with less code, less repetition, and ultimately less maintenance.

Open **catalog/views.py**, and copy the following code into the bottom of the file:

```python
from django.views import generic

class BookListView(generic.ListView):
    model = Book
```

That's it! The generic view will query the database to get all records for the specified model (`Book`) then render a template located at **/locallibrary/catalog/templates/catalog/book\_list.html** (which we will create below). Within the template you can access the list of books with the template variable named `object_list` OR `book_list` (i.e. generically "`<the model name>_list`").

**Note:** This awkward path for the template location isn't a misprint — the generic views look for templates in `/application_name/the_model_name_list.html` (`catalog/book_list.html` in this case) inside the application's `/application_name/templates/` directory (`/catalog/templates/)`.

You can add attributes to change the default behavior above. For example, you can specify another template file if you need to have multiple views that use this same model, or you might want to use a different template variable name if `book_list` is not intuitive for your particular template use-case. Possibly the most useful variation is to change/filter the subset of results that are returned — so instead of listing all books you might list top 5 books that were read by other users.

```python
class BookListView(generic.ListView):
    model = Book
    context_object_name = 'book\_list'   # your own name for the list as a template variable
    queryset = Book.objects.filter(title__icontains='war')[:5] # Get 5 books containing the title war
    template_name = 'books/my\_arbitrary\_template\_name\_list.html'  # Specify your own template name/location
```

#### Overriding methods in class-based views

While we don't need to do so here, you can also override some of the class methods.

For example, we can override the `get_queryset()` method to change the list of records returned. This is more flexible than just setting the `queryset` attribute as we did in the preceding code fragment (though there is no real benefit in this case):

```python
class BookListView(generic.ListView):
    model = Book

    def get\_queryset(self):
        return Book.objects.filter(title__icontains='war')[:5] # Get 5 books containing the title war
```

We might also override `get_context_data()` in order to pass additional context variables to the template (e.g. the list of books is passed by default). The fragment below shows how to add a variable named "`some_data`" to the context (it would then be available as a template variable).

```python
class BookListView(generic.ListView):
    model = Book

    def get\_context\_data(self, \*\*kwargs):
        # Call the base implementation first to get the context
        context = super(BookListView, self).get_context_data(\*\*kwargs)
        # Create any data and add it to the context
        context['some\_data'] = 'This is just some data'
        return context
```

When doing this it is important to follow the pattern used above:

* First get the existing context from our superclass.
* Then add your new context information.
* Then return the new (updated) context.

**Note:** Check out Built-in class-based generic views (Django docs) for many more examples of what you can do.

### Creating the List View template

Create the HTML file **/locallibrary/catalog/templates/catalog/book\_list.html** and copy in the text below. As discussed above, this is the default template file expected by the generic class-based list view (for a model named `Book` in an application named `catalog`).

 Templates for generic views are just like any other templates (although of course the context/information passed to the template may differ).
 As with our *index* template, we extend our base template in the first line and then replace the block named `content`.

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

{% block content %}
  <h1>Book List</h1>
  {% if book\_list %}
    <ul>
      {% for book in book\_list %}
      <li>
        <a href="{{ book.get\_absolute\_url }}">{{ book.title }}</a>
        ({{book.author}})
      </li>
      {% endfor %}
    </ul>
  {% else %}
    <p>There are no books in the library.</p>
  {% endif %}
{% endblock %}
```

The view passes the context (list of books) by default as `object_list` and `book_list` aliases; either will work.

#### Conditional execution

 We use the `if`, `else`, and `endif` template tags to check whether the `book_list` has been defined and is not empty.
 If `book_list` is empty, then the `else` clause displays text explaining that there are no books to list.
 If `book_list` is not empty, then we iterate through the list of books.

```django
{% if book\_list %}
  <!-- code here to list the books -->
{% else %}
  <p>There are no books in the library.</p>
{% endif %}
```

 The condition above only checks for one case, but you can test on additional conditions using the `elif` template tag (e.g. `{% elif var2 %}`).
 For more information about conditional operators see: if, ifequal/ifnotequal, and ifchanged in Built-in template tags and filters (Django Docs).

#### For loops

 The template uses the for and `endfor` template tags to loop through the book list, as shown below.
 Each iteration populates the `book` template variable with information for the current list item.

```django
{% for book in book\_list %}
  <li><!-- code here get information from each book item --></li>
{% endfor %}
```

You might also use the `{% empty %}` template tag to define what happens if the book list is empty (although our template chooses to use a conditional instead):

```django
<ul>
  {% for book in book\_list %}
    <li><!-- code here get information from each book item --></li>
  {% empty %}
    <p>There are no books in the library.</p>
  {% endfor %}
</ul>
```

 While not used here, within the loop Django will also create other variables that you can use to track the iteration.
 For example, you can test the `forloop.last` variable to perform conditional processing the last time that the loop is run.

#### Accessing variables

The code inside the loop creates a list item for each book that shows both the title (as a link to the yet-to-be-created detail view) and the author.

```django
<a href="{{ book.get\_absolute\_url }}">{{ book.title }}</a> ({{book.author}})
```

We access the *fields* of the associated book record using the "dot notation" (e.g. `book.title` and `book.author`), where the text following the `book` item is the field name (as defined in the model).

We can also call *functions* in the model from within our template — in this case we call `Book.get_absolute_url()` to get a URL you could use to display the associated detail record. This works provided the function does not have any arguments (there is no way to pass arguments!)

**Note:** We have to be a little careful of "side effects" when calling functions in templates. Here we just get a URL to display, but a function can do pretty much anything — we wouldn't want to delete our database (for example) just by rendering our template!

#### Update the base template

Open the base template (**/locallibrary/catalog/templates/*base\_generic.html***) and insert **{% url 'books' %}** into the URL link for **All books**, as shown below. This will enable the link in all pages (we can successfully put this in place now that we've created the "books" URL mapper).

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

### What does it look like?

You won't be able to build the book list yet, because we're still missing a dependency — the URL map for the book detail pages, which is needed to create hyperlinks to individual books. We'll show both list and detail views after the next section.

Book detail page
----------------

The book detail page will display information about a specific book, accessed using the URL `catalog/book/<id>` (where `<id>` is the primary key for the book). In addition to fields in the `Book` model (author, summary, ISBN, language, and genre), we'll also list the details of the available copies (`BookInstances`) including the status, expected return date, imprint, and id. This will allow our readers to not only learn about the book, but also to confirm whether/when it is available.

### URL mapping

 Open **/catalog/urls.py** and add the path named '**book-detail**' shown below.
 This `path()` function defines a pattern, associated generic class-based detail view, and a name.

```python
urlpatterns = [
    path('', views.index, name='index'),
    path('books/', views.BookListView.as_view(), name='books'),
    path('book/<int:pk>', views.BookDetailView.as_view(), name='book-detail'),
]
```

 For the *book-detail* path the URL pattern uses a special syntax to capture the specific id of the book that we want to see.
 The syntax is very simple: angle brackets define the part of the URL to be captured, enclosing the name of the variable that the view can use to access the captured data.
 For example, **<something>**, will capture the marked pattern and pass the value to the view as a variable "something". You can optionally precede the variable name with a converter specification that defines the type of data (int, str, slug, uuid, path).

In this case we use `'<int:pk>'` to capture the book id, which must be a specially formatted string and pass it to the view as a parameter named `pk` (short for primary key). This is the id that is being used to store the book uniquely in the database, as defined in the Book Model.

**Note:** As discussed previously, our matched URL is actually `catalog/book/<digits>` (because we are in the **catalog** application, `/catalog/` is assumed).

**Warning:** The generic class-based detail view *expects* to be passed a parameter named **pk**. If you're writing your own function view you can use whatever parameter name you like, or indeed pass the information in an unnamed argument.

#### Advanced path matching/regular expression primer

**Note:** You won't need this section to complete the tutorial! We provide it because knowing this option is likely to be useful in your Django-centric future.

The pattern matching provided by `path()` is simple and useful for the (very common) cases where you just want to capture *any* string or integer. If you need more refined filtering (for example, to filter only strings that have a certain number of characters) then you can use the re\_path() method.

This method is used just like `path()` except that it allows you to specify a pattern using a Regular expression. For example, the previous path could have been written as shown below:

```python
re_path(r'^book/(?P<pk>\d+)$', views.BookDetailView.as_view(), name='book-detail'),
```

*Regular expressions* are an incredibly powerful pattern mapping tool. They are, frankly, quite unintuitive and can be intimidating for beginners. Below is a very short primer!

The first thing to know is that regular expressions should usually be declared using the raw string literal syntax (i.e. they are enclosed as shown: **r'<your regular expression text goes here>'**).

The main parts of the syntax you will need to know for declaring the pattern matches are:

| Symbol | Meaning |
| --- | --- |
| ^ | Match the beginning of the text |
| $ | Match the end of the text |
| \d | Match a digit (0, 1, 2, … 9) |
| \w |
 Match a word character, e.g. any upper- or lower-case character in the
 alphabet, digit or the underscore character (\_)
  |
| + |
 Match one or more of the preceding character. For example, to match one
 or more digits you would use `\d+`. To match one or more "a"
 characters, you could use `a+` |
| \* |
 Match zero or more of the preceding character. For example, to match
 nothing or a word you could use `\w*` |
| ( ) |
 Capture the part of the pattern inside the parentheses. Any captured values
 will be passed to the view as unnamed parameters (if multiple patterns
 are captured, the associated parameters will be supplied in the order
 that the captures were declared).
  |
| (?P<*name*>...) |
 Capture the pattern (indicated by ...) as a named variable (in this case
 "name"). The captured values are passed to the view with the name
 specified. Your view must therefore declare a parameter with the same
 name!
  |
| [ ] |
 Match against one character in the set. For example, [abc] will match on
 'a' or 'b' or 'c'. [-\w] will match on the '-' character or any word
 character.
  |

Most other characters can be taken literally!

Let's consider a few real examples of patterns:

| Pattern | Description |
| --- | --- |
| **r'^book/(?P<pk>\d+)$'** |
 This is the RE used in our URL mapper. It matches a string that has
 `book/` at the start of the line (**^book/**),
 then has one or more digits (`\d+`), and then ends (with no
 non-digit characters before the end of line marker).

 It also captures all the digits **(?P<pk>\d+)** and
 passes them to the view in a parameter named 'pk'.
 **The captured values are always passed as a string!**

 For example, this would match `book/1234`, and send a
 variable `pk='1234'` to the view.
  |
| **r'^book/(\d+)$'** |
 This matches the same URLs as the preceding case. The captured
 information would be sent as an unnamed argument to the view.
  |
| **r'^book/(?P<stub>[-\w]+)$'** |
 This matches a string that has `book/` at the start of the
 line (**^book/**), then has one or more characters that
 are *either* a '-' or a word character
 (**[-\w]+**), and then ends. It also captures this set of
 characters and passes them to the view in a parameter named 'stub'.

 This is a fairly typical pattern for a "stub". Stubs are URL-friendly
 word-based primary keys for data. You might use a stub if you wanted
 your book URL to be more informative. For example
 `/catalog/book/the-secret-garden` rather than
 `/catalog/book/33`.
  |

You can capture multiple patterns in the one match, and hence encode lots of different information in a URL.

**Note:** As a challenge, consider how you might encode a URL to list all books released in a particular year, month, day, and the RE that could be used to match it.

#### Passing additional options in your URL maps

One feature that we haven't used here, but which you may find valuable, is that you can pass a dictionary containing additional options to the view (using the third un-named argument to the `path()` function). This approach can be useful if you want to use the same view for multiple resources, and pass data to configure its behavior in each case.

For example, given the path shown below, for a request to `/myurl/halibut/` Django will call `views.my_view(request, fish='halibut', my_template_name='some_path')`.

```python
path('myurl/<fish>', views.my_view, {'my\_template\_name': 'some\_path'}, name='aurl'),
```

**Note:** Both named captured patterns and dictionary options are passed to the view as *named* arguments. If you use the **same name** for both a capture pattern and a dictionary key, then the dictionary option will be used.

### View (class-based)

Open **catalog/views.py**, and copy the following code into the bottom of the file:

```python
class BookDetailView(generic.DetailView):
    model = Book
```

That's it! All you need to do now is create a template called **/locallibrary/catalog/templates/catalog/book\_detail.html**, and the view will pass it the database information for the specific `Book` record extracted by the URL mapper. Within the template you can access the book's details with the template variable named `object` OR `book` (i.e. generically "`the_model_name`").

If you need to, you can change the template used and the name of the context object used to reference the book in the template. You can also override methods to, for example, add additional information to the context.

#### What happens if the record doesn't exist?

If a requested record does not exist then the generic class-based detail view will raise an `Http404` exception for you automatically — in production, this will automatically display an appropriate "resource not found" page, which you can customize if desired.

Just to give you some idea of how this works, the code fragment below demonstrates how you would implement the class-based view as a function if you were **not** using the generic class-based detail view.

```python
def book\_detail\_view(request, primary_key):
    try:
        book = Book.objects.get(pk=primary_key)
    except Book.DoesNotExist:
        raise Http404('Book does not exist')

    return render(request, 'catalog/book\_detail.html', context={'book': book})
```

The view first tries to get the specific book record from the model. If this fails the view should raise an `Http404` exception to indicate that the book is "not found". The final step is then, as usual, to call `render()` with the template name and the book data in the `context` parameter (as a dictionary).

 Another way you could do this if you were not using a generic view would be to call the `get_object_or_404()` function.
 This is a shortcut to raise an `Http404` exception if the record is not found.

```python
from django.shortcuts import get_object_or_404

def book\_detail\_view(request, primary_key):
    book = get_object_or_404(Book, pk=primary_key)
    return render(request, 'catalog/book\_detail.html', context={'book': book})
```

### Creating the Detail View template

Create the HTML file **/locallibrary/catalog/templates/catalog/book\_detail.html** and give it the below content. As discussed above, this is the default template file name expected by the generic class-based *detail* view (for a model named `Book` in an application named `catalog`).

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

{% block content %}
  <h1>Title: {{ book.title }}</h1>

  <p><strong>Author:</strong> <a href="">{{ book.author }}</a></p>
  <!-- author detail link not yet defined -->
  <p><strong>Summary:</strong> {{ book.summary }}</p>
  <p><strong>ISBN:</strong> {{ book.isbn }}</p>
  <p><strong>Language:</strong> {{ book.language }}</p>
  <p><strong>Genre:</strong> {{ book.genre.all|join:", " }}</p>

  <div style="margin-left:20px;margin-top:20px">
    <h4>Copies</h4>

    {% for copy in book.bookinstance\_set.all %}
      <hr />
      <p
 class="{% if copy.status == 'a' %}text-success{% elif copy.status == 'm' %}text-danger{% else %}text-warning{% endif %}">
        {{ copy.get\_status\_display }}
      </p>
      {% if copy.status != 'a' %}
        <p><strong>Due to be returned:</strong> {{ copy.due\_back }}</p>
      {% endif %}
      <p><strong>Imprint:</strong> {{ copy.imprint }}</p>
      <p class="text-muted"><strong>Id:</strong> {{ copy.id }}</p>
    {% endfor %}
  </div>
{% endblock %}
```

**Note:** The author link in the template above has an empty URL because we've not yet created an author detail page to link to.
 Once the detail page exists we can get its URL with either of these two approaches:

* Use the `url` template tag to reverse the 'author-detail' URL (defined in the URL mapper), passing it the author instance for the book:

```django
<a href="{% url 'author-detail' book.author.pk %}">{{ book.author }}</a>
```

* Call the author model's `get_absolute_url()` method (this performs the same reversing operation):

```django
<a href="{{ book.author.get\_absolute\_url }}">{{ book.author }}</a>
```

While both methods effectively do the same thing, `get_absolute_url()` is preferred because it helps you write more consistent and maintainable code (any changes only need to be done in one place: the author model).

Though a little larger, almost everything in this template has been described previously:

* We extend our base template and override the "content" block.
* We use conditional processing to determine whether or not to display specific content.
* We use `for` loops to loop through lists of objects.
* We access the context fields using the dot notation (because we've used the detail generic view, the context is named `book`; we could also use "`object`")

The first interesting thing we haven't seen before is the function `book.bookinstance_set.all()`. This method is "automagically" constructed by Django in order to return the set of `BookInstance` records associated with a particular `Book`.

```django
{% for copy in book.bookinstance\_set.all %}
  <!-- code to iterate across each copy/instance of a book -->
{% endfor %}
```

This method is needed because you declare a `ForeignKey` (one-to many) field only in the "many" side of the relationship (the `BookInstance`). Since you don't do anything to declare the relationship in the other ("one") model, it (the `Book`) doesn't have any field to get the set of associated records. To overcome this problem, Django constructs an appropriately named "reverse lookup" function that you can use. The name of the function is constructed by lower-casing the model name where the `ForeignKey` was declared, followed by `_set` (i.e. so the function created in `Book` is `bookinstance_set()`).

**Note:** Here we use `all()` to get all records (the default). While you can use the `filter()` method to get a subset of records in code, you can't do this directly in templates because you can't specify arguments to functions.

Beware also that if you don't define an order (on your class-based view or model), you will also see errors from the development server like this one:
```

[29/May/2017 18:37:53] "GET /catalog/books/?page=1 HTTP/1.1" 200 1637
/foo/local_library/venv/lib/python3.5/site-packages/django/views/generic/list.py:99: UnorderedObjectListWarning: Pagination may yield inconsistent results with an unordered object_list: <QuerySet [<Author: Ortiz, David>, <Author: H. McRaven, William>, <Author: Leigh, Melinda>]>
  allow_empty_first_page=allow_empty_first_page, **kwargs)
```

That happens because the paginator object expects to see some ORDER BY being executed on your underlying database. Without it, it can't be sure the records being returned are actually in the right order!

This tutorial hasn't covered **Pagination** (yet!), but since you can't use `sort_by()` and pass a parameter (the same with `filter()` described above) you will have to choose between three choices:

1. Add a `ordering` inside a `class Meta` declaration on your model.
2. Add a `queryset` attribute in your custom class-based view, specifying an `order_by()`.
3. Adding a `get_queryset` method to your custom class-based view and also specify the `order_by()`.

If you decide to go with a `class Meta` for the `Author` model (probably not as flexible as customizing the class-based view, but easy enough), you will end up with something like this:

```python
class Author(models.Model):
    first_name = models.CharField(max_length=100)
    last_name = models.CharField(max_length=100)
    date_of_birth = models.DateField(null=True, blank=True)
    date_of_death = models.DateField('Died', null=True, blank=True)

    def get\_absolute\_url(self):
        return reverse('author-detail', args=[str(self.id)])

    def \_\_str\_\_(self):
        return f'{self.last\_name}, {self.first\_name}'

    class Meta:
        ordering = ['last\_name']
```

Of course, the field doesn't need to be `last_name`: it could be any other.

Last but not least, you should sort by an attribute/column that actually has an index (unique or not) on your database to avoid performance issues. Of course, this will not be necessary here (we are probably getting ahead of ourselves with so few books and users), but it is something worth keeping in mind for future projects.

 The second interesting (and non-obvious) thing in the template is where we display the status text for each book instance ("available", "maintenance", etc.).
 Astute readers will note that the method `BookInstance.get_status_display()` that we use to get the status text does not appear elsewhere in the code.

```django
 <p class="{% if copy.status == 'a' %}text-success{% elif copy.status == 'm' %}text-danger{% else %}text-warning{% endif %}">
 {{ copy.get\_status\_display }} </p>
```

 This function is automatically created because `BookInstance.status` is a choices field.
 Django automatically creates a method `get_FOO_display()` for every choices field "`Foo`" in a model, which can be used to get the current value of the field.

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

At this point, we should have created everything needed to display both the book list and book detail pages. Run the server (`python3 manage.py runserver`) and open your browser to `http://127.0.0.1:8000/`.

**Warning:** Don't click any author or author detail links yet — you'll create those in the challenge!

Click the **All books** link to display the list of books.

![Book List Page](/en-US/docs/Learn/Server-side/Django/Generic_views/book_list_page_no_pagination.png)

Then click a link to one of your books. If everything is set up correctly, you should see something like the following screenshot.

![Book Detail Page](/en-US/docs/Learn/Server-side/Django/Generic_views/book_detail_page_no_pagination.png)

Pagination
----------

If you've just got a few records, our book list page will look fine. However, as you get into the tens or hundreds of records the page will take progressively longer to load (and have far too much content to browse sensibly). The solution to this problem is to add pagination to your list views, reducing the number of items displayed on each page.

Django has excellent inbuilt support for pagination. Even better, this is built into the generic class-based list views so you don't have to do very much to enable it!

### Views

Open **catalog/views.py**, and add the `paginate_by` line shown below.

```python
class BookListView(generic.ListView):
    model = Book
    paginate_by = 10
```

 With this addition, as soon as you have more than 10 records the view will start paginating the data it sends to the template.
 The different pages are accessed using GET parameters — to access page 2 you would use the URL `/catalog/books/?page=2`.

### Templates

Now that the data is paginated, we need to add support to the template to scroll through the results set. Because we might want paginate all list views, we'll add this to the base template.

Open **/locallibrary/catalog/templates/*base\_generic.html*** and find the "content block" (as shown below).

```django
{% block content %}{% endblock %}
```

Copy in the following pagination block immediately following the `{% endblock %}`. The code first checks if pagination is enabled on the current page. If so, it adds *next* and *previous* links as appropriate (and the current page number).

```django
{% block pagination %}
    {% if is\_paginated %}
        <div class="pagination">
            <span class="page-links">
                {% if page\_obj.has\_previous %}
                    <a href="{{ request.path }}?page={{ page\_obj.previous\_page\_number }}">previous</a>
                {% endif %}
                <span class="page-current">
                    Page {{ page\_obj.number }} of {{ page\_obj.paginator.num\_pages }}.
                </span>
                {% if page\_obj.has\_next %}
                    <a href="{{ request.path }}?page={{ page\_obj.next\_page\_number }}">next</a>
                {% endif %}
            </span>
        </div>
    {% endif %}
  {% endblock %}
```

The `page_obj` is a Paginator object that will exist if pagination is being used on the current page. It allows you to get all the information about the current page, previous pages, how many pages there are, etc.

We use `{{ request.path }}` to get the current page URL for creating the pagination links. This is useful because it is independent of the object that we're paginating.

That's it!

### What does it look like?

The screenshot below shows what the pagination looks like — if you haven't entered more than 10 titles into your database, then you can test it more easily by lowering the number specified in the `paginate_by` line in your **catalog/views.py** file. To get the below result we changed it to `paginate_by = 2`.

The pagination links are displayed on the bottom, with next/previous links being displayed depending on which page you're on.

![Book List Page - paginated](/en-US/docs/Learn/Server-side/Django/Generic_views/book_list_paginated.png)

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

The challenge in this article is to create the author detail and list views required to complete the project. These should be made available at the following URLs:

* `catalog/authors/` — The list of all authors.
* `catalog/author/<id>` — The detail view for the specific author with a primary key field named `<id>`

The code required for the URL mappers and the views should be virtually identical to the `Book` list and detail views we created above. The templates will be different but will share similar behavior.

**Note:**

* Once you've created the URL mapper for the author list page you will also need to update the **All authors** link in the base template.
 Follow the same process as we did when we updated the **All books** link.
* Once you've created the URL mapper for the author detail page, you should also update the book detail view template (**/locallibrary/catalog/templates/catalog/book\_detail.html**) so that the author link points to your new author detail page (rather than being an empty URL).
 The recommended way to do this is to call `get_absolute_url()` on the author model as shown below.

```django
<p>
  <strong>Author:</strong>
  <a href="{{ book.author.get\_absolute\_url }}">{{ book.author }}</a>
</p>
```

When you are finished, your pages should look something like the screenshots below.

![Author List Page](/en-US/docs/Learn/Server-side/Django/Generic_views/author_list_page_no_pagination.png)

![Author Detail Page](/en-US/docs/Learn/Server-side/Django/Generic_views/author_detail_page_no_pagination.png)

Summary
-------

Congratulations, our basic library functionality is now complete!

In this article, we've learned how to use the generic class-based list and detail views and used them to create pages to view our books and authors. Along the way we've learned about pattern matching with regular expressions, and how you can pass data from URLs to your views. We've also learned a few more tricks for using templates. Last of all we've shown how to paginate list views so that our lists are manageable even when we have many records.

In our next articles, we'll extend this library to support user accounts, and thereby demonstrate user authentication, permissions, sessions, and forms.

See also
--------

* Built-in class-based generic views (Django docs)
* Generic display views (Django docs)
* Introduction to class-based views (Django docs)
* Built-in template tags and filters (Django docs)
* Pagination (Django docs)
* Making queries > Related objects (Django docs)
* Previous
* Overview: Django
* Next