I like structure. I like knowing where things belong and how they connect, which is probably why Django stuck with me. In this post, I walk through how I structure my backend projects, from models and templates to reusable apps that make sense six months later.
Nothing fancy, just the small systems that keep me organised when I build. I have learned that every project teaches you something new, and this is where I record those lessons. I share what’s working, what I have broken, and what I have learned to rebuild better. For me, this isn’t about creating perfect apps, but about understanding the logic behind them and becoming a little more fluent in Django every time.
Starting the Foundation
When I begin a new Django project, I start with the basics. A clean structure that helps me think clearly. I usually create an apps folder right away. It’s a simple decision that keeps my project organised as it grows. I set up a virtual environment for each folder then begin.
Inside the folder, I place each app: accounts, core, blog, shop, prompts, or whatever fits the project.
Over time, I learned that separating functionality into logical apps prevents chaos later. For example, core usually holds global templates and utilities - the pages that every project needs, like the homepage, policy pages, or contact forms. accounts is where user management lives. If I am working on an eCommerce site, I add a shop app for products and orders.
Each app has its own models.py, views.py, urls.py, and templates directory. I prefer that isolation - it makes each app feel like its own small world that can be reused or swapped out in another project.
Defining Models
Models are always my starting point. They define the data and, in many ways, the logic of the system. I like to start small with one or two models that describe the essentials.
For a blog, for example, it might look like this:
# blog/models.py
from django.db import models
from django.utils.text import slugify
class Post(models.Model):
title = models.CharField(max_length=200)
slug = models.SlugField(unique=True, blank=True)
content = models.TextField()
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
published = models.BooleanField(default=False)
def save(self, *args, **kwargs):
if not self.slug:
self.slug = slugify(self.title)
super().save(*args, **kwargs)
def __str__(self):
return self.title
It’s simple but it covers a lot. I add slugs automatically, use timestamps for ordering, and include a publish toggle for drafts. That’s the backbone of most blog-style content I create.
When I am building for eCommerce, I add a Product model, a Category model, and sometimes an Order model later. I try to keep relationships explicit - ForeignKey for one-to-many, ManyToManyField where necessary, but never more than I need at the start.
Building Views
Views are where I connect logic to what the user sees. In most of my projects, I start with simple class-based views - usually ListView and DetailView.
# blog/views.py
from django.views.generic import ListView, DetailView
from .models import Post
class PostListView(ListView):
model = Post
template_name = "blog/post_list.html"
context_object_name = "posts"
queryset = Post.objects.filter(published=True).order_by("-created_at")
class PostDetailView(DetailView):
model = Post
template_name = "blog/post_detail.html"
context_object_name = "post"
I use these as the foundation before introducing more complex logic. For me, readability matters more than cleverness. If I can open a file six months later and understand what it does instantly, that’s a win.
Over time, I might add API endpoints using Django REST Framework, but only when I need them. I’ve learned not to over-engineer.
Routing with URLs
Next comes the urls.py file — my roadmap.
# blog/urls.py
from django.urls import path
from . import views
app_name = "blog"
urlpatterns = [
path("", views.PostListView.as_view(), name="post_list"),
path("<slug:slug>/", views.PostDetailView.as_view(), name="post_detail"),
]
Then I include it at the project level:
# project/urls.py
from django.urls import path, include
urlpatterns = [
path("", include("core.urls", namespace="core")),
path("blog/", include("blog.urls", namespace="blog")),
]
That’s one of my favourite things about Django, how logical it feels. Each app is neatly contained, and including it in the main routes is just one line.
Templates That Make Sense
Templates are where structure really shows. Recently, I am forming the habit of keeping all app-specific templates inside each app - but it wasn't always like that. So for a portfolio app, I have:
portfolio/
└── templates/
└── portfolio/
├── portfolio_list.html
└── portfolio_detail.html
This prevents name clashes when you have multiple apps with similar views, like a list.html in shop and or blog apps. Django’s namespacing takes care of the rest.
A simple list template might look like this:
<!-- blog/templates/blog/post_list.html -->
<section class="max-w-5xl mx-auto mt-10 px-4 space-y-6">
<h1 class="text-3xl font-bold text-[color:var(--color-brand-primary)]">Latest Posts</h1>
{% for post in posts %}
<article>
<h2 class="text-xl font-semibold">
<a href="{% url 'blog:post_detail' slug=post.slug %}" class="hover:text-[color:var(--color-brand-accent)]">
{{ post.title }}
</a>
</h2>
<p class="text-[color:var(--color-font-main)] mt-2">{{ post.content|truncatewords:40 }}</p>
</article>
{% empty %}
<p>No posts yet.</p>
{% endfor %}
</section>
The key for me is keeping templates consistent. I use the same layout pattern - header, section, footer - so everything feels cohesive across the site.
Making Apps Reusable
The real magic happens when an app I built six months ago can drop neatly into a new project. My accounts app, for example, now includes login, registration, password reset, and a simple dashboard layout. I built it once, refined it a few times, and now it’s part of my base toolkit.
That’s the reward of building with Django: you don’t just create a website; you create a system you can reuse and evolve.
I also make sure each app can work independently. No unnecessary imports from other apps, no tangled dependencies. The goal is always clarity - knowing that every app does one thing well.
Lessons Along the Way
I have rebuilt some projects three times before they made sense. Early on, I tried cramming too much into one app, or mixing presentation with logic. Now I separate cleanly - one folder, one purpose.
Another big shift came when I started thinking in terms of scalability. Even small projects deserve a strong foundation. I might be building a blog today, but tomorrow it might need authentication, subscriptions, or a shop, so I build with that in mind.
I also stopped chasing the “perfect” structure. Django gives you a solid base, but every project has its quirks. What matters is understanding why you are doing something, not just following a tutorial or the instructions of AI.
Reflections
Building with Django has become a kind of practice for me - equal parts technical and personal. Each model, view, and template reminds me that progress in development comes from doing the small things right, consistently.
Structure doesn’t just make my code cleaner. It keeps my mind clear too. When everything has a place, I can focus on creating something that works and something that grows with me.
Every time I start a new project, I learn a little more about what I value in design, discipline, and the satisfaction of watching something I built actually work.
That’s why I keep building. Not because it’s easy but because Django keeps teaching me how to think.
Thanks for sharing: