Using URL Patterns to Connect Views

Introduction

Django is one of the most powerful and popular web frameworks in the Python ecosystem. It follows the Model-View-Template (MVT) architecture, which organizes your application into three main components — Models (data), Views (logic), and Templates (presentation).

While models define the structure of your data and templates define how information is presented, views handle the core business logic — they process requests and return responses. However, before a view can be executed, Django needs to know which view should handle which URL.

This mapping between a URL and its corresponding view function is achieved through Django’s URL dispatcher using URL patterns.

In this detailed guide, we’ll explore how Django processes URLs, how to define and manage URL patterns, how to connect them to views, and how to organize them for scalable projects. You’ll also learn about path converters, dynamic URLs, namespaces, include(), and best practices for maintaining clean and maintainable URL configurations.

Understanding Django’s URL Dispatcher

When a user makes a request to a Django-powered website (for example, visiting https://example.com/home), Django doesn’t automatically know which piece of code should handle it. Instead, it relies on a URL dispatcher, which works like a routing system that looks for a matching pattern in your project’s URL configuration.

Here’s what happens step by step:

  1. A request comes into Django.
  2. Django checks the project’s urls.py file to see which URL pattern matches the requested path.
  3. When a match is found, Django calls the view function associated with that pattern.
  4. The view processes the request and returns a response (often rendered through a template).
  5. If no pattern matches, Django returns a 404 Page Not Found error.

This URL mapping mechanism is flexible, powerful, and one of Django’s core strengths.


The Role of urls.py

In every Django project, you’ll find a file named urls.py. It acts as the central routing configuration for your application.

  • The project-level urls.py (located in the main project folder) defines the root URL configuration.
  • Each app inside your project can have its own urls.py file that defines URL routes specific to that app.

This separation allows large projects to remain modular and maintainable.


Setting Up a Basic Django Project

Before we dive deeper into URL patterns, let’s create a simple Django project to demonstrate how URLs connect to views.

Step 1: Create a New Django Project

Run the following command in your terminal:

django-admin startproject myproject

This creates a project structure like:

myproject/
manage.py
myproject/
    __init__.py
    settings.py
    urls.py
    asgi.py
    wsgi.py

Step 2: Create a New App

Navigate into the project folder and create a new app:

python manage.py startapp myapp

Now your structure looks like:

myproject/
myproject/
    urls.py
myapp/
    views.py
    urls.py

Step 3: Register the App

Open myproject/settings.py and add 'myapp' to INSTALLED_APPS:

INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'myapp',
]

Creating Your First View

In Django, a view is simply a Python function or class that takes a request and returns a response.

Open myapp/views.py and add:

from django.http import HttpResponse

def home(request):
return HttpResponse("Welcome to the Home Page!")

This is a simple view that returns a plain text response.


Connecting the View with a URL

Now we’ll create a URL pattern that connects this view to a specific web address.

Step 1: Create a urls.py File Inside the App

By default, new Django apps don’t include a urls.py file. Create one manually inside your app folder (myapp/urls.py):

from django.urls import path
from . import views

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

Here’s what happens:

  • The path() function defines a URL pattern.
  • The empty string '' means this view will handle the root URL of the app.
  • views.home links the pattern to the view function.
  • name='home' gives this URL a name for easy reference in templates and redirects.

Including App URLs in the Project’s URL Configuration

Next, we need to tell Django that our app’s URLs exist.

Open myproject/urls.py and modify it like this:

from django.contrib import admin
from django.urls import path, include

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

Here, the include() function tells Django to include all the URL patterns defined in myapp/urls.py whenever a request starts with the empty path ''.

Now, when you run:

python manage.py runserver

and visit http://127.0.0.1:8000/, you’ll see:

Welcome to the Home Page!

Congratulations — you’ve just linked your first view to a URL using Django’s URL dispatcher!


Understanding the path() Function

The path() function is the most commonly used method for defining URL patterns.

Syntax:

path(route, view, kwargs=None, name=None)

Parameters:

  1. route: A string that represents the URL pattern (for example 'about/' or 'blog/<int:id>/').
  2. view: The view function or class that should handle requests to this URL.
  3. kwargs: Optional arguments passed to the view.
  4. name: A name for the URL pattern, which helps reference it later.

Example: Multiple URL Patterns

You can define multiple routes in your app’s urls.py:

from django.urls import path
from . import views

urlpatterns = [
path('', views.home, name='home'),
path('about/', views.about, name='about'),
path('contact/', views.contact, name='contact'),
]

And in views.py:

from django.http import HttpResponse

def about(request):
return HttpResponse("About Us Page")
def contact(request):
return HttpResponse("Contact Us Page")

Now:

  • http://127.0.0.1:8000/ → Home page
  • http://127.0.0.1:8000/about/ → About page
  • http://127.0.0.1:8000/contact/ → Contact page

Dynamic URL Patterns with Path Converters

Static URLs like /about/ are fine, but most real-world websites have dynamic URLs — such as /products/5/ or /blog/python-basics/.

Django’s URL dispatcher allows you to capture parts of the URL and pass them as arguments to views using path converters.

Example 1: Integer Converter

path('user/<int:user_id>/', views.user_detail, name='user_detail')

In your view:

def user_detail(request, user_id):
return HttpResponse(f"User ID: {user_id}")

Now visiting /user/10/ will display:

User ID: 10

Example 2: String Converter

path('blog/<str:slug>/', views.blog_post, name='blog_post')

In the view:

def blog_post(request, slug):
return HttpResponse(f"Blog Slug: {slug}")

Visiting /blog/python-basics/ will output:

Blog Slug: python-basics

Common Path Converters

Django provides several built-in converters:

ConverterMatchesExample
<int:var>Integers/user/1/
<str:var>Non-empty strings without slashes/blog/post/
<slug:var>Letters, numbers, hyphens, and underscores/article/django-tutorial/
<uuid:var>UUID strings/item/550e8400-e29b-41d4/
<path:var>Any string including slashes/files/images/logo.png

You can even define custom path converters, but built-ins usually cover most needs.


Using re_path() for Regular Expressions

If you need more flexibility than the simple converters, Django also offers the re_path() function, which allows you to use regular expressions.

Example:

from django.urls import re_path
from . import views

urlpatterns = [
re_path(r'^article/(?P&lt;year&gt;&#91;0-9]{4})/$', views.article_year),
]

In views.py:

def article_year(request, year):
return HttpResponse(f"Articles from {year}")

Now /article/2024/ will display:

Articles from 2024

This approach provides more control but is harder to read, so path() with converters is preferred unless you specifically need regex.


URL Names and Reverse URL Resolution

Using named URLs is one of Django’s best practices. Instead of hardcoding URLs in templates or views, you can refer to them by their names.

Example:

path('about/', views.about, name='about')

In your template:

<a href="{% url 'about' %}">About</a>

In your view:

from django.shortcuts import redirect

def go_to_about(request):
return redirect('about')

This makes your code more maintainable — if the actual URL path changes later, you won’t have to update every reference manually.


Organizing URLs with include()

In large projects with multiple apps, your urls.py files can grow big quickly. Django’s include() function helps break them into smaller, manageable parts.

Example project structure:

myproject/
urls.py
blog/
    urls.py
shop/
    urls.py

In myproject/urls.py:

from django.urls import path, include

urlpatterns = [
path('blog/', include('blog.urls')),
path('shop/', include('shop.urls')),
]

In blog/urls.py:

from django.urls import path
from . import views

urlpatterns = [
path('', views.index, name='blog_home'),
path('&lt;int:post_id&gt;/', views.post_detail, name='post_detail'),
]

Now:

  • /blog/ → Blog home
  • /blog/3/ → Blog post #3

This modular approach improves maintainability and clarity.


URL Namespaces

When multiple apps have the same URL names, Django could get confused. To fix this, you can use namespaces to uniquely identify URLs per app.

Example:

In myproject/urls.py:

urlpatterns = [
path('blog/', include(('blog.urls', 'blog'), namespace='blog')),
path('shop/', include(('shop.urls', 'shop'), namespace='shop')),
]

Now you can reference them as:

<a href="{% url 'blog:post_detail' 3 %}">Read Post</a>
<a href="{% url 'shop:product_detail' 5 %}">View Product</a>

This ensures there’s no conflict between URL names across apps.


Passing Extra Parameters via URLs

You can pass extra parameters to views using the kwargs argument.

path('welcome/', views.greet, {'greeting': 'Hello'}, name='greet')

And in the view:

def greet(request, greeting):
return HttpResponse(f"{greeting}, visitor!")

When you visit /welcome/, it will display:

Hello, visitor!

Redirecting URLs

Django provides utilities for redirecting URLs to other views or locations.

Example:

from django.views.generic import RedirectView

urlpatterns = [
path('old-home/', RedirectView.as_view(url='/new-home/')),
]

Visiting /old-home/ will redirect to /new-home/.


Handling 404 Errors

If a URL doesn’t match any pattern, Django automatically raises a 404 error.

You can create a custom 404 page by adding a view:

def custom_404(request, exception):
return HttpResponse("Sorry, page not found!", status=404)

Then in settings.py:

handler404 = 'myapp.views.custom_404'

This enhances user experience by providing friendly error messages.


Reverse URL Lookup in Python Code

To dynamically build URLs in your Python code, use reverse() from django.urls.

Example:

from django.urls import reverse

url = reverse('about')
print(url)
# Output: /about/

You can also pass parameters:

url = reverse('post_detail', args=[3])
# Output: /blog/3/

This is especially useful in redirects or APIs where URLs are generated programmatically.


Best Practices for Managing URLs

  1. Use Named URLs: Always name your URL patterns for flexibility.
  2. Keep URLs Human-Readable: URLs should be simple and descriptive (/about-us/ instead of /page1/).
  3. Use include() for Modularity: Each app should have its own urls.py.
  4. Avoid Hardcoding URLs: Use {% url %} in templates and reverse() in views.
  5. Prefer path() over re_path() unless regex is necessary.
  6. Add Trailing Slashes: Django conventionally ends URLs with /.
  7. Use Namespaces: When multiple apps might reuse URL names.
  8. Organize Logically: Group related routes in meaningful patterns.

Example: A Complete Blog URL Setup

Let’s put it all together.

blog/views.py

from django.http import HttpResponse

def index(request):
return HttpResponse("Welcome to the Blog!")
def post_detail(request, post_id):
return HttpResponse(f"Viewing Post #{post_id}")

blog/urls.py

from django.urls import path
from . import views

app_name = 'blog'

urlpatterns = [
path('', views.index, name='index'),
path('&lt;int:post_id&gt;/', views.post_detail, name='post_detail'),
]

myproject/urls.py

from django.urls import path, include

urlpatterns = [
path('blog/', include('blog.urls')),
]

Now:

  • /blog/ → Blog homepage
  • /blog/1/ → Post with ID 1

Advanced: Custom Path Converters

You can even create your own custom path converters.

Example:

myapp/converters.py

class FourDigitYearConverter:
regex = '&#91;0-9]{4}'
def to_python(self, value):
    return int(value)
def to_url(self, value):
    return '%04d' % value

Register the Converter

In myapp/urls.py:

from django.urls import path, register_converter
from . import views, converters

register_converter(converters.FourDigitYearConverter, 'yyyy')

urlpatterns = [
path('archive/&lt;yyyy:year&gt;/', views.archive, name='archive'),
]

In views.py:

def archive(request, year):
return HttpResponse(f"Archive for year {year}")

Now visiting /archive/2025/ will work perfectly.


URL Routing with Class-Based Views

You can also map URLs to class-based views (CBVs) using the as_view() method.

Example:

from django.views import View
from django.http import HttpResponse

class HelloView(View):
def get(self, request):
    return HttpResponse("Hello from a Class-Based View!")

In urls.py:

from django.urls import path
from .views import HelloView

urlpatterns = [
path('hello/', HelloView.as_view(), name='hello'),
]

This approach is ideal for building REST APIs or views that handle multiple request types (GET, POST, etc.).


Summary

We’ve covered a lot in this guide! Let’s recap:

  • Django routes incoming requests using URL patterns.
  • URL patterns are defined in urls.py files.
  • The path() function connects a URL to a specific view.
  • Dynamic URLs use path converters to capture variable data.
  • Use include() to organize app URLs modularly.
  • Always name your URLs and use reverse() or {% url %} to reference them.
  • Use namespaces to prevent naming conflicts across apps.
  • Custom path converters and class-based views make your URLs even more powerful.

Comments

Leave a Reply

Your email address will not be published. Required fields are marked *