In this tutorial, we’re gonna create Python 3/Django & MongoDB CRUD example with Django Rest Framework for building Rest Apis. You’ll know:
- How to setup Django to connect with MongoDB Database
- How to define Data Models and migrate it to MongoDB
- Way to use Django Rest Framework to process HTTP requests
- Way to make Django CRUD Operations with MongoDB Database
Related Post: Django CRUD with MySQL example | Django Rest Framework
Fullstack:
– Django + Angular 8
– Django + Angular 10
– Django + Angular 11
– Django + React
– Django + React Hooks
– Django + Vue.js
Contents
- Django MongoDB CRUD Rest API overview
- Architecture
- Technology
- Project structure
- Install Django REST framework
- Setup new Django project
- Connect Django project to MongoDB database
- Setup new Django app for Rest CRUD Api
- Configure CORS and middleware
- Define the Django Model
- Migrate Data Model to MongoDB database
- Create Serializer class for Data Model
- Define Routes to Views functions
- Write API Views
- Test the CRUD with APIs
- Conclusion
- Further Reading
- Source code
Django MongoDB CRUD Rest API overview
We will build Rest Apis using Django Rest Framework that can create, retrieve, update, delete and find Tutorials by title or published status.
First, we setup Django Project with a MongoDB Connector. Next, we create Rest Api app, add it with Django Rest Framework to the project. Next, we define data model and migrate it to the database. Then we write API Views and define Routes for handling all CRUD operations (including custom finder).
The following table shows overview of the Rest APIs that will be exported:
Methods | Urls | Actions |
---|---|---|
GET | api/tutorials | get all Tutorials |
GET | api/tutorials/:id | get Tutorial by id |
POST | api/tutorials | add new Tutorial |
PUT | api/tutorials/:id | update Tutorial by id |
DELETE | api/tutorials/:id | remove Tutorial by id |
DELETE | api/tutorials | remove all Tutorials |
GET | api/tutorials/published | find all published Tutorials |
GET | api/tutorials?title=[kw] | find all Tutorials which title contains 'kw' |
Finally, we’re gonna test the Rest Apis using Postman.
Architecture
This diagram shows the architecture of our Django CRUD Rest Apis App with MongoDB database:
- HTTP requests will be matched by Url Patterns and passed to the Views
- Views processes the HTTP requests and returns HTTP responses (with the help of Serializer)
- Serializer serializes/deserializes data model objects
- Models contains essential fields and behaviors for CRUD Operations with MongoDB Database
Technology
- Python 3.7
- Django 2.1.15
- Django Rest Framework 3.11.0
- djongo 1.3.1
- django-cors-headers 3.2.1
- MongoDB 3.4 or higher
Project structure
This is the directory structure of our Django Project:
Let me explain it briefly.
- tutorials/apps.py: declares
TutorialsConfig
class (subclass ofdjango.apps.AppConfig
) that represents Rest CRUD Apis app and its configuration. - DjangoRestApiMongoDB/settings.py: contains settings for our Django project: MongoDB Database engine,
INSTALLED_APPS
list with Django REST framework, Tutorials Application, CORS andMIDDLEWARE
. - tutorials/models.py: defines Tutorial data model class (subclass of
django.db.models.Model
). - migrations/0001_initial.py: is created when we make migrations for the data model, and will be used for generating MongoDB database collection.
- tutorials/serializers.py: manages serialization and deserialization with
TutorialSerializer
class (subclass ofrest_framework.serializers.ModelSerializer
). - tutorials/views.py: contains functions to process HTTP requests and produce HTTP responses (using
TutorialSerializer
). - tutorials/urls.py: defines URL patterns along with request functions in the Views.
- DjangoRestApiMongoDB/urls.py: also has URL patterns that includes
tutorials.urls
, it is the root URL configurations.
Install Django REST framework
Django REST framework helps us to build RESTful Web Services flexibly.
To install this package, run command:
pip install djangorestframework
Setup new Django project
Let’s create a new Django project with command:
django-admin startproject DjangoRestApiMongoDB
You can see the following folder tree when the process is done.
Now open settings.py and add Django REST framework to the INSTALLED_APPS
array here.
INSTALLED_APPS = [
...
# Django REST framework
'rest_framework',
]
Connect Django project to MongoDB database
We need a Django MongoDb connector to work with MongoDb database.
In this tutorial, we’re gonna use djongo.
Run the command: pip install djongo
.
Then we need to setup MongoDb Database engine.
So open settings.py and change declaration of DATABASES
:
DATABASES = {
'default': {
'ENGINE': 'djongo',
'NAME': 'bezkoder_db',
'HOST': '127.0.0.1',
'PORT': 27017,
}
}
Setup new Django app for Rest CRUD Api
Run following commands to create new Django app tutorials:
cd DjangoRestApiMongoDB
python manage.py startapp tutorials
The project directory now looks like:
Open tutorials/apps.py, you can see TutorialsConfig
class (subclass of django.apps.AppConfig
). This is the Django app and its configuration that we’ve just created.
from django.apps import AppConfig
class TutorialsConfig(AppConfig):
name = 'tutorials'
Don’t forget to add this app to INSTALLED_APPS
array in settings.py:
INSTALLED_APPS = [
...
# Tutorials application
'tutorials.apps.TutorialsConfig',
]
Configure CORS and middleware
We need to allow requests to our Django application from other origins.
In this example, we’re gonna configure CORS to accept requests from localhost:8081
.
First, install the django-cors-headers library:
pip install django-cors-headers
In settings.py, add configuration for CORS:
INSTALLED_APPS = [
...
# CORS
'corsheaders',
]
You also need to add a middleware class to listen in on responses:
MIDDLEWARE = [
...
# CORS
'corsheaders.middleware.CorsMiddleware',
'django.middleware.common.CommonMiddleware',
]
Note: CorsMiddleware
should be placed as high as possible, especially before any middleware that can generate responses such as CommonMiddleware
.
Next, set CORS_ORIGIN_ALLOW_ALL and add the host to CORS_ORIGIN_WHITELIST:
CORS_ORIGIN_ALLOW_ALL = False
CORS_ORIGIN_WHITELIST = (
'http://localhost:8081',
)
- CORS_ORIGIN_ALLOW_ALL: If
True
, all origins will be accepted (not use the whitelist below). Defaults toFalse
. - CORS_ORIGIN_WHITELIST: List of origins that are authorized to make cross-site HTTP requests. Defaults to
[]
.
Define the Django Model
Open tutorials/models.py, add Tutorial
class as subclass of django.db.models.Model
.
There are 3 fields: title, description, published.
from django.db import models
class Tutorial(models.Model):
title = models.CharField(max_length=70, blank=False, default='')
description = models.CharField(max_length=200,blank=False, default='')
published = models.BooleanField(default=False)
Each field is specified as a class attribute, and each attribute maps to a database column.
id field is added automatically.
Migrate Data Model to MongoDB database
Run the Python script: python manage.py makemigrations tutorials
.
The console will show:
Migrations for 'tutorials':
tutorials\migrations\0001_initial.py
- Create model Tutorial
New file 0001_initial.py has just been generated in tutorials/migrations folder. It includes code to create Tutorial
data model:
# Generated by Django 2.1.15
from django.db import migrations, models
class Migration(migrations.Migration):
initial = True
dependencies = [
]
operations = [
migrations.CreateModel(
name='Tutorial',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('title', models.CharField(default='', max_length=70)),
('description', models.CharField(default='', max_length=200)),
('published', models.BooleanField(default=False)),
],
),
]
The generated code defines Migration
class (subclass of the django.db.migrations.Migration
).
It has operations array that contains operation for creating collection for Customer model: migrations.CreateModel()
.
The call to this will create a new model in the project history and a corresponding collection in the MongoDB database to match it.
Now run the following Python script to apply the generated migration above:
python manage.py migrate tutorials
The console will show:
Operations to perform:
Apply all migrations: tutorials
Running migrations:
Applying tutorials.0001_initial... OK
Check MongoDB database, you can see that a collection for Tutorial
model was generated automatically with the name: tutorials_tutorial:
Create Serializer class for Data Model
Let’s create TutorialSerializer
class that will manage serialization and deserialization from JSON.
It inherit from rest_framework.serializers.ModelSerializer
superclass which automatically populates a set of fields
and default validators
. We need to specify the model class here.
tutorials/serializers.py
from rest_framework import serializers
from tutorials.models import Tutorial
class TutorialSerializer(serializers.ModelSerializer):
class Meta:
model = Tutorial
fields = ('id',
'title',
'description',
'published')
In the inner class Meta
, we declare 2 attributes:
model
: the model for Serializerfields
: a tuple of field names to be included in the serialization
Define Routes to Views functions
Let determine how the server will response for HTTP request (GET, POST, PUT, DELETE) with some endpoints. We’re gonna define the routes:
/api/tutorials
: GET, POST, DELETE/api/tutorials/:id
: GET, PUT, DELETE/api/tutorials/published
: GET
Inside tutorials app, create urls.py file with urlpatterns
containing url
s to be matched with the functions in the views.py:
from django.conf.urls import url
from tutorials import views
urlpatterns = [
url(r'^api/tutorials$', views.tutorial_list),
url(r'^api/tutorials/(?P<pk>[0-9]+)$', views.tutorial_detail),
url(r'^api/tutorials/published$', views.tutorial_list_published)
]
Don’t forget to include this URL patterns in root URL configurations.
Open DjangoRestApiMongoDB/urls.py and modify the content with the following code:
from django.conf.urls import url, include
urlpatterns = [
url(r'^', include('tutorials.urls')),
]
Write API Views
Now we create the functions that are pointed in Url Patterns above:
– tutorial_list()
: GET list of tutorials, POST a new tutorial, DELETE all tutorials
– tutorial_detail()
: GET / PUT / DELETE tutorial by ‘id’
– tutorial_list_published()
: GET all published tutorials
These functions process HTTP requests and make CRUD Operations to database via Django Model.
Open tutorials/views.py and write following code:
from django.shortcuts import render
from django.http.response import JsonResponse
from rest_framework.parsers import JSONParser
from rest_framework import status
from tutorials.models import Tutorial
from tutorials.serializers import TutorialSerializer
from rest_framework.decorators import api_view
@api_view(['GET', 'POST', 'DELETE'])
def tutorial_list(request):
# GET list of tutorials, POST a new tutorial, DELETE all tutorials
@api_view(['GET', 'PUT', 'DELETE'])
def tutorial_detail(request, pk):
# find tutorial by pk (id)
try:
tutorial = Tutorial.objects.get(pk=pk)
except Tutorial.DoesNotExist:
return JsonResponse({'message': 'The tutorial does not exist'}, status=status.HTTP_404_NOT_FOUND)
# GET / PUT / DELETE tutorial
@api_view(['GET'])
def tutorial_list_published(request):
# GET all published tutorials
Let’s implement these functions.
Create a new object
Create and Save a new Tutorial:
@api_view(['GET', 'POST', 'DELETE'])
def tutorial_list(request):
...
elif request.method == 'POST':
tutorial_data = JSONParser().parse(request)
tutorial_serializer = TutorialSerializer(data=tutorial_data)
if tutorial_serializer.is_valid():
tutorial_serializer.save()
return JsonResponse(tutorial_serializer.data, status=status.HTTP_201_CREATED)
return JsonResponse(tutorial_serializer.errors, status=status.HTTP_400_BAD_REQUEST)
Retrieve objects (with condition)
Retrieve all Tutorials/ find by title
from MongoDB database:
@api_view(['GET', 'POST', 'DELETE'])
def tutorial_list(request):
if request.method == 'GET':
tutorials = Tutorial.objects.all()
title = request.GET.get('title', None)
if title is not None:
tutorials = tutorials.filter(title__icontains=title)
tutorials_serializer = TutorialSerializer(tutorials, many=True)
return JsonResponse(tutorials_serializer.data, safe=False)
# 'safe=False' for objects serialization
Retrieve a single object
Find a single Tutorial with an id
:
@api_view(['GET', 'PUT', 'DELETE'])
def tutorial_detail(request, pk):
# ... tutorial = Tutorial.objects.get(pk=pk)
if request.method == 'GET':
tutorial_serializer = TutorialSerializer(tutorial)
return JsonResponse(tutorial_serializer.data)
Update an object
Update a Tutorial by the id
in the request:
@api_view(['GET', 'PUT', 'DELETE'])
def tutorial_detail(request, pk):
# ... tutorial = Tutorial.objects.get(pk=pk)
# ...
elif request.method == 'PUT':
tutorial_data = JSONParser().parse(request)
tutorial_serializer = TutorialSerializer(tutorial, data=tutorial_data)
if tutorial_serializer.is_valid():
tutorial_serializer.save()
return JsonResponse(tutorial_serializer.data)
return JsonResponse(tutorial_serializer.errors, status=status.HTTP_400_BAD_REQUEST)
Delete an object
Delete a Tutorial with the specified id
:
@api_view(['GET', 'PUT', 'DELETE'])
def tutorial_detail(request, pk):
# ... tutorial = Tutorial.objects.get(pk=pk)
# ...
elif request.method == 'DELETE':
tutorial.delete()
return JsonResponse({'message': 'Tutorial was deleted successfully!'}, status=status.HTTP_204_NO_CONTENT)
Delete all objects
Delete all Tutorials from the database:
@api_view(['GET', 'POST', 'DELETE'])
def tutorial_list(request):
# ...
elif request.method == 'DELETE':
count = Tutorial.objects.all().delete()
return JsonResponse({'message': '{} Tutorials were deleted successfully!'.format(count[0])}, status=status.HTTP_204_NO_CONTENT)
Find all objects by condition
Find all Tutorials with published = True
:
@api_view(['GET'])
def tutorial_list_published(request):
tutorials = Tutorial.objects.filter(published=True)
if request.method == 'GET':
tutorials_serializer = TutorialSerializer(tutorials, many=True)
return JsonResponse(tutorials_serializer.data, safe=False)
Test the CRUD with APIs
Run our Django Project with command: python manage.py runserver 8080
.
The console shows:
python manage.py runserver 8080
Performing system checks...
System check identified no issues (0 silenced).
March 30, 2020 - 16:24:01
Django version 2.1.15, using settings 'DjangoRestApiMongoDB.settings'
Starting development server at http://127.0.0.1:8080/
Quit the server with CTRL-BREAK.
Using Postman, we’re gonna test all the Apis above.
- Create a new Tutorial using
POST /tutorials
Api - Retrieve all Tutorials using
GET /tutorials
Api - Retrieve a single Tutorial by id using
GET /tutorials/:id
Api - Update a Tutorial using
PUT /tutorials/:id
Api - Find all Tutorials which title contains ‘ngo’:
GET /tutorials?title=ngo
- Find all published Tutorials using
GET /tutorials/published
Api - Delete a Tutorial using
DELETE /tutorials/:id
Api - Delete all Tutorials using
DELETE /tutorials
Api

Check MongoDB database after creating some Tutorials:
Check tutorials_tutorial
collection after some rows were updated:
Tutorial with id=4 was removed from tutorials_tutorial
collection:
You can use the Simple HTTP Client using Axios to check it.
Or: Simple HTTP Client using Fetch API
Conclusion
Today, we’ve learned how to create MongoDB & Django Rest Framework for Rest Apis CRUD example. We also know way to connect Python 3/Django application with MongoDB database, create a Django Model, migrate it to database, write the Views and define Url patterns for handling all CRUD operations.
Happy learning! See you again.
Further Reading
- Django Rest Framework quich start
- Django Model
- https://github.com/nesdis/djongo
- https://github.com/adamchainz/django-cors-headers
Fullstack CRUD App:
- Django + Angular 8
- Django + Angular 10
- Django + Angular 11
- Django + React
- Django + React Hooks
- Django + Vue
Source code
You can find the complete source code for this example on Github.
One thing for all future readers the api for published filter breaks in new djongo/mongo/django. do use the workaround of publishe__in=[True] instead.
Refer to the details at: https://github.com/nesdis/djongo/issues/465
You completed nice points! Thanks for the tutorial.
Hi great material ! 🙂 i have maybe a stupid question. I tried to create file tutorials/serializers.py inside i have line:
from tutorials.models import Tutorial, from which file it takes it ? i am beginner in programing and if a copy it to this file it shows me a error Unresolved reverence tutorials and Tutorial .Why in your repository its working and in mine not ?
Thanks for this wonderful tutorial.
Thank you for this tutorial. it really helped. Do you have a similar tutorial for WebSockets in Django as well.
Can you show me an example for ArrayField please
I managed to solve it. There was still a need to apply migrate before makemigrations. Thanks for the tutorial!
How you resolve it?
I downloaded the source on github to compare and I didn’t find any difference, but when running migrate in your code, I received this output and there are other tables that are not exemplified. Now he saves the id normally.
Output:
❯ python manage.py migrate
Operations to perform:
Apply all migrations: admin, auth, contenttypes, sessions, tutorials
Running migrations:
This version of djongo does not support “NULL, NOT NULL column validation check” fully. Visit https://www.patreon.com/nesdis
Applying contenttypes.0001_initial…This version of djongo does not support “schema validation using CONSTRAINT” fully. Visit https://www.patreon.com/nesdis
OK
Applying auth.0001_initial…This version of djongo does not support “schema validation using KEY” fully. Visit https://www.patreon.com/nesdis
This version of djongo does not support “schema validation using REFERENCES” fully. Visit https://www.patreon.com/nesdis
OK
Applying admin.0001_initial… OK
Applying admin.0002_logentry_remove_auto_add… OK
Applying admin.0003_logentry_add_action_flag_choices… OK
Applying contenttypes.0002_remove_content_type_name…This version of djongo does not support “COLUMN DROP NOT NULL ” fully. Visit https://www.patreon.com/nesdis
This version of djongo does not support “DROP CASCADE” fully. Visit https://www.patreon.com/nesdis
OK
Applying auth.0002_alter_permission_name_max_length… OK
Applying auth.0003_alter_user_email_max_length… OK
Applying auth.0004_alter_user_username_opts… OK
Applying auth.0005_alter_user_last_login_null… OK
Applying auth.0006_require_contenttypes_0002… OK
Applying auth.0007_alter_validators_add_error_messages… OK
Applying auth.0008_alter_user_username_max_length… OK
Applying auth.0009_alter_user_last_name_max_length… OK
Applying auth.0010_alter_group_name_max_length… OK
Applying auth.0011_update_proxy_permissions… OK
Applying sessions.0001_initial… OK
Applying tutorials.0001_initial… OK
Hi sir,
My ids are being saved as “null”.
[
{“id”: null, “title”: “Django MongoDB Tutorial#1”, “description”: “Tutorial#1 Descritivo”, “published”: false},
{“id”: null, “title”: “Django MongoDB Tutorial#2”, “description”: “Tutorial#2 Descritivo”, “published”: false}
]
Do you know what it can be?
Can you please tell me how you have GUI on mongoDB? I am on windows, I downloaded and installed mongoDB, code runs fine on PyCharm but I cannot find how to visually see collections and documents.
Hi, you can use MongoDB Compass Community, it is free 🙂
Sir, can you please add jwt authentication in it…
Hi, I will write the tutorial when having time 🙂
Thanks Sir
Thanks for the great tutorial. I’m trying to extend your models by adding
thumb = models.ImageField(default=’default.png’, blank=True, upload_to=’articles’)
GET & DELETE api are working well
but i got error msg when POST/PUT (in postman) as:
POST
{
“title”: “hello world”,
“slug”: “hello-world”,
“body”: “reported by Re”,
“thumb”: “media/default.png”,
“published”: true
}
MSG
{“thumb”: [“The submitted data was not a file. Check the encoding type on the form.”]}
i tried to set “thumb” as “” or null or any value, but it still got that error. BTW im not using any form, just serializers as in your instruction. Could you give any hint to overcome that, thanks again
Hi, you can try to make HTTP POST request with multipart/form-data.
Great tutorial, thank you for writing it!
Please note that an exception was encountered on test #8 (delete all tutorials). I checked the installed packages:
python -m pip list
Package Version
——————— ——-
asgiref 3.2.7
astroid 2.4.1
bson 0.5.8
colorama 0.4.3
dataclasses 0.6
Django 2.2.13
django-cors-headers 3.3.0
django-filter 2.2.0
django-mongodb-engine 0.6.0
djangorestframework 3.11.0
djangotoolbox 1.8.0
djongo 1.3.2
isort 4.3.21
lazy-object-proxy 1.4.3
Markdown 3.2.2
mccabe 0.6.1
pip 20.1.1
pylint 2.5.2
pymongo 3.10.1
python-dateutil 2.8.1
pytz 2020.1
setuptools 41.2.0
six 1.15.0
sqlparse 0.2.4
toml 0.10.1
wrapt 1.12.1
And, found that when I rolled back the djongo version to match the one you used in your example the exception went away and the last test completed successfully.
python -m pip install djongo==1.3.1
Thank you again for writing the tutorial!
I wonder how I manage multiple models in application. For example , I want to add other collection named ‘reviews’ , The “python manage.py migrate tutorials” generates only single model. When I have multiple models, how to accommodate?
Found answer from https://docs.djangoproject.com/en/3.0/intro/tutorial02/
Hi Scott, that is also my concern, but about dealing with multiple models in Non SQL db (Mongobd)? would anyone can share any example, thank you.
Thanks for tutorial, I could understand the components to combine db to REST from this article.
Took me some time to figure out that you have to install mongodb and start it to be able to migrate. Otherwise you would get this error: pymongo.errors.ServerSelectionTimeoutError: localhost:27017: [Errno 61] Connection refused
Great guide! Just missed this part.