<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Arthur Obo-Nwakaji</title>
    <description>The latest articles on DEV Community by Arthur Obo-Nwakaji (@arthurobo).</description>
    <link>https://dev.to/arthurobo</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F556337%2Fda22e62a-49d9-494f-a8e2-59a5ad116aa4.jpeg</url>
      <title>DEV Community: Arthur Obo-Nwakaji</title>
      <link>https://dev.to/arthurobo</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/arthurobo"/>
    <language>en</language>
    <item>
      <title>Integrating Django and Golang with Docker and PostgreSQL: A Scalable Approach</title>
      <dc:creator>Arthur Obo-Nwakaji</dc:creator>
      <pubDate>Mon, 02 Jun 2025 15:00:53 +0000</pubDate>
      <link>https://dev.to/arthurobo/integrating-django-and-golang-with-a-shared-postgresql-database-a-scalable-approach-12fg</link>
      <guid>https://dev.to/arthurobo/integrating-django-and-golang-with-a-shared-postgresql-database-a-scalable-approach-12fg</guid>
      <description>&lt;p&gt;In this tutorial guide, we will walk through setting up a scalable, production-ready backend architecture using PostgreSQL, Django, and Golang for microservice in development. In this setup, we’re using Django as our main backend framework and we will utilize the Django ORM for all models structuring and database migrations. Our Django Backend will serve as our single source of truth and will be the only backend to manage Database migrations and schemas. &lt;/p&gt;

&lt;p&gt;This architectural setup ensures modularity, performance, and the flexibility to assign the right tool for each job and ensures scalability for a real world production ready architecture. &lt;/p&gt;

&lt;p&gt;We'll start by establishing a shared PostgreSQL database docker container accessible by both Django and Golang services. We are only setting up a shared PostgreSQL database container because of development purposes. In a production environment, we’ll definitely want to use a cloud solution for managing our database. &lt;/p&gt;

&lt;p&gt;This guide will be divided into 3 parts, the first part is all about Setting Up a simple and straightforward containerized PostgreSQL Database for development purpose. Then the second part will be setting up our Django application and all starter code needed this guide. Then the last part will be our Golang microservice architecture and simple API endpoints to test our connections.&lt;/p&gt;

&lt;h2&gt;
  
  
  Part 1: Setting Up the PostgreSQL Database
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Project Structure:
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;guide/
├── backend/
├── database/
└── golang/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Our project structure naming convention is self explanatory as we easily know what each directory will handle.&lt;/p&gt;

&lt;p&gt;We will begin in the &lt;code&gt;database/&lt;/code&gt; directory where our PostgreSQL setup lives.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;code&gt;database/compose.yml&lt;/code&gt;&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;services:
  postgres:
    image: postgres:14
    container_name: django_golang_db
    hostname: django_golang_db
    restart: unless-stopped
    environment:
      POSTGRES_DB: django_golang_db
      POSTGRES_USER: django_golang_user
      POSTGRES_PASSWORD: django_golang_password
    ports:
      - "5433:5432"
    volumes:
      - postgres_data:/var/lib/postgresql/data
    networks:
      - shared-net

volumes:
  postgres_data:

networks:
  shared-net:
    external: true
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this setup, we, we have our compose.yml file, we have the basic PostgreSQL setup in a docker container. Here are the explanations of all we have implemented in our compose.yml file below:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;services:&lt;/code&gt; → This defines the services (containers) to be started.&lt;br&gt;
&lt;code&gt;image:&lt;/code&gt; → This uses the official PostgreSQL Docker image, version &lt;strong&gt;14&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;container_name:&lt;/code&gt; django_golang_db → this sets a custom name for our database container instead of a generated one&lt;/p&gt;

&lt;p&gt;&lt;code&gt;hostname:&lt;/code&gt; django_golang_db → This sets the internal hostname of the container (this will be used in networking between our different containers).&lt;/p&gt;

&lt;p&gt;&lt;code&gt;restart: unless-stopped&lt;/code&gt; → This will automatically restart our container if it crashes, unless we explicitly stop it.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;POSTGRES_DB, POSTGRES_USER, POSTGRES_PASSWORD&lt;/code&gt; → All these are self explanatory as they represent our database name, database username, database password respectively.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;ports:&lt;/code&gt; → This exposes our &lt;strong&gt;PostgreSQL's default port 5432&lt;/strong&gt; inside the container as &lt;strong&gt;5433&lt;/strong&gt; on your host machine. This means we will connect to PostgreSQL via &lt;code&gt;localhost:5433&lt;/code&gt; on our host machine. I am using port 5433 because on my local machine, I have PostgreSQL already using port 5432 which is the standard default PostgreSQL port.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;volumes:&lt;/code&gt; → This mounts a &lt;strong&gt;named volume&lt;/strong&gt; called &lt;code&gt;postgres_data&lt;/code&gt; to persist database data, even if the container is destroyed.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;networks:
   shared-net
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This here connects the PostgreSQL container to the &lt;strong&gt;user-defined external network&lt;/strong&gt; named &lt;code&gt;shared-net&lt;/code&gt; which we will create shortly in the next command we will run. This is useful since other containers like our Django backend or Go service need to talk to this PostgreSQL container using its hostname.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;volumes:&lt;/code&gt; → This Declares a named volume called &lt;code&gt;postgres_data&lt;/code&gt;, used above to persist database data.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;networks:&lt;/code&gt; → This is needed as it declares the &lt;code&gt;shared-net&lt;/code&gt; network as &lt;strong&gt;external&lt;/strong&gt;, meaning it must already exist before we run this compose file. Docker won't create this for us automatically. It enables the communication with other containers&lt;/p&gt;

&lt;h3&gt;
  
  
  Why External Network?
&lt;/h3&gt;

&lt;p&gt;We are using a named &lt;strong&gt;external network&lt;/strong&gt; (&lt;code&gt;shared-net&lt;/code&gt;) to ensure our &lt;code&gt;postgres&lt;/code&gt; container can be accessed by both the Django Backend and Golang service that will be defined in other Docker Compose files in separate directoriesn (Django Backend and Golang Service).&lt;/p&gt;

&lt;h3&gt;
  
  
  Creating the Shared Docker Network
&lt;/h3&gt;

&lt;p&gt;Before running the PostgreSQL container, we need to create the shared Docker network manually:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;docker network create shared-net&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;This command ensures that all services across different Compose files can communicate seamlessly. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;NOTE:&lt;/strong&gt; You can only run this command once, for me I can’t run the command again because I already have a running network and got the error message when I tried running it a second time: &lt;code&gt;Error response from daemon: network with name shared-net already exists&lt;/code&gt; &lt;/p&gt;

&lt;h3&gt;
  
  
  Starting the PostgreSQL Container
&lt;/h3&gt;

&lt;p&gt;Navigate to the &lt;code&gt;database/&lt;/code&gt; directory and run:&lt;br&gt;
&lt;code&gt;docker compose up --build&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Here, we will see the PostgreSQL container named &lt;code&gt;django_golang_db&lt;/code&gt; running on port &lt;code&gt;5433&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Here, I am using the —build flag so we can see the logs as the container is running.&lt;/p&gt;
&lt;h3&gt;
  
  
  Verifying PostgreSQL Access
&lt;/h3&gt;

&lt;p&gt;For us to get a list of all running containers, we need to run the first command below, then we can run the second command below to connect and test the database in an interactive bash shell, then the third command to enter our PostgreSQL shell and will be able to run PostgreSQL specific commands in the future when we’re done with setting up the Django side of things:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;docker ps
docker exec -it django_golang_db bash
psql -U django_golang_user -d django_golang_db
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If successful, you should see the &lt;code&gt;psql&lt;/code&gt; prompt:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;django_golang_db=#&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;At this point, our database is ready and accessible for both Django and Golang services via the container hostname &lt;code&gt;django_golang_db&lt;/code&gt; over port &lt;code&gt;5432&lt;/code&gt; (internal Docker port).&lt;/p&gt;

&lt;h2&gt;
  
  
  Part 2: Integrating Django with External PostgreSQL
&lt;/h2&gt;

&lt;p&gt;In this section, we will dive into setting up Django to use this external PostgreSQL container using a separate &lt;code&gt;compose.yml&lt;/code&gt;, Dockerfile, and Nginx reverse proxy. &lt;/p&gt;

&lt;p&gt;Now that our PostgreSQL database is up and running on a shared Docker network (&lt;code&gt;shared-net&lt;/code&gt;), we’ll connect our Django application to it. The goal here is to make Django our schema source and business logic hub which means Django will be our single source of truth, especially useful for admin interfaces, authentication, and model definitions.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;backend/
├── backend/ # Django core Setting (includes settings, urls, etc.)
├── blog/ # Example app
├── manage.py
├── Dockerfile
├── compose.yml
├── entrypoint.sh
├── requirements.txt
├── nginx.conf
├── media/
└── staticfiles/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Follow the commands below to get a working django project with an initial virtual environment which we will not need anymore once our docker set up is complete:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;python -m venv venv
source venv/bin/activate
mkdir backend
cd backend
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now we have a working backend directory, let’s create a new requirements.txt file in our backend directory which will have all our dependencies:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;backend/requirements.txt&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;amqp==5.3.1
annotated-types==0.7.0
anyio==4.9.0
asgiref==3.8.1
async-timeout==5.0.1
billiard==4.2.1
celery==5.5.1
certifi==2025.4.26
click==8.2.0
click-didyoumean==0.3.1
click-plugins==1.1.1
click-repl==0.3.0
Deprecated==1.2.18
Django==5.2.1
django-autoslug==1.9.9
django-cors-headers==4.7.0
django-elasticsearch-dsl==7.2.2
django-elasticsearch-dsl-drf==0.22.4
django-nine==0.2.7
djangorestframework==3.16.0
elastic-transport==8.17.1
elasticsearch==7.13.4
elasticsearch-dsl==7.4.0
exceptiongroup==1.3.0
fastapi==0.115.12
gunicorn==23.0.0
h11==0.16.0
idna==3.10
kombu==5.5.3
packaging==25.0
prompt_toolkit==3.0.51
psycopg2-binary==2.9.10
pydantic==2.11.4
pydantic_core==2.33.2
python-dateutil==2.9.0.post0
redis==4.3.4
six==1.17.0
sniffio==1.3.1
sqlparse==0.5.3
starlette==0.46.2
typing-inspection==0.4.0
typing_extensions==4.13.2
tzdata==2025.2
urllib3==1.26.20
uv==0.7.3
uvicorn==0.34.2
vine==5.1.0
wcwidth==0.2.13
wrapt==1.17.2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now let’s install all dependencies so we can create a new Django project, we can choose to install only Django as that is only what we need to get our Django project running, but for this guide, we will need to install all dependencies:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;pip install -r requirements.txt
#OR
pip install Django==5.2.1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once our required dependencies are installed, the next we have to do is to start a new django project with the command below:&lt;br&gt;
&lt;code&gt;django-admin startproject backend .&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;We’re using the extra &lt;code&gt;.&lt;/code&gt;  because we want the whole project to be in our backend folder.&lt;/p&gt;

&lt;p&gt;Now we can test the django application with the runserver command to be sure our django project is running manually:&lt;br&gt;
&lt;code&gt;python manage.py runserver&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;We can visit &lt;a href="http://localhost" rel="noopener noreferrer"&gt;localhost&lt;/a&gt; on port 8000, and we’ll see our django application running there.&lt;/p&gt;

&lt;p&gt;Once our django application is running manually, let’s create a new blog app in our django backend. This new blog app will handle our models structure for a simple blog application which our Golang microservice will use.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;python manage.py startapp blog&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Once this new blog app is created, let’s add it to the backend/backend/settings.py file in the list of INSTALLED_APPS:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;INSTALLED_APPS = [
        ...
    'django.contrib.staticfiles',

    # Local apps
    'blog', # New
]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then in our backend/blog/models.py let’s add the following code below for our models structure:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;backend/blog/models.py&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;from django.db import models


class Post(models.Model):
    title = models.CharField(max_length=200)
    content = models.TextField()
    date_created = models.DateTimeField(auto_now_add=True)
    last_updated = models.DateTimeField(auto_now=True)

    def __str__(self):
        return self.title
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next we have to update our backend/blog/admin.py file:&lt;br&gt;
&lt;code&gt;backend/blog/admin.py&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;from django.contrib import admin
from .models import Post

admin.site.register(Post)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Django Docker Compose File Setup
&lt;/h3&gt;

&lt;p&gt;Let’s create a new &lt;code&gt;backend/compose.yml&lt;/code&gt; file in our django setup:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;backend/compose.yml&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;services:
  backend:
    build: .
    container_name: backend
    hostname: backend  # this helps DNS resolution
    expose:
      - "8000"
    networks:
      - shared-net
    env_file:
      - .env
    volumes:
      - .:/app
      - static_volume:/app/staticfiles
      - media_volume:/app/media

  nginx:
    image: nginx:latest
    container_name: nginx
    depends_on:
      - backend
    ports:
      - "8000:8000"
    networks:
      - shared-net
    volumes:
      - ./nginx.conf:/etc/nginx/conf.d/default.conf
      - static_volume:/app/staticfiles
      - media_volume:/app/media

volumes:
  static_volume:
  media_volume:

networks:
  shared-net:
    external: true
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;From our compose.yml file above, we can see we’re setting up two containers for our use case which is the actual backend and nginx setup to handle incoming requests and serve static/media files efficiently. &lt;/p&gt;

&lt;p&gt;Here I’m only going to explain the significant external PostgreSQL Database connection configuration:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;networks:
  shared-net
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This joins the external network shared-net, enabling communication with other containers like nginx or postgres&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;networks:
  shared-net:
    external: true
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This above uses an &lt;strong&gt;external Docker network which we have already created before in the first part&lt;/strong&gt; with the command (&lt;code&gt;docker network create shared-net&lt;/code&gt;). We cannot run this command again as it is already working.&lt;/p&gt;

&lt;h3&gt;
  
  
  Django Dockerfile File Setup
&lt;/h3&gt;

&lt;p&gt;Let’s create a new &lt;code&gt;backend/Dockerfile&lt;/code&gt; file in our django backend&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;setup:
FROM python:3.10

RUN mkdir /app

WORKDIR /app

ENV PYTHONDONTWRITEBYTECODE=1
ENV PYTHONUNBUFFERED=1

# Install uv
RUN pip install --upgrade pip
RUN pip install --upgrade uv

COPY requirements.txt /app/

# Use uv with --system flag to install packages system-wide without virtual env
RUN uv pip install --system --no-cache-dir -r requirements.txt

COPY . /app/

EXPOSE 8000

RUN chmod +x entrypoint.sh

CMD ["./entrypoint.sh"]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is a basic and straightforward Dockerfile setup for a Django application. From our setup, we see we need an backend/entrypoint.sh file to run all django specific commands.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
#!/bin/bash

# Define path to manage.py
MANAGE_PY="/app/manage.py"

# Apply migrations
echo "Applying database migrations"
python $MANAGE_PY migrate --noinput

# Collect static files
echo "Collecting static files"
python $MANAGE_PY collectstatic --noinput

# Start the server - the $DJANGO_MODE is set in the .env file and is either "development" or "production"
if [ "$DJANGO_MODE" = "development" ]; then
    echo "Starting Django development server..."
    exec python $MANAGE_PY runserver 0.0.0.0:8000
else
    echo "Starting Gunicorn server..."
    exec gunicorn backend.wsgi:application --bind 0.0.0.0:8000 --workers 4
fi
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once we have this entrypoint.sh file in place, we need to make it executable, run the command below to make it executable:&lt;br&gt;
&lt;code&gt;chmod +x backend/entrypoint.sh&lt;/code&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  Django Database Configuration
&lt;/h3&gt;

&lt;p&gt;Next we need to do is replace the &lt;code&gt;DATABASES&lt;/code&gt; section setup in our &lt;code&gt;backend/backend/settings.py&lt;/code&gt;  file to use the shared PostgreSQL container instead of the default sqlite3 database.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;backend/backend/settings.py&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.postgresql',
        'NAME': 'django_golang_db',
        'USER': 'django_golang_user',
        'PASSWORD': 'django_golang_password',
        'HOST': 'django_golang_db',  # this must match Postgres container name
        'PORT': '5432',
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next we have to do in the backend/backend/settings.py file is to set our STATIC_ROOT, add this block of code below beneath our STATIC_URL:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import os
...
STATIC_URL = 'static/'
STATIC_ROOT = os.path.join(BASE_DIR, 'staticfiles')
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Last thing we need to setup in our backend/backend/settings.py file is the  CSRF_TRUSTED_ORIGINS:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;BACKEND_URLS = [
    # Our local IP and port used by Nginx
    "http://127.0.0.1:8000",
    "http://localhost:8000",
]

CSRF_TRUSTED_ORIGINS = BACKEND_URLS
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next thing we need to set up is our backend/nginx.conf file which will handle all incoming requests:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;backend/nginx.conf&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;server {
    listen 8000;

    location / {
        proxy_pass http://backend:8000;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }

    location /static/ {
        alias /app/staticfiles/;
        expires 30d;
    }

    location /media/ {
        alias /app/media/;
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Running the Django Container
&lt;/h3&gt;

&lt;p&gt;From the &lt;code&gt;backend/&lt;/code&gt; directory, let’s run the command below to build and run our Django container and we will see our application running on &lt;a href="http://localhost" rel="noopener noreferrer"&gt;localhost&lt;/a&gt; on port 8000:&lt;br&gt;
&lt;code&gt;docker compose up --build&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Now that our django application is running, next we need to do is open our django container in an interactive bash shell run the following commands to perform some migrations.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;docker ps
docker compose exec -it backend bash
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once you run the last command above, you’ll see a shell like this below, it means you are in the interactive shell:&lt;br&gt;
root@backend:/app# &lt;/p&gt;

&lt;p&gt;Great job, now we’re in the interactive bash shell, we can run the following commands&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;python manage.py makemigrations
python manage.py migrate
python manage.py createsuperuser
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Validating DB Connection
&lt;/h3&gt;

&lt;p&gt;Now this is all the setup we have to do code wise for our django backend and we now have our superuser, we can log in to the django admin and add some blog data which we will use for our Golang microservice in the next section.&lt;/p&gt;

&lt;p&gt;Before we proceed to the next section, let’s open our postgresql in an interactive bash shell to see our whole database schema and structure.&lt;/p&gt;

&lt;p&gt;To validate that Django is writing to PostgreSQL correctly:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Enter the PostgreSQ Database container:&lt;br&gt;
&lt;code&gt;docker exec -it django_golang_db bash&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Connect with psql:&lt;br&gt;
&lt;code&gt;psql -U django_golang_user -d django_golang_db&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Check tables with this sql commands below:&lt;br&gt;
&lt;code&gt;\dt&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;In the \dt command we just ran, we’ll see that it lists all the tables in our PostgreSQL database like this below:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;\dt
                        List of relations
 Schema |            Name            | Type  |       Owner        
--------+----------------------------+-------+--------------------
 public | auth_group                 | table | django_golang_user
 public | auth_group_permissions     | table | django_golang_user
 public | auth_permission            | table | django_golang_user
 public | auth_user                  | table | django_golang_user
 public | auth_user_groups           | table | django_golang_user
 public | auth_user_user_permissions | table | django_golang_user
 public | blog_post                  | table | django_golang_user
 public | django_admin_log           | table | django_golang_user
 public | django_content_type        | table | django_golang_user
 public | django_migrations          | table | django_golang_user
 public | django_session             | table | django_golang_user
(11 rows)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We see that we have all the default Django tables created when we run the &lt;code&gt;python manage.py migrate&lt;/code&gt; command for the first time in a Django application and our &lt;code&gt;blog_post&lt;/code&gt; table in the blog app for the Post models instance we created earlier.&lt;/p&gt;

&lt;p&gt;Next let’s view all the columns in the &lt;code&gt;blog_post&lt;/code&gt; table, we’ll use the command below:&lt;br&gt;
&lt;code&gt;\d blog_post&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;\d blog_post
                                     Table "public.blog_post"
    Column    |           Type           | Collation | Nullable |             Default              
--------------+--------------------------+-----------+----------+----------------------------------
 id           | bigint                   |           | not null | generated by default as identity
 title        | character varying(200)   |           | not null | 
 content      | text                     |           | not null | 
 date_created | timestamp with time zone |           | not null | 
 last_updated | timestamp with time zone |           | not null | 
Indexes:
    "blog_post_pkey" PRIMARY KEY, btree (id)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;At this point, everything works perfectly both on our Database set up and Django setup which now brings us to the final part of this guide.&lt;/p&gt;

&lt;h2&gt;
  
  
  Part 3: Integrating Golang with PostgreSQL
&lt;/h2&gt;

&lt;p&gt;In this part, we’ll connect our Golang backend to the same PostgreSQL database container that our Django app uses. This setup allows Django to manage database models and migrations, while Golang focuses on high-performance APIs using raw SQL for speed and control.&lt;/p&gt;

&lt;p&gt;Golang Project Structure:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;golang/
├── cmd/
│   └── api/
│       └── main.go
├── internal/
│   ├── blog/
│   │   ├── handler.go
│   │   ├── models.go
│   │   └── repository.go
│   ├── db/
│   │   └── postgres.go
│   └── users/
│       ├── handler.go
│       ├── model.go
│       └── repository.go
├── pkg/
│   └── utils/
│       └── response.go
├── Dockerfile
├── compose.yml
├── go.mod
├── go.sum
└── .air.toml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step 1: Initialize the Go Module
&lt;/h3&gt;

&lt;p&gt;Navigate to the &lt;code&gt;golang/&lt;/code&gt; directory and initialize the module. The name should reflect your import paths.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
cd golang
go mod init api
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This creates the &lt;code&gt;go.mod&lt;/code&gt; file.&lt;/p&gt;




&lt;h3&gt;
  
  
  Step 2: Install Required Dependencies
&lt;/h3&gt;

&lt;p&gt;Install the required packages using &lt;code&gt;go get&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;go get github.com/gorilla/mux
go get github.com/lib/pq
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This generates the appropriate entries in go.sum, such as:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;github.com/gorilla/mux v1.8.1
github.com/lib/pq v1.10.9
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step 3: Create the Main Entry File
&lt;/h3&gt;

&lt;p&gt;Create &lt;code&gt;golang/cmd/api/main.go&lt;/code&gt; with the following content:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;package main

import (
    "api/internal/blog"
    "api/internal/db"
    "api/internal/users"
    "log"
    "net/http"

    "github.com/gorilla/mux"
)

func main() {
    database, err := db.ConnectDB()
    if err != nil {
        log.Fatal(err)
    }

    router := mux.NewRouter()

    users.RegisterRoutes(router, database)
    blog.RegisterRoutes(router, database)

    log.Println("Server is running on port 8080...")
    log.Fatal(http.ListenAndServe(":8080", router))
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step 4: Database Connection
&lt;/h3&gt;

&lt;p&gt;Create &lt;code&gt;golang/internal/db/postgres.go&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;package db

import (
    "database/sql"
    "fmt"

    _ "github.com/lib/pq"
)

func ConnectDB() (*sql.DB, error) {
    host := "django_golang_db"
    port := 5432
    user := "django_golang_user"
    password := "django_golang_password"
    dbname := "django_golang_db"

    psqlInfo := fmt.Sprintf("host=%s port=%d user=%s password=%s dbname=%s sslmode=disable",
        host, port, user, password, dbname)

    db, err := sql.Open("postgres", psqlInfo)
    if err != nil {
        return nil, err
    }
    return db, db.Ping()
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step 4: Code Implementation
&lt;/h3&gt;

&lt;p&gt;At this point we will handle the implementation of users and blog in both golang/internal/users and golang/internal/blog respectively&lt;/p&gt;

&lt;p&gt;&lt;code&gt;golang/internal/users/model.go&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;package users

import "time"

type CompleteUsersModel struct {
    ID          int       `json:"id"`
    LastLogin   time.Time `json:"last_login"`
    IsSuperuser bool      `json:"is_superuser"`
    Username    string    `json:"username"`
    FirstName   string    `json:"first_name"`
    LastName    string    `json:"last_name"`
    Email       string    `json:"email"`
    IsStaff     bool      `json:"is_staff"`
    IsActive    bool      `json:"is_active"`
    DateJoined  time.Time `json:"date_joined"`
    Password    string    `json:"password"`
}

type GetAllUsersModel struct {
    ID        int    `json:"id"`
    Email     string `json:"email"`
    FirstName string `json:"first_name"`
    LastName  string `json:"last_name"`
    Username  string `json:"username"`
    IsActive  bool   `json:"is_active"`
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;golang/internal/users/repository.go&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;package users

import "database/sql"

func GetAllUsers(db *sql.DB) ([]GetAllUsersModel, error) {
    rows, err := db.Query("SELECT id, email, first_name, last_name, username, is_active FROM auth_user")
    if err != nil {
        return nil, err
    }
    defer rows.Close()

    var users []GetAllUsersModel
    for rows.Next() {
        var u GetAllUsersModel
        if err := rows.Scan(&amp;amp;u.ID, &amp;amp;u.Email, &amp;amp;u.FirstName, &amp;amp;u.LastName, &amp;amp;u.Username, &amp;amp;u.IsActive); err != nil {
            return nil, err
        }
        users = append(users, u)
    }
    return users, nil
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;golang/internal/users/handler.go&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;package users

import (
    "api/pkg/utils"
    "database/sql"
    "fmt"
    "net/http"

    "github.com/gorilla/mux"
)

func RegisterRoutes(r *mux.Router, db *sql.DB) {
    r.HandleFunc("/users", getAllUsersHandler(db)).Methods("GET")
}

func getAllUsersHandler(db *sql.DB) http.HandlerFunc {
    return func(w http.ResponseWriter, r *http.Request) {
        fmt.Println("Getting all usersD")
        users, err := GetAllUsers(db)
        if err != nil {
            utils.WriteJSONError(w, http.StatusInternalServerError, "Error fetching users", err.Error())
            return
        }
        utils.WriteJSONSuccess(w, http.StatusOK, "Users fetched successfully", users)
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now we have all the code for our users functionality, next we need to do is create our response pkg utility in&lt;br&gt;
golang/pkg/utils/response.go&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;package utils

import (
    "encoding/json"
    "net/http"
)

// This function is used to write a JSON error response to the client, will
// be called where there is an error in all api requests
func WriteJSONError(w http.ResponseWriter, status int, message string, details interface{}) {
    w.WriteHeader(status)

    resp := map[string]interface{}{
        "message": message,
    }

    if details != nil {
        resp["error"] = details
    }

    json.NewEncoder(w).Encode(resp)
}

type SuccessResponse struct {
    Message string      `json:"message"`
    Data    interface{} `json:"data,omitempty"`
}

// This function is used to write a JSON success response to the client, will
// be called where there is an error in all api requests
func WriteJSONSuccess(w http.ResponseWriter, status int, message string, data interface{}) {
    w.WriteHeader(status)
    resp := SuccessResponse{
        Message: message,
        Data:    data,
    }
    json.NewEncoder(w).Encode(resp)
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now the last setup is our blog application we need to setup:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;golang/internal/blog/model.go&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;package blog

import "time"

type CompleteBlogModel struct {
    ID          int64     `json:"id"`
    Title       string    `json:"title"`
    Content     string    `json:"content"`
    DateCreated time.Time `json:"date_created"`
    LastUpdated time.Time `json:"last_updated"`
}

type BlogCreateModel struct {
    ID          int64     `json:"id"`
    Title       string    `json:"title"`
    Content     string    `json:"content"`
    DateCreated time.Time `json:"date_created"`
    LastUpdated time.Time `json:"last_updated"`
}

func (p *BlogCreateModel) Validate() []string {
    var errors []string
    if p.Title == "" {
        errors = append(errors, "title is required")
    }
    if p.Content == "" {
        errors = append(errors, "content is required")
    }
    return errors
}

type GetAllBlogModel struct {
    ID          int64     `json:"id"`
    Title       string    `json:"title"`
    Content     string    `json:"content"`
    DateCreated time.Time `json:"date_created"`
    LastUpdated time.Time `json:"last_updated"`
}

type IndividualPostModel struct {
    ID          int64     `json:"id"`
    Title       string    `json:"title"`
    Content     string    `json:"content"`
    DateCreated time.Time `json:"date_created"`
    LastUpdated time.Time `json:"last_updated"`
}

type UpdatePostModel struct {
    ID      int64  `json:"id"`
    Title   string `json:"title"`
    Content string `json:"content"`
}

func (p *UpdatePostModel) Validate() []string {
    var errors []string
    if p.Title == "" {
        errors = append(errors, "title is required")
    }
    if p.Content == "" {
        errors = append(errors, "content is required")
    }
    return errors
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;golang/internal/blog/repository.go&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;package blog

import "database/sql"

func GetAllBlogs(db *sql.DB) ([]GetAllBlogModel, error) {
    rows, err := db.Query("SELECT id, title, content, date_created, last_updated FROM blog_post")
    if err != nil {
        return nil, err
    }
    defer rows.Close()

    var blogs []GetAllBlogModel
    for rows.Next() {
        var u GetAllBlogModel
        if err := rows.Scan(&amp;amp;u.ID, &amp;amp;u.Title, &amp;amp;u.Content, &amp;amp;u.DateCreated, &amp;amp;u.LastUpdated); err != nil {
            return nil, err
        }
        blogs = append(blogs, u)
    }
    return blogs, nil
}

func GetPostByID(db *sql.DB, id string) (IndividualPostModel, error) {
    var p IndividualPostModel
    err := db.QueryRow("SELECT id, title, content, date_created, last_updated FROM blog_post WHERE id = $1", id).Scan(&amp;amp;p.ID, &amp;amp;p.Title, &amp;amp;p.Content, &amp;amp;p.DateCreated, &amp;amp;p.LastUpdated)
    if err != nil {
        return p, err
    }
    return p, nil
}

func UpdatePost(db *sql.DB, id string, p *UpdatePostModel) (bool, error) {
    result, err := db.Exec("UPDATE blog_post SET title = $1, content = $2 WHERE id = $3", p.Title, p.Content, id)
    if err != nil {
        return false, err
    }
    rowsAffected, err := result.RowsAffected()
    if err != nil {
        return false, err
    }
    return rowsAffected &amp;gt; 0, nil
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;golang/internal/blog/handler.go&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;package blog

import (
    "api/pkg/utils"
    "database/sql"
    "encoding/json"
    "fmt"
    "net/http"

    "github.com/gorilla/mux"
)

func RegisterRoutes(r *mux.Router, db *sql.DB) {
    r.HandleFunc("/posts", getAllBlogsHandler(db)).Methods("GET")
    r.HandleFunc("/posts/{id}", getPostByIDHandler(db)).Methods("GET")
    r.HandleFunc("/posts/{id}", updatePostHandler(db)).Methods("PUT")
}

func getAllBlogsHandler(db *sql.DB) http.HandlerFunc {
    return func(w http.ResponseWriter, r *http.Request) {
        fmt.Println("Getting all usersD")
        blogs, err := GetAllBlogs(db)
        if err != nil {
            utils.WriteJSONError(w, http.StatusInternalServerError, "Error fetching users", err.Error())
            return
        }
        utils.WriteJSONSuccess(w, http.StatusOK, "Blogs fetched successfully", blogs)
    }
}

func getPostByIDHandler(db *sql.DB) http.HandlerFunc {
    return func(w http.ResponseWriter, r *http.Request) {
        id := mux.Vars(r)["id"]
        post, err := GetPostByID(db, id)
        if err != nil {
            utils.WriteJSONError(w, http.StatusNotFound, "Post not found", nil)
            return
        }
        utils.WriteJSONSuccess(w, http.StatusOK, "Post fetched successfully", post)
    }
}

func updatePostHandler(db *sql.DB) http.HandlerFunc {
    return func(w http.ResponseWriter, r *http.Request) {
        id := mux.Vars(r)["id"]
        var p UpdatePostModel
        if err := json.NewDecoder(r.Body).Decode(&amp;amp;p); err != nil {
            utils.WriteJSONError(w, http.StatusBadRequest, "Invalid request body", err.Error())
            return
        }
        updated, err := UpdatePost(db, id, &amp;amp;p)
        if err != nil {
            utils.WriteJSONError(w, http.StatusInternalServerError, "Error updating post", err.Error())
            return
        }
        utils.WriteJSONSuccess(w, http.StatusOK, "Post updated successfully", updated)
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Dockerize the Golang Microservice Application
&lt;/h3&gt;

&lt;p&gt;Golang Dockerfile:&lt;br&gt;
&lt;code&gt;golang/Dockerfile&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;FROM golang:1.23.4-alpine

WORKDIR /app

# Install git for downloading Air
RUN apk add --no-cache git

# Install Air
RUN go install github.com/air-verse/air@latest


COPY go.mod ./
COPY go.sum ./
RUN go mod download

COPY . .
COPY .air.toml . 

EXPOSE 8080

CMD ["air", "-c", ".air.toml"]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Docker Compose File:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;golang/compose.yml&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;services:
  api:
    build: .
    container_name: golang_api
    volumes:
      - .:/app
    networks:
      - shared-net
    ports:
      - "8080:8080"

networks:
  shared-net:
    external: true
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We’re using the same external Docker network &lt;code&gt;shared-net&lt;/code&gt; so that the Golang container can reach PostgreSQL using &lt;code&gt;django_golang_db&lt;/code&gt; as host.&lt;/p&gt;

&lt;h3&gt;
  
  
  Air Library Initialization:
&lt;/h3&gt;

&lt;p&gt;Lastly we need to initialize our &lt;strong&gt;Air library we installed installed earlier&lt;/strong&gt; which will be used for reloading our server (&lt;code&gt;go install github.com/air-verse/air@latest&lt;/code&gt;), simply run this command below in your Go project root:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;air init&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;We now have an initialized .air.toml file created in our golang root directory. Replace the generated code with this below:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;golang/.air.toml&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# .air.toml
# Configures Air to watch your app and build the actual entry point in cmd/api

root = "."
tmp_dir = "tmp"

[build]
  cmd = "go build -buildvcs=false -o ./tmp/main ./cmd/api"
  bin = "tmp/main"
  include_ext = ["go"]
  exclude_dir = ["tmp", "vendor"]
  delay = 1000
  log = "air.log"
  send_interrupt = true
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We’re almost done, now we can run and build our golang microservice with the command below:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;docker compose up --build&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Once our golang microservice is running, we’ll see it running on port 8080. At this point we can consume the API endpoints &lt;/p&gt;

&lt;p&gt;/posts [GET] → Gets the list of all Blog posts&lt;/p&gt;

&lt;p&gt;/posts/{id} [GET] → Gets the post object’s data detail&lt;/p&gt;

&lt;p&gt;/posts/{id} [PUT] → Update the post object’s data details&lt;/p&gt;

&lt;p&gt;/users [GET] → Gets the list of all users&lt;/p&gt;

&lt;p&gt;Codebase can be found here:&lt;br&gt;
&lt;a href="https://github.com/Arthurobo/-django-golang-postgresql.git" rel="noopener noreferrer"&gt;https://github.com/Arthurobo/-django-golang-postgresql.git&lt;/a&gt;&lt;/p&gt;

</description>
    </item>
    <item>
      <title>DJANGO CELERY SEND EMAILS TO ALL USERS</title>
      <dc:creator>Arthur Obo-Nwakaji</dc:creator>
      <pubDate>Wed, 23 Nov 2022 11:58:27 +0000</pubDate>
      <link>https://dev.to/arthurobo/django-celery-send-emails-to-all-users-1l6f</link>
      <guid>https://dev.to/arthurobo/django-celery-send-emails-to-all-users-1l6f</guid>
      <description>&lt;p&gt;In this guide, we're going to send emails to all our users on our Django web application asynchronously. Imagine a very large application where we have thousands of users and we want to email them the new and latest changes on our platform, probably some newsletter or something. We can't afford to allow the traditional Django to handle this for us as this will take a lot of time to complete this. Time waiting for our email service to send all these emails can be used to do something else by the user and it is not a very good experience for our users. So in this case, we need some sort of performance task that can improve our user's activity. &lt;/p&gt;

&lt;p&gt;Celery does the work for us. It enables our Django application to complete various task queues for multiple workers. &lt;/p&gt;

&lt;p&gt;For this guide, we'll use Redis as our message broker to get the performance. &lt;/p&gt;

&lt;p&gt;The first thing first is to install Django, Celery and Redis with the commands below&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;pip install Django==3.2.10
pip install celery==4.4.2
pip install redis==4.3.4

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So let's start a new Django project named "my_project". Once our project is created, we can now change the directory into this newly created project and run our server&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;django-admin startproject my_project
cd my_project
python manage.py runserver
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If our server is running just fine, then we're on the right track and now need to start setting up celery for our project.&lt;/p&gt;

&lt;p&gt;In my_project app, we need to create a new file named "celery.py". In this file, this is where all our celery configurations will be located. In this file, let's add the code below;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;from __future__ import absolute_import, unicode_literals
import os
from celery import Celery

# setting the Django settings module.
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'my_project.settings')
app = Celery('ecommerce')
app.config_from_object('django.conf:settings', namespace='CELERY')

# Looks up for task modules in Django applications and loads them
app.autodiscover_tasks()

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This last line of code tells Celery to automatically discover files named tasks.py in all registered Django apps.&lt;/p&gt;

&lt;p&gt;Now in the same main project app's folder where we have our celery.py and settings file, we need to update our &lt;strong&gt;init&lt;/strong&gt;.py file to tell Celery to automatically start whenever Django starts. Update our &lt;strong&gt;init&lt;/strong&gt;.py file with the code below;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;from .celery import app as celery_app

__all__ = ('celery_app',)

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next, we need to specify Redis as our broker for celery in our settings file. Add the line of code below to our settings.py&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# CELERY SETTINGS
CELERY_BROKER_URL = 'redis://127.0.0.1:6379'
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now we have all our celery configurations in place, our next steps will require us to create a view where we can perform the necessary actions and further integrate celery to make this asynchronous.&lt;/p&gt;

&lt;p&gt;Let's create a new app name public;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;python manage.py startapp public
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once created, add it to our installed apps in the settings file;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;INSTALLED_APPS = [
    ...
    'public',
]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We can now migrate our database with the comma nd below;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;python manage.py migrate
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next is to create our home view in the public app to handle all things for us, add the code below&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;from django.shortcuts import render
from django.contrib.auth.models import User


def home_view(request):
    users = User.objects.all()
    context = {
        'users': users
    }
    return render(request, 'public/home.html', context)

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We now have our simple view which will simply render our HTML page for us with a context that lists all our users. This will help us in our home view templates to know the number of users on our platform.&lt;/p&gt;

&lt;p&gt;Our next step is to create our urls.py file in our public app, and add the code below to our urls.py file.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;from django.urls import path
from .views import home_view

app_name = "public"

urlpatterns = [
    path('', home_view, name='home-view'),
]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We now have our views and it's URLs, lastly, we need to include the public's URLs in the main project URLs file so that Django will be able to render it.&lt;/p&gt;

&lt;p&gt;Now in our main project urls.py file, we can update it with the code below;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;from django.contrib import admin
from django.urls import path, include

urlpatterns = [
    path('admin/', admin.site.urls),
    path('', include('public.urls', namespace='public'))
]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now we have this in place, we can now run our server. We'll see an error in the browser which says &lt;br&gt;
TemplateDoesNotExist at /public/home/html&lt;/p&gt;

&lt;p&gt;If you get this error, it shows you're doing things right. The last thing to fix this error is to go to our settings.py file and tell Django how to locate our templates files&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;TEMPLATES = [
    {
        ...
        'DIRS': [BASE_DIR / 'templates'],
      ...
    },
]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With this in place, we can now create a templates folder in our main project directory and proceed to create a public folder in the templates folder and finally create a home.html file in the public folder.&lt;br&gt;
&lt;strong&gt;templates/public/home.html&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Now we need to update our home.html file with the code below;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;!doctype html&amp;gt;
&amp;lt;html lang="en"&amp;gt;

&amp;lt;head&amp;gt;
  &amp;lt;!-- Required meta tags --&amp;gt;
  &amp;lt;meta charset="utf-8"&amp;gt;
  &amp;lt;meta name="viewport" content="width=device-width, initial-scale=1"&amp;gt;

  &amp;lt;!-- Bootstrap CSS --&amp;gt;
  &amp;lt;link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/css/bootstrap.min.css" rel="stylesheet"
    integrity="sha384-EVSTQN3/azprG1Anm3QDgpJLIm9Nao0Yz1ztcQTwFspd3yD65VohhpuuCOmLASjC" crossorigin="anonymous"&amp;gt;

  &amp;lt;title&amp;gt;Hello, world!&amp;lt;/title&amp;gt;

&amp;lt;/head&amp;gt;

&amp;lt;body&amp;gt;

  &amp;lt;style&amp;gt;
    .centralize-div {
      display: flex !important;
      justify-content: center !important;
    }
  &amp;lt;/style&amp;gt;

  &amp;lt;nav class="navbar navbar-expand-lg navbar-light bg-light"&amp;gt;
    &amp;lt;div class="container-fluid"&amp;gt;
      &amp;lt;a class="navbar-brand" href="#"&amp;gt;Django Users&amp;lt;/a&amp;gt;
      &amp;lt;button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarSupportedContent"
        aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation"&amp;gt;
        &amp;lt;span class="navbar-toggler-icon"&amp;gt;&amp;lt;/span&amp;gt;
      &amp;lt;/button&amp;gt;
      &amp;lt;div class="collapse navbar-collapse" id="navbarSupportedContent"&amp;gt;
        &amp;lt;ul class="navbar-nav me-auto mb-2 mb-lg-0"&amp;gt;
          &amp;lt;li class="nav-item"&amp;gt;
            &amp;lt;a class="nav-link active" aria-current="page" href="#"&amp;gt;Posts&amp;lt;/a&amp;gt;
          &amp;lt;/li&amp;gt;
        &amp;lt;/ul&amp;gt;
      &amp;lt;/div&amp;gt;
    &amp;lt;/div&amp;gt;
  &amp;lt;/nav&amp;gt;

  &amp;lt;div class="container py-5"&amp;gt;
    &amp;lt;div class="row"&amp;gt;
        &amp;lt;h1&amp;gt;There are {{ users.count }} users&amp;lt;/h1&amp;gt;
    &amp;lt;/div&amp;gt;
  &amp;lt;/div&amp;gt;

  &amp;lt;script src="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/js/bootstrap.bundle.min.js"
    integrity="sha384-MrcW6ZMFYlzcLA8Nl+NtUVF0sA7MsXsP1UyJoMp4YLEuNSfAP+JcXn/tWtIaxVXM" crossorigin="anonymous"&amp;gt;
    &amp;lt;/script&amp;gt;

&amp;lt;/body&amp;gt;
&amp;lt;/html&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the code above, we are only using the Django templating language to tell Django how many users we have on our Django project. Currently, we have zero, so we have to create a super user so we can add more and more users to our platform.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;python manage.py createsuperuser
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now we have some users on our platform, we can see that when we visit the home page we see a zero change to the number of users we just created in the admin panel.&lt;/p&gt;

&lt;p&gt;We now have our basic Django setup, it's now time to work on our celery function. In our case, I want to keep things simple so we'll first write the most basic email function and include it on our home page so that when the page loads it will run the function. Once this works fine, then we can proceed to make it asynchronous with celery.&lt;/p&gt;

&lt;p&gt;Now create a new file "tasks" in our public app  and add the code below;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;from django.contrib.auth.models import User
from django.core.mail import send_mail

from celery import task
from celery.utils.log import get_task_logger


logger = get_task_logger(__name__)


# @task
def send_emails_to_users():
    users = User.objects.all()
    users_emails = []
    for user in users:
        users_emails.append(user.email)

    sending_mail = send_mail(
        'Subject here',
        'Here is the message.',
        'from@example.com',
        [users_emails],
        fail_silently=False,
    )
    print("Voila, Email Sent to " + str(len(users)) + " users")
    return sending_mail
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In our code above, we're importing the Django User model and send_mail for sending emails with Django. We're also import task which is what celery uses to send our function to queue to handle our function asynchronously. Even if our function just doesn't run maybe because of some failure, celery tasks will help us deliver our function to another worker to run the function.&lt;/p&gt;

&lt;p&gt;Next is our function that sends the email to all our users. First we set our users to be all the users on the platform then we have an empty list of users_emails. Our for loop helps us to get all the emails of all users and we now append these emails into our empty user_emails list.&lt;/p&gt;

&lt;p&gt;Last block sends emails to all the users on our platform. Once you have all these in place, the last steps is to add this line of code below in our settings file for our email setup. For the purpose of this tutorial, we'll print our emails to the console and not sending actual emails to our user's email addresses&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Email Settings
EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend'
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Alright, now we need to add our email function in our views.py file so our function will be called whenever we load our homepage. Update our views.py with the code below;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;from django.shortcuts import render
from django.contrib.auth.models import User
from .tasks import send_emails_to_users


def home_view(request):
    users = User.objects.all()
    context = {
        'users': users
    }
    send_emails_to_users()
    return render(request, 'public/home.html', context)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;All good, we now have everything working just fine. Run the server and monitor the command line for the outputs you'll get.&lt;/p&gt;

&lt;p&gt;In our console, we can see it prints the email and the email message being sent and also the print statement we added to our email function. &lt;/p&gt;

&lt;p&gt;Now, this is working as expected, but it is not using celery and it is not asynchronous. For us to make it asynchronous, we now need to uncomment "@task"  in our email function in tasks.py. This tells celery to handle our function. Our final code will look like this;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;from django.contrib.auth.models import User
from django.core.mail import send_mail

from celery import task
from celery.utils.log import get_task_logger


logger = get_task_logger(__name__)


@task
def send_emails_to_users():
    users = User.objects.all()
    users_emails = []
    for user in users:
        users_emails.append(user.email)

    sending_mail = send_mail(
        'Subject here',
        'Here is the message.',
        'from@example.com',
        [users_emails],
        fail_silently=False,
    )
    print("Voila, Email Sent to " + str(len(users)) + " users")
    return sending_mail
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next is to update our views.py by adding the .delay which is a celery method for calling tasks and is very convenient. Our final views.py should look like this;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;from django.shortcuts import render
from django.contrib.auth.models import User
from .tasks import send_emails_to_users


def home_view(request):
    users = User.objects.all()
    context = {
        'users': users
    }
    send_emails_to_users.delay()
    return render(request, 'public/home.html', context)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now run our server, you'll notice that our server still works perfectly fine but not with celery and our email function doesn't work. The very last step is to open another command line in the same project folder. This will be specifically for celery worker, use the command below;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;celery -A my_project worker --pool=solo -l info
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We're all set, now in the celery worker's console, you'll see the output of the previous result of our initial request to the home view webpage.&lt;/p&gt;

&lt;p&gt;Thank you all and this is all about this celery guide, we can make things better by adding an email service to send actual emails to our user's email addresses. If you have any questions, feel free to reach out to me, the final code repository for this project is in the GitHub repo below;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/Arthurobo/django-celery-send-emails-to-all-users"&gt;https://github.com/Arthurobo/django-celery-send-emails-to-all-users&lt;/a&gt;&lt;/p&gt;

</description>
    </item>
    <item>
      <title>DJANGO HTMX LOAD MORE OBJECTS</title>
      <dc:creator>Arthur Obo-Nwakaji</dc:creator>
      <pubDate>Mon, 21 Nov 2022 09:11:42 +0000</pubDate>
      <link>https://dev.to/arthurobo/django-htmx-load-more-objects-3jg3</link>
      <guid>https://dev.to/arthurobo/django-htmx-load-more-objects-3jg3</guid>
      <description>&lt;p&gt;In this guide, we'll be using Django and HTMX to load more objects from the database without refreshing our page. Traditionally, adding a load more button which sends a request to the database to load more data is done with JavaScript. But now we can load more data by writing little to no JavaScript for this purpose.&lt;/p&gt;

&lt;p&gt;First, we need to set up our Django project by first creating a virtual environment and installing the necessary dependencies. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;CREATING A VIRTUAL ENVIRONMENT&lt;/strong&gt;&lt;br&gt;
To create a virtual environment on your windows machine, run the command below;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;python -m venv my_project
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next, we need to change the directory into the newly created virtual environment with the command below;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cd my_project
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now we need to activate the virtual environment with the command below;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;scripts\activate
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We are done with creating our virtual environment and can now continue to start our new project by first creating the project with the name "blog". But before we do that, we need to first install Django which will be used and also going to help us create a Django project easily.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;pip install Django
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After installing Django, we now need to start our new Django blog project with the command below;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;django-admin startproject blog
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After starting our project, we now need to change the directory into this newly created blog project with the command below;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cd blog
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We're all set and can now test our project is ready by running the server. To run the server, use the command below;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;python manage.py runserver
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now our server is running, we can now go to our local host on port 8000 to confirm Django is running. 127.0.0.1:8000&lt;/p&gt;

&lt;p&gt;Congratulations, we're now up and running and have successfully started our new Django project in a virtual environment which is now running on port 8000.&lt;/p&gt;

&lt;p&gt;Now we need to create a new app to handle all our blog posts. To do this, go back to your command line and kill the server running and then run this command below;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;python manage.py startapp posts
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now our new "posts" app is ready, we can now add the app in our settings.py file. To add it, locate the INSTALLED_APPS and add 'posts ' to the list.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;INSTALLED_APPS = [
    ...
    'posts',
]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now we can continue by creating our models instance in our posts app. Go to models.py in the posts app and continue with the code below;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;class Post(models.Model):
    title = models.CharField(max_length=100)
    description = models.CharField(max_length=255)
    body = models.TextField()
    date_created = models.DateTimeField(auto_now_add=True)
    last_updated = models.DateTimeField(auto_now=True)
    def __str__(self):
        return str(self.title)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After adding all to the models.py, we need to update our admin.py file in the posts app so we can easily add posts from the easy django admin site.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;from django.contrib import admin
from .models import Post

admin.site.register(Post)

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We are good to go, this is all we need for this tutorial. Now we can proceed to migrate all our data to the database by running the command below;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;python manage.py makemigrations
python manage.py migrate

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After migrating our database, we now need to create a django superuser which will manage everything in our django admin panel which includes adding posts to our database. Run the command below to create a superuser;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;python manage.py createsuperuser

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Fill in your credentials and then your superuser can now log into the admin panel which is located at (&lt;a href="http://127.0.0.1:8000/admin/"&gt;http://127.0.0.1:8000/admin/&lt;/a&gt;). First you need to run the server again to access the django admin panel.&lt;br&gt;
Login to the django admin panel and add at least 20 blog posts for our testing purpose.&lt;/p&gt;

&lt;p&gt;We now have up to 20 blog posts so we can start doing all we have to do in loading our posts on our site. First, we need to go to the posts app and start writing our home view to load all our posts.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;from django.shortcuts import render
from .models import Post


def home(request):
    posts = Post.objects.all()
    context = {
        'posts': posts,
    }
    return render(request, 'posts/all-posts.html', context)

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Breakdown of our views.py&lt;br&gt;
first line imports render which returns a HttpResponse&lt;/p&gt;

&lt;p&gt;The second line imports our Post models objects which return all the posts we added to the database initially.&lt;/p&gt;

&lt;p&gt;Our function is the views that our URLs will call and render. This function also adds our blog posts to the context which can be called in the Django template language&lt;/p&gt;

&lt;p&gt;This is all we need in our views, for now, we can now proceed to add our URLs so Django will display our posts in the root URL. To do this, create a url.py file in the posts app and add the code below.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;from django.urls import path
from .views import home

app_name = 'home'

urlpatterns = [
    path('', home, name='home')
]

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now we need to add this URL in the root URLs. We now need to go to blog/urls.py and update it to be like this code below;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;from django.contrib import admin
from django.urls import path, include

urlpatterns = [
    path('admin/', admin.site.urls),
    path('', include('posts.urls', namespace='posts'))
]

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now we can run the server and visit &lt;a href="http://127.0.0.1:8000"&gt;http://127.0.0.1:8000&lt;/a&gt;. Now you'll see we have an error which says &lt;br&gt;
TemplateDoesNotExist at /posts/all-posts.html&lt;/p&gt;

&lt;p&gt;This is a friendly error for us in this case and it shows we have all things in place. Next, we'll need to create a templates folder in our root directory and a posts folder in the newly created templates folder. In this posts folder, we need to add our home.html file. This setup is based on our views.py where we have our home.html setup. &lt;br&gt;
Once this is in place, we need to go to our settings.py file and instruct Django where to find our Html files.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': [BASE_DIR / 'templates'],
        'APP_DIRS': True,
        ...

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here we updated the DIRS with the value; &lt;br&gt;
'DIRS': [BASE_DIR / 'templates'],&lt;/p&gt;

&lt;p&gt;This is all we need for our templates setup, we'll add our html files soon.&lt;/p&gt;

&lt;p&gt;Next we need to install htmx with the command below;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;pip install django-htmx
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After installing htmx, we now need to add htmx to our installed apps;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;...
'django_htmx',
...

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next is to add htmx to our middleware&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;...
'django_htmx.middleware.HtmxMiddleware',
...

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We're all ready to start using htmx in our django project. First we have to go to views.py and update our views with the code below;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;from django.shortcuts import render
from .models import Post
from django.core.paginator import EmptyPage, PageNotAnInteger, Paginator


def home(request):
    posts = _load_posts(request)
    context = {"posts": posts,}
    return render(request, "posts/all-posts.html", context)


def list_load_posts_view(request):
    posts = _load_posts(request)
    context = {"posts": posts,}
    return render(request, "posts/partials/all-posts.html", context)


def _load_posts(request):
    page = request.GET.get("page")
    posts = Post.objects.all().order_by('-date_created')
    paginator = Paginator(posts, 3)
    try:
        posts = paginator.page(page)
    except PageNotAnInteger:
        posts = paginator.page(1)
    except EmptyPage:
        posts = paginator.page(paginator.num_pages)
    return posts
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We're all good to go, our last steps will include creating a urls.py file in our posts app and update with the code below&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;from django.urls import path
from .views import home, list_load_posts_view

app_name = 'home'

urlpatterns = [
    path('', home, name='home'),
    path('posts/', list_load_posts_view, name='posts'),
]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now we have all our setup, we can now add our html files. We need two html files, one is the main home page view while the second will be included from our htmx view from our partials folder.&lt;/p&gt;

&lt;p&gt;Now if we go back to our root url, we'll see a django error html page. This shows we're on the right track and can now update our all-posts.html file with the code below.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;!doctype html&amp;gt;
&amp;lt;html lang="en"&amp;gt;

&amp;lt;head&amp;gt;
  &amp;lt;!-- Required meta tags --&amp;gt;
  &amp;lt;meta charset="utf-8"&amp;gt;
  &amp;lt;meta name="viewport" content="width=device-width, initial-scale=1"&amp;gt;

  &amp;lt;!-- Bootstrap CSS --&amp;gt;
  &amp;lt;link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/css/bootstrap.min.css" rel="stylesheet"
    integrity="sha384-EVSTQN3/azprG1Anm3QDgpJLIm9Nao0Yz1ztcQTwFspd3yD65VohhpuuCOmLASjC" crossorigin="anonymous"&amp;gt;

  &amp;lt;title&amp;gt;Hello, world!&amp;lt;/title&amp;gt;

  &amp;lt;!-- HTMX --&amp;gt;
  &amp;lt;script src="https://unpkg.com/htmx.org@1.6.0"&amp;gt;&amp;lt;/script&amp;gt;
  &amp;lt;script src="https://cdn.jsdelivr.net/npm/sortablejs@latest/Sortable.min.js"&amp;gt;&amp;lt;/script&amp;gt;
&amp;lt;/head&amp;gt;

&amp;lt;body&amp;gt;

  &amp;lt;style&amp;gt;
    .centralize-div {
      display: flex !important;
      justify-content: center !important;
    }
  &amp;lt;/style&amp;gt;

  &amp;lt;nav class="navbar navbar-expand-lg navbar-light bg-light"&amp;gt;
    &amp;lt;div class="container-fluid"&amp;gt;
      &amp;lt;a class="navbar-brand" href="#"&amp;gt;BLOG&amp;lt;/a&amp;gt;
      &amp;lt;button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarSupportedContent"
        aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation"&amp;gt;
        &amp;lt;span class="navbar-toggler-icon"&amp;gt;&amp;lt;/span&amp;gt;
      &amp;lt;/button&amp;gt;
      &amp;lt;div class="collapse navbar-collapse" id="navbarSupportedContent"&amp;gt;
        &amp;lt;ul class="navbar-nav me-auto mb-2 mb-lg-0"&amp;gt;
          &amp;lt;li class="nav-item"&amp;gt;
            &amp;lt;a class="nav-link active" aria-current="page" href="#"&amp;gt;Posts&amp;lt;/a&amp;gt;
          &amp;lt;/li&amp;gt;
        &amp;lt;/ul&amp;gt;
      &amp;lt;/div&amp;gt;
    &amp;lt;/div&amp;gt;
  &amp;lt;/nav&amp;gt;

  &amp;lt;div class="container py-5"&amp;gt;
    &amp;lt;div class="row"&amp;gt;
      {% include 'posts/partials/all-posts.html' %}
    &amp;lt;/div&amp;gt;
  &amp;lt;/div&amp;gt;

  &amp;lt;script src="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/js/bootstrap.bundle.min.js"
    integrity="sha384-MrcW6ZMFYlzcLA8Nl+NtUVF0sA7MsXsP1UyJoMp4YLEuNSfAP+JcXn/tWtIaxVXM" crossorigin="anonymous"&amp;gt;
    &amp;lt;/script&amp;gt;

&amp;lt;/body&amp;gt;
&amp;lt;/html&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If we go through our code above, you can see we have a basic bootstrap navigation bar, and all our posts from the database. &lt;/p&gt;

&lt;p&gt;Lastly, we need to create a folder named "partials" in the posts templates and add the just included html file "all-posts.html". Add the code below to the htmx partials file;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{% if posts %}
{% for post in posts %}
&amp;lt;div class="col-md-4 centralize-div"&amp;gt;
  &amp;lt;div class="card m-2 p-2" style="width: 18rem;"&amp;gt;
    &amp;lt;div class="card-body"&amp;gt;
      &amp;lt;h5 class="card-title"&amp;gt;{{ post.title }}&amp;lt;/h5&amp;gt;
      &amp;lt;p class="card-text"&amp;gt;
        {{ post.body|truncatechars:50 }}
      &amp;lt;/p&amp;gt;
      &amp;lt;!-- &amp;lt;a href="#" class="btn btn-primary"&amp;gt;Visit&amp;lt;/a&amp;gt; --&amp;gt;
    &amp;lt;/div&amp;gt;
  &amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
{% endfor %}
{% else %}
&amp;lt;div class="centralize-div"&amp;gt;
  &amp;lt;h3 class="ui header center aligned"&amp;gt;No results!&amp;lt;/h3&amp;gt;
&amp;lt;/div&amp;gt;
{% endif %}


&amp;lt;div class="centralize-div py-5" id="load-more"&amp;gt;
  {% if posts.has_next %}
  &amp;lt;div class="ui divider"&amp;gt;&amp;lt;/div&amp;gt;
  &amp;lt;button class="btn btn-primary" hx-get="{% url 'posts:posts' %}"
    hx-vals='{"page": "{{ posts.next_page_number }}", "posts": "{{ posts }}"}' hx-target="#load-more"
    hx-swap="outerHTML"&amp;gt;
    Load more
  &amp;lt;/button&amp;gt;
  {% endif %}
&amp;lt;/div&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Congratulations, we now have a working django project which has the load more feature working fine with less code and working efficiently. You can access the code in the github repo, also feel free to ask your questions and possible suggestions if you find me making the wrong decisions, I appreciate your time and effort.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/Arthurobo/django-htmx-load-more-objects"&gt;https://github.com/Arthurobo/django-htmx-load-more-objects&lt;/a&gt;&lt;/p&gt;

</description>
      <category>python</category>
      <category>django</category>
      <category>htmx</category>
      <category>javascript</category>
    </item>
  </channel>
</rss>
