This article is written by Anaiya Raisinghani (Developer Advocate @ MongoDB)
Learning how to create your first Django application has never been easier—there is a vast number of resources for developers to follow, and we all know the best way to learn is by example. In this tutorial, we will go through one of the most popular Django tutorials, located on Django’s documentation site, named Writing your first Django app. But this tutorial comes with a twist: Instead of following the tutorial exactly, we will be implementing our django-mongodb-backend
library where appropriate.
We will be taking you through the first two parts of this journey, since that is where the implementation will matter most. Once MongoDB is correctly configured as your database, you’ll be able to work with all the Django commands you know and love, without any other configurations.
Before we dive into the tutorial, let’s cover what this library is and why a developer would want to use Django and MongoDB together.
A summary of Django MongoDB Backend
This library, django-mongodb-backend
, is a third-party database that integrates seamlessly with Django! Why would a Django developer want to use this library? It aligns with all the familiar steps and commands that Django developers are already accustomed to using in their projects, so besides defining the database backend engine when creating the application, there are no other configuration steps developers need to follow to get up and running.
This process is smooth because MongoDB is committed to supporting as many of Django’s fundamentals as possible. These features include but are not limited to: querying data through the Django QuerySet API, the Django admin panel, representing MongoDB documents through Django models, and more.
Why use a NoSQL database with Django?
There are a variety of reasons why a developer would prefer to use MongoDB in their Django project. MongoDB’s document model, its robust ecosystem of tools, and its inherent competitive advantage set it as a pioneer in the space. While Django and relational databases are the typical pair, using Django with MongoDB will truly accelerate your application.
While Django is known for its simplicity and rapid development, MongoDB completely simplifies data modeling. With these two in tandem—MongoDB as the database back end and Django as the web framework—developers can fully commit to building complex applications instead of starting from square one.
With all this in mind, let’s dive in!
Tutorial pre-reqs
- An understanding of the
django-mongodb-backend
library - A MongoDB Atlas account
- An IDE of your choosing—we are using VS Code
- Python 3.10 or above
Create your MongoDB cluster
Our first step is to create our MongoDB cluster. We will be using the free tier. Please ensure the “Network Settings” in the cluster are correctly set up. This means making sure your IP address is included in the list of trusted addresses, or setting your cluster access to “Access from Anywhere." Please keep in mind “Access from Anywhere” is not encouraged for secure information, but for the sake of this tutorial, it will be fine. Ensure a secure username and password are set, as well. Once the cluster has been configured, copy and paste the connection string in a safe place as we will use it throughout the tutorial.
Once your cluster has been created, we can start.
Part 1: Basic request and response flow
Before we can get started, we need to create a virtual environment. This is crucial to ensure we can use isolated Python installations for various projects. Go ahead and run the commands below to create your virtual environment:
python3.12 -m venv venv
Then run:
source venv/bin/activate
Once you see the (venv)
next to your directory name in your terminal, you’ll know that you correctly configured your virtual environment. Make sure that your Python version is correct (or 3.10 and above) by double checking with:
python —-version
Now, we can install Django 5.0. We can do this and install the MongoDB integration in the same step to make things easier for ourselves when we reach the database connection step.
pip install django-mongodb-backend
This will install both PyMongo and Django since we will need both for the integration. Once the install has completed successfully, we can create a new Django project:
django-admin startproject quickstart --template https://github.com/mongodb-labs/django-mongodb-project/archive/refs/heads/5.0.x.zip
Please make sure the leading version numbers align with the Django version installed—e.g., the link above is for version 5.0.
This will be the structure of your new Django project.
Let’s test the development server to ensure that our Django project works. Make sure you’re in the quickstart
root and run this line:
python manage.py runserver
If run correctly, the development server will start:
When you click on the link, you’ll see this page. Congratulations!
The Django development server has been correctly created. It’s a lightweight web server specifically built for rapid development.
Now that we know our environment is correctly configured, we can start building our actual project.
Creating the Polls app
Make sure that you’re in the same directory where you ran the server and run this command:
python manage.py startapp polls --template https://github.com/mongodb-labs/django-mongodb-app/archive/refs/heads/5.0.x.zip
This command created the directory polls
. It looks like this.
Now, let’s write our first view! Open up the polls/views.py
file and copy in the following code:
from django.http import HttpResponse
from django.shortcuts import render
def index(request):
return HttpResponse("Hello! You've reached the Django MongoDB sample app landing page.")
This is our very basic view. Now, let’s access it in the browser. To do this, we need to map it to a URL. To define our URL configuration, create a file under the polls
application named urls.py
. Insert the following:
from django.urls import path
from . import views
urlpatterns = [
path("", views.index, name="index"),
]
Please ensure your app directory looks like this:
Now, we need to configure our global URL configuration from our quickstart
project to include the URL configuration that we just defined in our polls.urls
. So we can do this by adding in an import for django.urls.include
in quickstart/urls.py
and inserting an include()
in the urlspatterns
list.
Here is the code to copy into our quickstart/urls.py
file:
from django.contrib import admin
from django.urls import include, path
urlpatterns = [
path("polls/", include("polls.urls")),
path("admin/", admin.site.urls),
]
In this code snippet, the path()
function expects at least two arguments, route
and view
. The include()
function is for referencing the URL configurations.
You have successfully configured an index view into the URL configuration. Let’s ensure it’s working by running the server:
python manage.py runserver
Make sure you go to http://localhost:8000/polls/ in your browser and you’ll see the text that we defined from above!
Now that we have completed the basic request and response flow, let’s start incorporating our MongoDB database.
Part 2: Database set-up
Open up the quickstart/settings.py
file. Head over to the DATABASES
setting. Since we created our cluster through MongoDB Atlas, we can use the django_mongodb_backend.parse_uri(MONGODB_URI)
function to parse in our connection string.
DATABASES = {
"default": django_mongodb_backend.parse_uri(mongodb+srv://<username>:<password>@samplecluster.jkiff1s.mongodb.net/<database_name>?retryWrites=true&w=majority&appName=SampleCluster),
}
DATABASES["default"]["NAME"] = "pollsproject"
Make sure to specify the name of your database. This was created above when spinning up our cluster.
Take a look at the INSTALLED_APPS
setting above where we just enabled our database configuration. By default, we have these six:
INSTALLED_APPS = [
'quickstart.apps.MongoAdminConfig',
'quickstart.apps.MongoAuthConfig',
'quickstart.apps.MongoContentTypesConfig',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
]
Notice how instead of the traditional Django apps, we have MongoDB apps. django.contrib.admin
has been replaced withquickstart.apps.MongoAdminConfig
. django.contrib.auth
has been replaced with quickstart.apps.MongoAuthConfig
, and instead of django.contrib.contenttypes
, we have quickstart.apps.MongoContentTypesConfig
.
These are MongoDB versions of various Django apps. Each app that is included in our INSTALLED_APPS
setting references the corresponding AppConfig
.
Now, we need to run our migrate
command to specifically create our history. For each migration we create, it will create a database and a collection. Our database name has been specified when we connected to our MongoDB database. We will be able to see a message for each migration that gets applied.
Now, run this command:
python manage.py migrate
When this command is run successfully, you will see this:
(venv) anaiya.raisinghani@M-FQJJWDQ4CK quickstart % python manage.py migrate
Operations to perform:
Apply all migrations: admin, auth, contenttypes, sessions
Running migrations:
Applying contenttypes.0001_initial... OK
Applying auth.0001_initial... OK
Applying admin.0001_initial... OK
Applying sessions.0001_initial... OK
(venv) anaiya.raisinghani@M-FQJJWDQ4CK quickstart %
Inside of our MongoDB Atlas cluster, we are able to see the collections created for each of the installed Django apps and their models. This includes auth-related collections, like users, groups, permissions, session management, and migrations tracking.
This indicates Django is successfully using MongoDB as the database back end and is creating the necessary collections for our apps!
Creating models
Now that our database has been successfully configured, we can define our models. This is the layout of our database.
Following along in the tutorial for our poll app, we will create a Question
model and a Choice
model. Our Question
model has a question along with a publication date. The Choice
model has two fields: the text field and a vote tally. Every single Choice
is associated with a Question
.
To incorporate these models, we will need to edit our polls/models.py
file. Copy in the below code:
from django.db import models
class Question(models.Model):
question_text = models.CharField(max_length=200)
pub_date = models.DateTimeField("date published")
class Choice(models.Model):
question = models.ForeignKey(Question, on_delete=models.CASCADE)
choice_text = models.CharField(max_length=200)
votes = models.IntegerField(default=0)
This code here tells Django to create a database schema we can use to access the QuerySet API for Question
and Choice
objects.
Let’s head over and activate our models so we can install the polls
app.
For more information on the fields specified, please check out the Django project tutorial.
Activating our models
To include our app, we need to add it to the INSTALLED_APPS
in the settings file. Since the class we are working with is called PollsConfig
and it’s in the polls/apps.py
file, the path is polls.apps.PollsConfig
.
Head over to the quickstart/settings.py
file and add this path to the INSTALLED_APPS
setting. Once done, it will look like this:
INSTALLED_APPS = [
'polls.apps.PollsConfig',
'quickstart.apps.MongoAdminConfig',
'quickstart.apps.MongoAuthConfig',
'quickstart.apps.MongoContentTypesConfig',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
]
This lets Django know to install the polls
app.
Run this command:
python manage.py makemigrations polls
Your output will look like this:
makemigrations
allows Django to know the models have been created and these changes are going to be stored as a migration
.
The way Django stores changes to models is through migrations, which is why they are crucial for applications. Reading the migration for a new model can be done through the sqlmigrate
command. Even though we are using MongoDB as our database, with the django-mongodb-backend
library, all Django commands are the same, making it easier than ever to get started. Run the command below to see the structure of our migration for our new model under polls/migrations/0001_initial.py
:
python manage.py sqlmigrate polls 0001
Something very similar to the screenshot below will be produced through this command.
The output after this command will be different depending on the database decided on. This is what it will look like when utilizing MongoDB as your back end.
Let’s create our models in our database. Do this by running migrate
again:
python manage.py migrate
We get this result:
Once this command has been run, check the polls/migrations/0001_initial.py
file. It will look like this:
# Generated by Django 5.0.11 on 2025-01-21 23:34
import django.db.models.deletion
import django_mongodb_backend.fields
from django.db import migrations, models
class Migration(migrations.Migration):
initial = True
dependencies = [
]
operations = [
migrations.CreateModel(
name='Question',
fields=[
('id', django_mongodb_backend.fields.ObjectIdAutoField(primary_key=True, serialize=False)),
('question_text', models.CharField(max_length=200)),
('pub_date', models.DateTimeField(verbose_name='date published')),
],
),
migrations.CreateModel(
name='Choice',
fields=[
('id', django_mongodb_backend.fields.ObjectIdAutoField(primary_key=True, serialize=False)),
('choice_text', models.CharField(max_length=200)),
('votes', models.IntegerField(default=0)),
('question', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='polls.question')),
],
),
]
As we can see, instead of Django’s BigAutoField
or AutoField
for our IDs, we have django_mongodb_backend.fields.ObjectIdAutoField
.
Playing with the API
Pull up the Python shell with this command:
python manage.py shell
Import the model classes we just wrote with:
>>> from polls.models import Choice, Question
Take a look and check which questions are in the system:
# No questions are in the system yet.
>>> Question.objects.all()
There are none so this will be the response:
<QuerySet []>
Let’s create a new question.
First, import the timezone and ask a question:
>>> from django.utils import timezone
>>> q = Question(question_text="What's new?", pub_date=timezone.now())
Go ahead and save:
>>> q.save()
Take a look at the ID:
>>> q.id
The ID comes up as:
ObjectId('67903543e362728a32306c98')
Now, let’s take a look at the question we just created:
>>> q.question_text
We will see the question we asked:
"What's new?"
Let’s change the question by changing our attributes. Remember to call save()
when done.
>>> q.question_text = "What's up?"
>>> q.save()
Let’s display all the questions we currently have in our database:
>>> Question.objects.all()
<QuerySet [<Question: Question object (67903543e362728a32306c98)>]>
We are able to see the ID, but that isn’t helpful for readability. Close the shell using exit()
.
Let’s add a string method to both our Question
and Choice
in our polls/models.py
file:
import datetime
from django.db import models
from django.utils import timezone
class Question(models.Model):
question_text = models.CharField(max_length=200)
pub_date = models.DateTimeField("date published")
def was_published_recently(self):
return self.pub_date >= timezone.now() - datetime.timedelta(days=1)
def __str__(self):
return self.question_text
class Choice(models.Model):
question = models.ForeignKey(Question, on_delete=models.CASCADE)
choice_text = models.CharField(max_length=200)
votes = models.IntegerField(default=0)
def __str__(self):
return self.choice_text
Let’s save our changes and start a new Python shell. Do this by running:
python manage.py shell
Check and see if our __str__()
addition worked and if we are able to see the question asked from above:
>>> from polls.models import Choice, Question
>>> Question.objects.all()
<QuerySet [<Question: What's up?>]>
We are also able to view questions that start with specific keywords:
>>> filter = Question.objects.filter(question_text__startswith="What")
>>> filter
<QuerySet [<Question: What's up?>]>
We can also access the question through its ID:
>>> q = filter.first()
>>> Question.objects.get(pk=q.id)
<Question: What's up?>
Now, let’s give the question some choices.
We can display choices from our related object set (we do not have any so far):
>>> q.choice_set.all()
<QuerySet []>
Let’s create three choices:
>>> q.choice_set.create(choice_text="Not much", votes=0)
<Choice: Not much>
>>> q.choice_set.create(choice_text="The sky", votes=0)
<Choice: The sky>
>>> c = q.choice_set.create(choice_text="Just hacking again", votes=0)
We are able to have API access to our related question objects:
>>> c.question
<Question: What's up?>
And we are able to allow our question objects to have access to our choice objects:
>>> q.choice_set.all()
<QuerySet [<Choice: Not much>, <Choice: The sky>, <Choice: Just hacking again>]>
>>> q.choice_set.count()
3
Now, let’s delete one of the choices we created. We can use delete()
to accomplish this:
>>> c = q.choice_set.filter(choice_text__startswith="Just hacking")
>>> c.delete()
(1, {'polls.Choice': 1})
Exit the shell with exit()
.
Cool! Now, let’s head onto configuring the Django admin page.
Django admin page
To make things easier for developers, Django entirely automates the creation of admin sites for models. Please keep in mind that this admin site is not intended for all users, only site managers.
First, let’s create an admin user:
python manage.py createsuperuser
This will prompt for a Username
, an Email address
, and a Password
. The Password
will prompt twice:
Username: admin
Email address: admin@example.com
Password: **********
Password (again): *********
Superuser created successfully.
Once all the information is in, we can start the development server. Run the command below:
python manage.py runserver
Access the website: http://127.0.0.1:8000/admin/.
Here, there will be this admin screen:
Log in using the previously created credentials.
Here, we can see our groups
and users
. These were provided through our 'quickstart.apps.MongoAuthConfig
Now, let’s make our poll app modifiable from this admin page. First, edit the polls/admin.py
file to match the code below:
from django.contrib import admin
from .models import Question
admin.site.register(Question)
Once this file is saved, refresh the Django admin site and the Questions
will be registered:
Now, we are free to edit the questions, if we wish!
Conclusion
In this tutorial, we covered the first two parts of the popular Django Getting Started tutorial. Instead of following the tutorial exactly, we changed up important aspects to integrate the new django-mongodb-backend
library so we could use MongoDB as our database. We went over a ton of crucial information:
- Creating a Django project
- Starting up the development server
- Creating an app within a project
- Creating a view
- Setting up the database
- Creating models
- Activating models
- Interacting with the API
- Interacting with Django’s admin interface
For more information on the django-mongodb-backend
library, check out our GitHub, and please refer any questions to our Developer Forum!
Top comments (0)