Build a Book Collection REST API

Build a REST API with Django for books and authors with auth and filtering.

Introduction

30 Second Summary

Every time you browse an online bookstore, search for a title, or add something to your reading list, you're talking to a REST API behind the scenes. These APIs are the invisible backbone that connects apps to their data.

In this project, you will build a Book Collection REST API from scratch using Django REST Framework. Your API will support full CRUD operations, token-based authentication, and a browser-friendly interface for testing everything without extra tools.

What You'll Build

A fully functional REST API that manages books and authors, complete with authentication and permission controls.

By the end of this project, you'll have:

  • A working REST API with full CRUD operations for books and authors.
  • Authentication and permission controls protecting your API endpoints.
  • DRF's Browsable API for testing every endpoint directly in your browser.
  • Secret Mission: filtering and search capabilities so users can find books by author, title keyword, or publication year.

Are there any prerequisites?

You should have intermediate Python knowledge and a basic understanding of HTTP methods (GET, POST, PUT, DELETE). No prior Django experience is required.

Set Up Your Project Environment

Before writing any API code, you need a clean, isolated workspace. A virtual environment keeps your project's packages separate from your system Python, so nothing conflicts.

In this step, you'll create a project folder, install Django and Django REST Framework, then scaffold the project structure that every DRF API needs.

In this step, get ready to:
  • Create a virtual environment and install Django + Django REST Framework.
  • Create the Django project and books app.
  • Configure settings to register your new app and DRF.
Create your project folder and virtual environment
  • Press Cmd+Space (macOS) or the Windows key (Windows) to open your search bar.
  • Type Terminal (macOS) or Command Prompt (Windows) and press Enter to open it.
  • Move to your Desktop by running this command:
cd ~/Desktop
  • Create your project folder and move into it by running these commands:
mkdir bookapi
cd bookapi
  • Confirm the folder was created by running:
ls

The folder will be empty for now. That's expected.

  • Create a virtual environment inside your project folder by running:
python3 -m venv .venv

What does this command do?

This creates a hidden folder called .venv that contains a private copy of Python and pip.

Any packages you install while the virtual environment is active stay inside this folder instead of affecting your entire system.

Now you need to activate the virtual environment so your terminal uses it.

macOS

  • Activate your virtual environment by running:
source .venv/bin/activate

Windows

  • Activate your virtual environment by running:
.venv\Scripts\activate

Using PowerShell instead?

If you're using PowerShell, run .venv\Scripts\Activate.ps1 instead.

If you see a permissions error, run this first:

Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser

You should see (.venv) appear at the beginning of your terminal prompt. This confirms the virtual environment is active.

Don't see (.venv) in your prompt?

Make sure you're still inside the bookapi folder. Run pwd to check your location.

On Windows, try the PowerShell activation command instead if you're not using Command Prompt.

Help me activate my virtual environment

  • Install Django REST Framework (which includes Django as a dependency) by running:
pip install djangorestframework==3.17.1

You'll see pip downloading and installing several packages. This takes a minute.

  • Verify the installation succeeded by running:
pip show djangorestframework

You should see output showing Name: djangorestframework and Version: 3.17.1.

Seeing 'pip: command not found'?

This usually means your virtual environment isn't active. Check that (.venv) appears in your terminal prompt before running pip.

On macOS, you may need to use pip3 instead of pip if your virtual environment isn't activated.

Help me fix my pip installation

Create the Django project and books app

Django organizes code into a project (the overall configuration) and apps (individual features). Your project will be called bookapi and your first app will be called books.

  • Create the Django project in your current folder by running:
django-admin startproject bookapi .

What does the dot at the end do?

The trailing . tells Django to create the project files in your current directory instead of making another nested folder.

Without it, you'd end up with bookapi/bookapi/bookapi/ which gets confusing fast.

  • Confirm the project was created by running:
ls

You should see manage.py and a bookapi/ folder in the output.

  • Create the books app by running:
python manage.py startapp books
  • Confirm the app was created by running:
ls

You should now also see a books/ folder alongside manage.py and bookapi/.

Seeing 'django-admin: command not found'?

This means Django didn't install correctly or your virtual environment isn't active. Make sure (.venv) appears in your prompt, then try the pip install step again.

Help me fix my Django installation

Register your apps in settings

Django doesn't automatically know about new apps or third-party packages. You need to register them in your project's settings file.

  • Press Cmd+Space (macOS) or the Windows key (Windows) to open your search bar.
  • Type VS Code and press Enter to open it.
  • Click File in the top menu bar.
  • Click Open Folder.
  • Navigate to your Desktop and select the bookapi folder, then click Open.
  • In the Explorer sidebar on the left, expand the bookapi/ folder (the inner one, not the project root).
  • Click on settings.py to open it.
  • Find the INSTALLED_APPS list and replace it with the following:
INSTALLED_APPS = [
    "django.contrib.admin",
    "django.contrib.auth",
    "django.contrib.contenttypes",
    "django.contrib.sessions",
    "django.contrib.messages",
    "django.contrib.staticfiles",
    # Django REST Framework for building our API
    "rest_framework",
    # Our custom app for book and author data
    "books",
]

What does this code do?

The six django.contrib entries are Django's built-in apps that come pre-configured (admin panel, authentication, sessions, etc.).

You're adding two new entries. rest_framework enables DRF's serializers, viewsets, and the Browsable API. books tells Django to include the app you just created.

  • Save settings.py by pressing Cmd+S (macOS) or Ctrl+S (Windows).
  • Go back to your terminal and verify everything is wired up correctly by running:
python manage.py check

You should see System check identified no issues (0 silenced). in the output.

Seeing 'ModuleNotFoundError' or issues with the check?

Double-check that you spelled rest_framework with an underscore, not a hyphen. Also confirm books is lowercase and matches the folder name exactly.

Make sure each entry in INSTALLED_APPS ends with a comma and is wrapped in quotes.

Help me fix my INSTALLED_APPS configuration

✔️ Awesome, I've got everything!

Great. Make sure you've saved settings.py and move on to the next step.

ⓧ I'd like to double check the full code

Here's the complete INSTALLED_APPS section in bookapi/settings.py as it should look right now:

INSTALLED_APPS = [
    "django.contrib.admin",
    "django.contrib.auth",
    "django.contrib.contenttypes",
    "django.contrib.sessions",
    "django.contrib.messages",
    "django.contrib.staticfiles",
    "rest_framework",
    "books",
]

Your environment is ready and Django knows about your app. Next up, you'll define the Author and Book models that form the backbone of your API.

Define Your Models

Your Django project is set up and ready for code. Before you can build API endpoints, you need a data structure for the API to serve.

In Django, data structures live in models. Each model maps directly to a database table. In this step, you will define an Author model and a Book model, then let Django create the database tables for you.

In this step, get ready to:
  • Create Author and Book models with a foreign key relationship.
  • Run migrations to build the database tables.
  • Register models in the Django admin and create a superuser.
Create the Author model

Every book in your collection belongs to an author. You will define the Author model first because the Book model needs to reference it.

  • In the VS Code Explorer sidebar, open books/models.py.
  • Replace everything in the file with this code:
from django.db import models


class Author(models.Model):
    name = models.CharField(max_length=200)
    bio = models.TextField(blank=True)

    def __str__(self):
        return self.name

What does this code do?

  • Author inherits from models.Model, which tells Django this class maps to a database table.
  • CharField stores short text (like a name) with a max length. TextField stores longer text (like a biography) with no strict limit.
  • blank=True means the bio field is optional. Authors can exist without one.
  • __str__ controls how the model displays in the admin panel and shell. Without it, you would just see "Author object (1)".

You will not see a change yet. The next chunk adds the Book model that depends on this Author.

Create the Book model

The Book model is where things get interesting. It introduces a ForeignKey relationship that links every book to its author.

  • In books/models.py, add the following Book class below the Author class:
class Book(models.Model):
    title = models.CharField(max_length=300)
    author = models.ForeignKey(Author, related_name="books", on_delete=models.CASCADE)
    isbn = models.CharField(max_length=13, unique=True)
    published_date = models.DateField()
    description = models.TextField(blank=True)

    def __str__(self):
        return self.title

What does this code do?

  • ForeignKey(Author, related_name="books", on_delete=models.CASCADE) creates a many-to-one relationship. Many books can belong to one author. If the author is deleted, all their books are deleted too.
  • related_name="books" lets you access an author's books as author.books.all() in Python. This becomes important when building the serializers later.
  • unique=True on the ISBN field ensures no two books can have the same ISBN in your database.
  • DateField() stores dates in YYYY-MM-DD format.
  • Save books/models.py.

Seeing a red underline on Author in the ForeignKey?

Make sure the Author class is defined above the Book class in the same file. Python reads top to bottom, so Book can only reference Author if it appears first.

help me fix my models.py file

✔️ Awesome, I've got everything!

Great. Double check you have saved books/models.py before moving on.

ⓧ I'd like to double check the full code

from django.db import models


class Author(models.Model):
    name = models.CharField(max_length=200)
    bio = models.TextField(blank=True)

    def __str__(self):
        return self.name


class Book(models.Model):
    title = models.CharField(max_length=300)
    author = models.ForeignKey(Author, related_name="books", on_delete=models.CASCADE)
    isbn = models.CharField(max_length=13, unique=True)
    published_date = models.DateField()
    description = models.TextField(blank=True)

    def __str__(self):
        return self.title
Run migrations to create the database tables

Django does not create database tables the moment you write a model. Instead, it uses a two-step process called migrations. First you generate a migration file that describes the changes, then you apply it to the database.

  • Generate the migration file by running this command in your terminal:
python manage.py makemigrations

You should see output that says Migrations for 'books': books/migrations/0001_initial.py followed by a list of the Author and Book models being created.

  • Apply the migration to your database by running:
python manage.py migrate

You should see several lines of output ending with OK next to each migration being applied. This confirms your Author and Book tables now exist in the database.

Seeing "No changes detected"?

This means Django cannot find your models. Check that "books" is listed in INSTALLED_APPS inside bookapi/settings.py. Also confirm your models are saved in books/models.py (not a different file).

help me debug my makemigrations issue

Register models in the admin and create a superuser

The Django admin gives you a web interface to manage your data. You need to register each model so it appears in the admin panel.

  • Open books/admin.py in the Explorer sidebar.
  • Replace everything in the file with the following:
from django.contrib import admin
from .models import Author, Book

admin.site.register(Author)
admin.site.register(Book)

What does this code do?

admin.site.register() tells Django to display that model in the admin panel. Without these lines, you would have no way to add authors or books through the admin interface.

  • Save books/admin.py.

Now you need a superuser account to log into the admin panel.

  • Create a superuser by running this command:
python manage.py createsuperuser

What will this command ask?

The command prompts you for a username, email address, and password. The email is optional (you can press Enter to skip it). Choose a simple password you will remember for local development.

  • Enter a username, email (optional), and password when prompted.
  • Start the development server to verify everything works:
python manage.py runserver
  • Open your browser and go to http://127.0.0.1:8000/admin/.
  • Log in with the superuser credentials you just created.

You should see the Django administration panel with Authors and Books listed under the BOOKS section.

Don't see Authors and Books in the admin?

Make sure you saved books/admin.py after adding the register lines. Also confirm the import line reads from .models import Author, Book with a dot before models.

help me fix my Django admin registration

  • Stop the server by pressing Ctrl+C in your terminal when you are done verifying.

Your data layer is complete. You have models, a database, and an admin interface for managing records. Next up, you will build the serializers and viewsets that turn these models into a fully functional REST API.

Build Serializers and ViewSets

Your models define how data is stored in the database. But an API needs to send that data as JSON over HTTP. Something needs to translate between Python objects and JSON.

That translation layer is called a serializer. In this step, you'll create serializers for your models, build ViewSets that handle all the CRUD logic, and wire everything to URL routes so your API is live and testable in the browser.

In this step, get ready to:
  • Create serializers that convert model data to JSON and back.
  • Build ViewSets that handle list, create, retrieve, update, and delete operations.
  • Wire up URL routes and test CRUD in the Browsable API.
Create serializers for Author and Book

A ModelSerializer reads your model's fields and automatically generates the rules for converting instances to JSON. You tell it which model to use and which fields to expose.

  • In VS Code's Explorer sidebar, right-click the books folder and select New File.
  • Name the file serializers.py and press Enter.
  • Add the imports and your first serializer by pasting this code:
from rest_framework import serializers
from .models import Author, Book


# Converts Book model instances to/from JSON
class BookSerializer(serializers.ModelSerializer):
    class Meta:
        model = Book
        # Each field listed here appears in the API response
        fields = ["id", "title", "author", "isbn", "published_date", "description"]

What does this code do?

ModelSerializer inspects the Book model and generates validation rules for each field you list. When someone sends a POST request with JSON data, the serializer checks that the data is valid before saving it to the database.

The fields list controls exactly which fields appear in API responses. Adding "id" gives each book a unique identifier clients can use to fetch or update it.

  • Below BookSerializer, add the AuthorSerializer class:
# Includes all books by this author nested inside the response
class AuthorSerializer(serializers.ModelSerializer):
    # Uses BookSerializer to render each related book as JSON
    books = BookSerializer(many=True, read_only=True)

    class Meta:
        model = Author
        fields = ["id", "name", "bio", "books"]

What is a nested serializer?

The books field uses BookSerializer(many=True, read_only=True) to embed a list of the author's books directly inside the author's JSON response. This works because your Book model has related_name="books" on its foreign key to Author.

The read_only=True means you can't create books by sending them inside an author request. Books are created through their own endpoint.

  • Save books/serializers.py.

You won't see a change yet. The ViewSets you build next will use these serializers to handle API requests.

✔️ Awesome, I've got everything!

Great. Double check you've saved your file before moving on.

ⓧ I'd like to double check the full code

from rest_framework import serializers
from .models import Author, Book


class BookSerializer(serializers.ModelSerializer):
    class Meta:
        model = Book
        fields = ["id", "title", "author", "isbn", "published_date", "description"]


class AuthorSerializer(serializers.ModelSerializer):
    books = BookSerializer(many=True, read_only=True)

    class Meta:
        model = Author
        fields = ["id", "name", "bio", "books"]
Create ViewSets for your models

A ViewSet groups all the logic for a resource (list, create, retrieve, update, delete) into a single class. A ModelViewSet provides all five operations with just two lines of configuration.

  • Open books/views.py in VS Code and replace its contents with the following:
from rest_framework import viewsets
from .models import Author, Book
from .serializers import AuthorSerializer, BookSerializer


# Handles all CRUD operations for Author
class AuthorViewSet(viewsets.ModelViewSet):
    queryset = Author.objects.all()
    serializer_class = AuthorSerializer


# Handles all CRUD operations for Book
class BookViewSet(viewsets.ModelViewSet):
    queryset = Book.objects.all()
    serializer_class = BookSerializer

What does this code do?

  • queryset tells the ViewSet which database records to work with. Author.objects.all() means every author in the database.
  • serializer_class tells the ViewSet how to convert those records to JSON and validate incoming data.
  • ModelViewSet inherits from DRF's mixins to provide list, create, retrieve, update, and destroy actions automatically.
  • Save books/views.py.

You won't see a change yet. The URL router in the next substep connects these ViewSets to actual endpoints.

✔️ Awesome, I've got everything!

Great. Make sure you've saved before continuing.

ⓧ I'd like to double check the full code

from rest_framework import viewsets
from .models import Author, Book
from .serializers import AuthorSerializer, BookSerializer


class AuthorViewSet(viewsets.ModelViewSet):
    queryset = Author.objects.all()
    serializer_class = AuthorSerializer


class BookViewSet(viewsets.ModelViewSet):
    queryset = Book.objects.all()
    serializer_class = BookSerializer
Wire up URLs and test the Browsable API

ViewSets define what happens when a request arrives, but they don't know which URLs they respond to. A Router automatically generates URL patterns for each ViewSet you register.

  • Open bookapi/urls.py and replace its contents with the following:
from django.contrib import admin
from django.urls import path, include
from rest_framework.routers import DefaultRouter
from books.views import AuthorViewSet, BookViewSet

# Auto-generates URL patterns for each registered ViewSet
router = DefaultRouter()
router.register(r"authors", AuthorViewSet)
router.register(r"books", BookViewSet)

urlpatterns = [
    path("admin/", admin.site.urls),
    # All API endpoints live under /api/
    path("api/", include(router.urls)),
    # Adds login/logout buttons to the Browsable API
    path("api-auth/", include("rest_framework.urls", namespace="rest_framework")),
]

What does this code do?

  • DefaultRouter() creates a router that generates URL patterns like /api/books/ (list) and /api/books/1/ (detail) for each registered ViewSet.
  • router.register(r"authors", AuthorViewSet) maps the AuthorViewSet to the /api/authors/ URL prefix.
  • The api-auth/ path adds login and logout buttons to DRF's Browsable API so you can test authenticated requests in the browser.
  • Save bookapi/urls.py.
  • Start the development server by running this command in your terminal:
python manage.py runserver
  • Open your browser and navigate to http://127.0.0.1:8000/api/.

You should see DRF's Browsable API page with links to your authors and books endpoints listed on the page.

What is the Browsable API?

DRF automatically renders your API as an interactive HTML page when you visit it in a browser. You can create, read, update, and delete records directly from this page without needing tools like Postman or curl.

  • Click the authors link to visit http://127.0.0.1:8000/api/authors/.
  • Scroll to the bottom of the page where you see the HTML form.
  • Enter a name (like J.K. Rowling) in the Name field and a short bio in the Bio field.
  • Click POST.

The page refreshes and shows your new author as JSON with an id field and an empty books array. That confirms your serializer, ViewSet, and router are all working together.

  • Now click the books link in the top navigation (or visit http://127.0.0.1:8000/api/books/).
  • Create a book using the HTML form at the bottom. Enter a title, select your author from the Author dropdown, enter a 13-character ISBN (like 9780747532743), a published date (like 1997-06-26), and a description.
  • Click POST.

You should see the book's JSON response with all the fields you entered.

Seeing an error when you visit the API?

  • If you see ModuleNotFoundError, check that your virtual environment is still active. You should see (.venv) at the start of your terminal prompt.
  • If you see ImportError: cannot import name 'AuthorViewSet', make sure books/views.py is saved and that the class names match exactly.
  • If you see a Page not found error, check that you're visiting /api/ (with the trailing slash), not just /.

Help me debug my Browsable API error

✔️ Awesome, I've got everything!

Great. Double check you've saved all three files before moving on.

ⓧ I'd like to double check the full code

from django.contrib import admin
from django.urls import path, include
from rest_framework.routers import DefaultRouter
from books.views import AuthorViewSet, BookViewSet

router = DefaultRouter()
router.register(r"authors", AuthorViewSet)
router.register(r"books", BookViewSet)

urlpatterns = [
    path("admin/", admin.site.urls),
    path("api/", include(router.urls)),
    path("api-auth/", include("rest_framework.urls", namespace="rest_framework")),
]

Your API is live with full CRUD support for both authors and books. Next up, you'll lock it down so only authenticated users can create, update, or delete records.

Add Authentication and Permissions

Your API currently lets anyone create, edit, and delete books. That's fine for testing, but a real API needs access control.

In this step, you'll add token-based authentication so the API can verify who is making a request. You'll also add permission classes that allow anyone to read data, but only authenticated users to write.

In this step, get ready to:
  • Configure Token authentication and permission classes in your Django settings.
  • Create an auth token for your superuser.
  • Test that unauthenticated users can only read, while authenticated users can write.
Configure Token authentication in settings

DRF supports multiple authentication schemes. Token authentication assigns a unique string to each user. Clients include this token in the HTTP Authorization header to prove their identity.

  • Open bookapi/settings.py in VS Code.
  • Find the INSTALLED_APPS list. Locate this section:
    "rest_framework",
    "books",
]
  • Add "rest_framework.authtoken" between "rest_framework" and "books", so the list now looks like this:
    "rest_framework",
    "rest_framework.authtoken",
    "books",
]
  • Now add the following REST_FRAMEWORK configuration block below the INSTALLED_APPS list. Copy this code and paste it after the closing ] of INSTALLED_APPS:
REST_FRAMEWORK = {
    "DEFAULT_AUTHENTICATION_CLASSES": [
        "rest_framework.authentication.TokenAuthentication",
        "rest_framework.authentication.SessionAuthentication",
    ],
    "DEFAULT_PERMISSION_CLASSES": [
        "rest_framework.permissions.IsAuthenticatedOrReadOnly",
    ],
    "DEFAULT_PAGINATION_CLASS": "rest_framework.pagination.PageNumberPagination",
    "PAGE_SIZE": 10,
}

What does this configuration do?

  • DEFAULT_AUTHENTICATION_CLASSES tells DRF how to identify users. TokenAuthentication checks for a token in the header. SessionAuthentication keeps the Browsable API login working.
  • DEFAULT_PERMISSION_CLASSES controls what authenticated vs unauthenticated users can do. IsAuthenticatedOrReadOnly means anyone can GET, but only logged-in users can POST, PUT, or DELETE.
  • PAGE_SIZE limits API responses to 10 results per page. This prevents your API from dumping thousands of records in a single response.
  • Save bookapi/settings.py.
  • The rest_framework.authtoken app needs its own database table to store tokens. Run migrations by entering this command in your terminal:
python manage.py migrate

You should see output that includes Applying authtoken.0001_initial... OK. This confirms the token table was created.

Seeing an error during migrate?

  • Check that "rest_framework.authtoken" is spelled exactly right in your INSTALLED_APPS list. A missing comma or typo will cause an import error.
  • Make sure your virtual environment is active. You should see (.venv) at the start of your terminal prompt.

Help me fix my migration error.

Create a token for your superuser

Each user who needs API write access needs their own token. DRF includes a management command that generates one instantly.

  • Generate a token for your superuser by running this command (replace admin with whatever username you chose when creating your superuser):
python manage.py drf_create_token [[SUPERUSER_NAME="your superuser username"]]

You should see output like:

Generated token abc123def456 for user admin

Copy your token now

Copy the long token string from the output. You'll use it in the next substep to authenticate your API requests.

Command not found?

If you see Unknown command: 'drf_create_token', make sure you ran python manage.py migrate after adding rest_framework.authtoken to INSTALLED_APPS. The management command comes from that app.

Help me fix the drf_create_token command.

Test that permissions protect your API

Your permission classes are now active. Time to prove they work by making requests with and without your token.

  • Make sure your development server is running. If it's not, start it by running:
python manage.py runserver
  • Open a second terminal window (keep the server running in the first one).
  • First, confirm that unauthenticated reads still work. Test a GET request by running:
curl http://127.0.0.1:8000/api/books/

You should see a JSON response with your books (or an empty list if you haven't created any yet). The read worked without a token.

  • Now try to create a book without a token. This should be blocked by your permission classes. Run:
curl -X POST http://127.0.0.1:8000/api/books/ -H "Content-Type: application/json" -d '{"title": "Test", "author": 1, "isbn": "1234567890123", "published_date": "2024-01-01"}'

You should see a 401 Unauthorized response with "detail": "Authentication credentials were not provided.". Your permissions are working.

  • Finally, try the same POST request with your token in the Authorization header. Replace the token value with the one you copied earlier:
curl -X POST http://127.0.0.1:8000/api/books/ -H "Content-Type: application/json" -H "Authorization: Token your-token-here" -d '{"title": "Test Book", "author": 1, "isbn": "1234567890123", "published_date": "2024-01-01"}'

What's happening with these three requests?

  • GET without token: Allowed. IsAuthenticatedOrReadOnly permits read-only access for everyone.
  • POST without token: Blocked. Write operations require authentication.
  • POST with token: Allowed. The token proves your identity, so DRF grants write access.

If the authenticated POST returned a 201 Created response with your book's JSON data, everything is working correctly.

Don't have an author yet?

The POST request above references "author": 1. If you haven't created an author yet, you'll get a validation error. Create one first through the Browsable API at http://127.0.0.1:8000/api/authors/ (log in with your superuser credentials using the **Log in** button in the top right).

Authenticated POST still returning 401?

  • Check the header format is exactly Authorization: Token <your-token>. The word Token (capital T) followed by a space and then the token string is required.
  • Make sure you copied the full token string with no extra spaces or missing characters.
  • Verify that "rest_framework.authentication.TokenAuthentication" is in your DEFAULT_AUTHENTICATION_CLASSES list in settings.

Help me debug my token authentication.

✔️ Awesome, I've got everything!

Great. Double check you've saved bookapi/settings.py and that your authenticated POST returned a 201 Created response.

ⓧ I'd like to double check the full code

Here's the complete bookapi/settings.py with all the additions from this step (showing only the relevant sections):

INSTALLED_APPS = [
    "django.contrib.admin",
    "django.contrib.auth",
    "django.contrib.contenttypes",
    "django.contrib.sessions",
    "django.contrib.messages",
    "django.contrib.staticfiles",
    "rest_framework",
    "rest_framework.authtoken",
    "books",
]

REST_FRAMEWORK = {
    "DEFAULT_AUTHENTICATION_CLASSES": [
        "rest_framework.authentication.TokenAuthentication",
        "rest_framework.authentication.SessionAuthentication",
    ],
    "DEFAULT_PERMISSION_CLASSES": [
        "rest_framework.permissions.IsAuthenticatedOrReadOnly",
    ],
    "DEFAULT_PAGINATION_CLASS": "rest_framework.pagination.PageNumberPagination",
    "PAGE_SIZE": 10,
}

Your API is now secured. Unauthenticated visitors can browse your book collection, but only token-holding users can modify it. In the Secret Mission, you'll add filtering and search so users can find exactly the books they're looking for.

Secret mission

Add Filtering and Search

Your API works, but finding specific books requires scrolling through everything. Real APIs let users filter and search. Can you add those capabilities to your Book API?

Clean Up Your Resources

Clean Up Your Resources

This project runs entirely locally on your machine, so there are no ongoing costs or cloud resources to worry about. Decide whether to keep your project files intact, stop the development server, or delete everything entirely.

Resources you used:

  • Virtual environment (.venv folder) with Django and DRF installed.
  • Django project files (bookapi project and books app).
  • SQLite database (db.sqlite3) storing your authors, books, and auth tokens.
  • Django superuser account (local to this project only).

Keep everything running

No action needed. Choose this if you're still actively building on your API or plan to extend it with the Secret Mission.

  • Your project folder stays on your Desktop.
  • The development server only runs when you start it with python manage.py runserver, so it won't consume resources in the background.
  • To resume work later, activate your virtual environment and start the server again.

Pause - I'll come back to this later

Stop the development server to free up your terminal. Your files and database stay intact for when you return.

  • Press Ctrl+C in the terminal where your server is running to stop it.
  • Run deactivate to exit your virtual environment.
  • When you're ready to resume, navigate back to your project folder, activate the virtual environment, and run the server again.

Delete - I don't want to use this again

Remove all project files, the virtual environment, and the database completely.

  • Press Ctrl+C in your terminal to stop the server if it is still running.
  • Run deactivate to exit the virtual environment.
  • Delete your entire project folder from the Desktop. This removes the virtual environment, all project code, and the SQLite database in one step.

Nice Work!

Nice Work!

You just built a fully functional REST API from scratch using Django and Django REST Framework. Your API handles creating, reading, updating, and deleting books and authors, all protected by token-based authentication.

Here's what you learned:

  • Built Django models with a foreign key relationship connecting Authors to Books, and managed your database schema with migrations.
  • Created serializers and ViewSets that handle full CRUD operations, wired up with a Router for automatic URL configuration.
  • Added Token authentication and permission classes to protect write endpoints while keeping read access open to everyone.
  • Added filtering and search capabilities to make your API production-ready.

Ready to quiz yourself?