39
loading...
This website collects cookies to deliver better user experience
# Install the packages, and creates a virtual environment
pipenv install django djangorestframework
# Activates the virtual environment
pipenv shell
django-admin startproject api .
.
character at the end to start the project in the current folder. This way I have the manage.py
file in the same folder as Pipfile
, and just one folder. So our folder structure should look like this.
├── api
│ ├── asgi.py
│ ├── __init__.py
│ ├── settings.py
│ ├── urls.py
│ └── wsgi.py
├── manage.py
├── Pipfile
└── Pipfile.lock
.
, we would have the following structure..
├── api
│ ├── api
│ │ ├── asgi.py
│ │ ├── __init__.py
│ │ ├── settings.py
│ │ ├── urls.py
│ │ └── wsgi.py
│ └── manage.py
├── Pipfile
└── Pipfile.lock
INTALLED_APPS
on api/settings.py
.INSTALLED_APPS = [
'rest_framework',
...
]
python manage.py migrate
python manage.py startapp books
INSTALLED_APPS
on api/settings.py
INSTALLED_APPS = [
'books.apps.BooksConfig',
...
]
books/models.py
file so it looks like this:from django.db import models
class Book(models.Model):
title = models.CharField(max_length=200)
description = models.TextField(blank=True
# Create migrations for Books app
python manage.py makemigrations books
# Sync the database
python manage.py migrate
Every time we add a new app to INSTALLED_APPS
or change a model, we can tell Django to create the migrations, with the makemigrations
command. When we're ready we can sync it with the migrate
command.
books/serializers.py
with the serializer for the Book model.from rest_framework import serializers
from books.models import Book
class BookSerializer(serializers.ModelSerializer):
class Meta:
model = Book
fields = ["id", "title", "description"]
books/views.py
add the following.from rest_framework import generics
from books.models import Book
from books.serializers import BookSerializer
class BookList(generics.ListCreateAPIView):
queryset = Book.objects.all()
serializer_class = BookSerializer
books/urls.py
and connect the view to the root of the route.from django.urls import path
from books.views import BookList
urlpatterns = [
path("", BookList.as_view(), name="index"),
]
books
to the Book app, by adding it to api/urls.py
:from django.urls import include, path
urlpatterns = [
...,
path("books/", include("books.urls")),
]
python manage.py runserver
Performing system checks...
System check identified no issues (0 silenced).
August 25, 2021 - 22:47:34
Django version 3.2.6, using settings 'api.settings'
Starting development server at http://127.0.0.1:8000/
Quit the server with CONTROL-C.
POST
request to http://127.0.0.1:8000/books/
, with the book title and description.http http://127.0.0.1:8000/books/ title='Cool book' description='Long description'
HTTP/1.1 201 Created
...
{
"description": "Long description",
"id": 1,
"title": "Cool book"
}
GET
request to http http://127.0.0.1:8000/books/
we get a list of existing books.http http://127.0.0.1:8000/books/
HTTP/1.1 200 OK
...
[
{
"description": "Long description",
"id": 1,
"title": "Cool book"
},
{
"description": "Long description of another book",
"id": 2,
"title": "Fantasy book title"
}
]
http://127.0.0.1:8000/books
in our browser we should see the following screen, where it lists all the books saved in our database, and we can use the POST
method to add more books.manage.py
file run the commandpython manage.py startapp users
api/settings.py
INSTALLED_APPS = [
'users.apps.UsersConfig',
...
]
users/serializer.py
and add the users serializer:from rest_framework import serializers
from django.contrib.auth.models import User
class UserSerializer(serializers.ModelSerializer):
class Meta:
model = User
fields = ["username", "email", "password"]
extra_kwargs = {"password": {"write_only": True}}
def create(self, validated_data):
user = User(email=validated_data["email"], username=validated_data["username"])
user.set_password(validated_data["password"])
user.save()
return user
set_password
method so that we store the password hash instead of the actual password on the database, for security reasons. We set the password field to write_only, this way we can send a password when creating the user, but when we fetch the users list, it is not returned.users/views.py
.from django.contrib.auth.models import User
from users.serializers import UserSerializer
from rest_framework import generics
class UserCreate(generics.ListCreateAPIView):
queryset = User.objects.all()
serializer_class = UserSerializer
users/urls.py
from django.urls import path
from users import views
urlpatterns = [
path('', views.UserCreate.as_view()),
]
users
routes on api/urls.py
:urlpatterns = [
...,
path("users/", include("users.urls")),
]
http http://127.0.0.1:8000/users/ username='Luke' email='[email protected]' password='lukespassword'
HTTP/1.1 201 Created
...
{
"email": "[email protected]",
"username": "Luke"
}
GET
request we'll get a list of all users.http http://127.0.0.1:8000/users/
HTTP/1.1 200 OK
...
[
{
"email": "[email protected]",
"username": "Luke"
},
{
"email": "[email protected]",
"username": "Leia"
}
]
rest_framework.authtoken
to our installed apps on api/settings.py
.INSTALLED_APPS = [
'rest_framework.authtoken',
...,
]
python manage.py migrate
obtain_auth_token
for handling user authentication. All we need is to connect it into a route path. Into users/urls.py
add the import and plug the view.from rest_framework.authtoken.views import obtain_auth_token
urlpatterns = [
...,
path('login/', obtain_auth_token)
]
http http://127.0.0.1:8000/users/login/ username='Luke' password='lukespassword'
HTTP/1.1 200 OK
...
{
"token": "6650c889f12dafb1cff9dd50b58254f47df67288"
}
Authorization
HTTP header in our future requests in the format bellow, this way the API can provide us with the correct permissions. For instance, for the token above, the header would be:Authorization: Token 6650c889f12dafb1cff9dd50b58254f47df67288
Token
and the token itself.books/views.py
, set permission_classes
to tell it the type of permission we want. Also set authentication_classes
to the authentication method being used.from rest_framework.authentication import TokenAuthentication
from rest_framework.permissions import IsAuthenticatedOrReadOnly
class BookList(generics.ListCreateAPIView):
queryset = Book.objects.all()
serializer_class = BookSerializer
permission_classes = [IsAuthenticatedOrReadOnly]
authentication_classes = [TokenAuthentication]
http http://127.0.0.1:8000/books/ title='Sad book' description="I won't work"
HTTP/1.1 401 Unauthorized
...
{
"detail": "Authentication credentials were not provided."
}
X
bellow with the token returned for your user, it works!http http://127.0.0.1:8000/books/ title='Happy book' description="I work" Authorization:"Token XXXXXXXXXXXXXXXXX"
HTTP/1.1 201 Created
...
{
"description": "I work",
"id": 3,
"title": "Happy book"
}