# Django Rest Framework Tutorial: Todo API

Django REST framework is a powerful and flexible toolkit for building Web APIs. It is a powerful library that sits on top of existing Django projects to add robust web APIs. If you have an existing Django project with only models and a database--no views, urls, or templates required--you can quickly transform it into a RESTful API with a minimal amount of code. In this tutorial, we'll create a basic Django *To Do* app web API using serializers, viewsets, and routers.

## **Prerequisites**

You should have a basic understanding of how Django works and a local development configuration with Python 3.

## **Initial Setup**

Let's start by creating a directory for our code, installing Django, and creating a new project. Execute the following on the command line.

```python
$ cd ~/Destkop
$ mkdir todo && cd todo
$ pipenv install django~=3.1.0
$ pipenv shell
(todo) $ django-admin startproject config .
(todo) $ python manage.py startapp todo
```

We're placing the code on the `Desktop` but it can live anywhere you choose on your computer. We've used Pipenv to install Django and then enter a dedicated virtual environment. And finally created a new Django project called `config` which has a `todo` app.

Since we have a new app, we need to update our `INSTALLED_APPS` setting. Open `config/settings.py` with your text editor and add `todo` at the bottom of the list.

```python
# config/settings.py
INSTALLED_APPS = [
  ...
  'todo', # new
]
```

Perform our first migration to set up the initial database at this point.

```python
(todo) $ python manage.py migrate
```

Next, we can create a basic model for our `Todo` app which will just have a `title`, `description`, and add a `__str__` method.

```python
# todo/models.py
from django.db import models


class Todo(models.Model):
    title = models.CharField(max_length=200)
    description = models.TextField()

    def __str__(self):
        return self.title
```

Then create a migration file and migrate our change to the project database.

```python
(todo) $ python manage.py makemigrations todo
(todo) $ python manage.py migrate
```

The final step is to update the [`admin.py`](http://admin.py) file so the `todo` app is visible when we log into the admin.

```python
# todo/admin.py
from django.contrib import admin

from .models import Todo

admin.site.register(Todo)
```

In a normal Django app at this point, we would need to add URLs, views, and templates to display our content. But since our end goal is an API that will transmit the data over the internet, we don't actually need anything beyond our [`models.py`](http://models.py) file!

Let's create a superuser account so we can log into the admin and add some data to our model. Follow the prompts to add a name, email, and password. If you're curious, I've used `user`, [`user@email.com`](mailto:admin@email.com), and `1234567890` since this example is for learning purposes. Obviously use a name and password that are more secure on a real site!

```python
(todo) $ python manage.py createsuperuser
(todo) $ python manage.py runserver
```

Navigate to [`http://127.0.0.1:8000/admin`](http://127.0.0.1:8000/admin) on your browser and log in with your new superuser account.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1671898909786/527fd8f9-8919-4bb2-863c-c271057e1c18.png align="center")

On the Admin homepage you should see the `todo` app. Click on the "+ Add" button for Todow and add two new entries we can use. I've called mine the following:

* title: learn Django; description: learn Django
    
* title: learn python; description: learn python
    
    ![](https://cdn.hashnode.com/res/hashnode/image/upload/v1671900707696/4fa20a0f-e031-4f98-b084-b2b488a63fc4.png align="center")
    

Now it's time for Django Rest Framework.

## **Django Rest Framework**

The first step is to install Django Rest Framework.

On the command line stop the server with `Control+c` and then enter the following.

```python
(todo) $ pipenv install djangorestframework
```

Next, add `rest_framework` app to our `INSTALLED_APPS` setting

```python
# config/settings.py
INSTALLED_APPS = [
    ...
    'rest_framework', # new
    'todo',
]
```

The next step is to Configure the URL for our API endpoints in `config/urls.py`.

```python
# config/urls.py
from django.contrib import admin
from django.urls import path, include

urlpatterns = [
    path('admin/', admin.site.urls),
    path('api/', include('todo.urls'))
]
```

we added `todo.urls` but we haven't created it, so let's create a file inside the todo directory and name it urls.py and add these lines:

```python
# todo/urls.py

from django.urls import path
from .views import ListTodo, DetailTodo, CreateTodo


urlpatterns = [
    path('<int:pk>/', DetailTodo.as_view()),
    path('', ListTodo.as_view()),
    path('create', CreateTodo.as_view())
]
```

we imported the `ListTodo, DetailTodo` and `CreateTodo` which we yet have to create these classes. and `urlspatterns` is where we create our routes. `<int:pk>` is passing the Primary key as a URL query.

#### Serializer (JSON)

we need a serializer file to transpile the python queryset to JSON in order to send it over HTTP request. let's go ahead and create a file `todo/serializer.py`

```python
from rest_framework import serializers
from .models import Todo


class TodoSerializer(serializers.ModelSerializer):
    class Meta:
        model = Todo
        fields = ('id', 'title', ' description')
```

Importing the Todo Model and exposing the `id, title, and description` field as JSON in the `Meta` class. `model` variable is which model we need to transpile and fields are which fields we need to expose. the `id` field is created automatically when adding a new object

#### View

open the `todo/views.py` file and the logic

```python
from rest_framework import generics
from .serializers import TodoSerializer
from .models import Todo


# Showing the List
class ListTodo(generics.ListAPIView):
    queryset = Todo.objects.all()
    serializer_class = TodoSerializer

# fetching single todo
class DetailTodo(generics.RetrieveAPIView):
    queryset = Todo.objects.all()
    serializer_class = TodoSerializer

# creating one
class CreateTodo(generics.CreateAPIView):
    queryset = Todo.objects.all()
    serializer_class = TodoSerializer
```

now run the server and head over to '[http://127.0.0.1:8000/api/create\`  
](http://127.0.0.1:8000/api/create`￼)

```python
$(todo) $ python manage.py runserver
```

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1671929373089/159a5895-e4bd-4460-961a-3f9172e01729.png align="center")

it will let you create a new todo, and play around with it.
