URL Namespacing in Django: What is app_name in Django?

Share your love

URL namespaces, as used in Django URLs, are essential URL configurations that help to avoid confusion between URL names across different apps and app instances.

As you know, Django apps are more likely to implement CRUD (Create, Read, Update, Delete) operations. Thus, you will end up having create, update, read, and delete URL endpoints in a Django project. If you have more than one app in your Django project, let’s say blog and products apps, you may have conflicting URL names when you use CRUD operations.

Conflicting URL names may arise when you name one app URL name that is similar to another app URL name.

For example, let’s say our blog app has a list view of every blog post on your website. Thus, you will end up with a URL name of ‘list’. Therefore, in your template, list.html, you will have a URL configuration that looks like this:

{% url 'list' %}

Similar to your blog app, you have another list view for every product you sell on your website. Therefore, you will create a URL name for the products with a similar URL name, ‘list’. So, in your template, list.html, you will have another URL configuration that looks similar:

{% url 'list' %}

With such a URL configuration in your Django project, you will end up having conflicting URL names, and you may end up viewing blog posts when you want to view products in your Django project.

What is URL namespacing in Django?

A solution to such a problem is to use URL namespaces to uniquely identify URLs for each app in your Django project that may have similar URL configurations. As seen in the example above, you should use namespacing to identify URL endpoints for a blog and products apps uniquely.

We can achieve URL namespaces in Django by using the app_name argument in our app-level URL configuration (urls.py file of each app).

What is app_name in Django? Django app_name is an argument used in app-level URL configuration to uniquely identify each app URL and achieve URL namespacing. Thus, app_name helps create a unique URL name that you can use to reverse URLs in your views, models, or templates of your Django project.

The purpose of app_name in urls.py in Django is to:

  1. Reverse unique URL names for different Django applications using the same URL names
  2. Helps third-party apps achieve URL namespacing and avoid conflicting URLs with the project’s URL configuration
  3. Allow reversing unique URLs for shared named URLs when multiple instances of an application are used.

Advantages of using URL namespacing in Django

  1. It helps avoid URL hardcoding within your Django code (reverse()) and in your templates ({% url %})
  2. It helps avoid URL naming redundancy that may make debugging and changing URLs an expensive task in terms of time and effort.
  3. Allows Django developers to implement multiple instances of a Django app in a project
  4. It helps avoid conflicting URLs within your Django project

How to create a URL namespace for your Django apps

To create URL namespacing in Django URL configuration, open the app-level URL configuration file and add the app_name argument with the name of the app. By adding the argument, you instruct Django to match the URLs of the application whenever the namespacing is used in other parts of your project.

Here is an example of adding a namespace in a Django application, blog.

Step 1: Open urls.py of the blog app

from django.urls import path

from . import views


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

Step 2: Edit urls.py of the blog app and add the app_name argument

Add the app_name argument on top of your urlpatterns variable following the syntax: app_name=the_name_of_your_app


from django.urls import path

from . import views

app_name='blog'

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

After creating the app_name argument for each Django app, you should use the app_name:named URL syntax to reference the URL for each app correctly. For our example, blog application, you may use the following syntax in your templates:

{% url 'blog:list' %}

Also, you can use the URL namespacing in your reverse method, especially when creating the get_absolute_url() for your instance objects. Here is a code example:

    ...
    def get_absolute_url(self):
        return reverse("blog:detail", args={str(self.id)})

How to use URL namespace in Django (with an example project)

To demonstrate how to implement URL namespacing in Django, we will create a new Django project, create two applications, create conflicting URLs, and provide a solution for the conflicting URLs using URL namespacing.

Create a new Django project

Open a new Terminal window, navigate into the Desktop folder, and create a new folder for our new Django project.

You may create a Django project folder anywhere on your file system.

cd ~/Desktop && mkdir new_django_project 

cd ~/Desktop/new_django_project

Create a new environment that you will use to install Django.

Use the command below if you already have a particular directory for all your virtual environment.

I use the ~/.virtualenvs directory to store all my virtual environments. Use your preferred directory

python -m venv ~/.virtualenvs/url_namespacing

If you want to create the same directory I use for all my virtual environments, use the command below:

mkdir ~/.virtualenvs 

python -m venv ~/.virtualenvs/url_namespacing

After creating the virtual environment, activate it and install Django.

source ~/.virtualenvs/url_namespacing/bin/activate

pip install django

After installing Django and its dependencies, create a new Django project in the same folder you had created earlier. I used the Desktop directory earlier.

cd ~/Desktop/new_django_project

django-admin startproject spongeBlog .

I used spongeBlog as the name of my project, but you can use any name for your Django project.

After successfully creating a new Django project, open the project’s folder with your favorite IDE or editor.

cd ~/Desktop/new_django_project && code .

Start creating the blog and products apps. I may use the blog to write articles about sponges for a project like this. Later, after gaining some traffic, I may sell sponges, sponge cleaning kits, or how-to guide books in my products app.

Create apps for your Django project

Create the blog app by typing the following with your virtual environment active.

python manage.py startapp blog

Create products app

python manage.py startapp products

Register your apps in the settings.py of your Django project

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

    'blog',
    'products',
]

Let’s create product and blog models for our Django website:

Blog post model (blog/models.py):

from django.db import models


class BlogPost(models.Model):
    article_title = models.CharField(max_length=80)

    def __str__(self):
        return self.article_title

Product model (product/models.py):

from django.db import models


class Product(models.Model):
    product_name = models.CharField(max_length=255)

    def __str__(self):
        return self.product_name

Create migrations and migrate to create persistent tables in the database

python manage.py makemigrations 

python manage.py migrate

Create views for the product and blog models

Blog views (blog/views.py):

from django.shortcuts import render, get_object_or_404

from .models import BlogPost


def index(request):
    # fetch all the products in the database
    context = {'articles': BlogPost.objects.all()}
    template_name = 'list.html'
    return render(request, template_name, context)


def article(request, id):
    # fetch a single product with an id
    article = get_object_or_404(BlogPost, id=id)
    context = {'article': article}
    template_name = 'detail.html'
    return render(request, template_name, context)

Create the templates, list.html, and detail.html, and add the following code

In list.html, add:

Articles
<ul>
    {% for article in articles %}
        <li><a href="">{{ article }}</a></li>
    {% endfor %}
</ul>

In detail.html, add:

Article Detail

{{ article.article_title }}

Product views (products/views.py):

from django.shortcuts import render, get_object_or_404

from .models import Product


def index(request):
    # fetch all the products in the database
    context = {'products': Product.objects.all()}
    template_name = 'list.html'
    return render(request, template_name, context)


def product(request, id):
    # fetch a single product with an id
    product = get_object_or_404(Product, id=id)
    context = {'product': product}
    template_name = 'detail.html'
    return render(request, template_name, context)

Create the templates, list.html, and detail.html inside the/templates/products folder and add the following code

In list.html, add:

Products
<ul>
    {% for product in products %}
        <li><a href="">{{ product }}</a></li>
    {% endfor %}
</ul>

In detail.html, add:

Product detail

{{ product.product_name }}

Create URLs for the products and blog apps

Blog app URLs (blog/urls.py):

from django.urls import path

from .views import index, article

urlpatterns = [
    path('', index),
    path('<int:id>/', article,),
]

Product app URLs (product/urls.py):

from django.urls import path

from .views import index, product

urlpatterns = [
    path('', index),
    path('<int:id>/', product),
]

Add our app-level URL configuration to the project-level configuration

Open the main project urls.py and add the following lines of code to add blog and product URLs to the Django project.

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

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

If you access http://127.0.0.1:8000/, you can see that Django is rendering the correct products in the database. Access the products page, http://127.0.0.1:8000/products. Well, you will find that the page shows a list of products.

Create conflicting URLs names in your Django project

Let’s create URL names that are similar in both blog and products apps:

Open the blog app urls.py and name the URL that shows all the articles, list.

Also, name the products list URL, list.

So, the final files should look like this:

blog/urls.py

from django.urls import path

from .views import index, article

urlpatterns = [
    # updated line
    path('', index, name='list'),
    path('<int:id>/', article,),
]

products/urls.py

from django.urls import path

from .views import products, product

urlpatterns = [
    # updated line
    path('', products, name='list'),
    path('<int:id>/', product),
]

Use the following URL names in your blog and products list templates, list.html. To do this, let’s add navigation at the top of each blog/templates/list.html and products/templates/products/list.html file.

blog/templates/list.html

Navigation
<a href="{% url 'list' %}">Articles</a>
<a href="{% url 'list' %}">Products</a>

<br style="margin: 2rem">

Articles
<ul>
    {% for article in articles %}
        <li><a href="">{{ article }}</a></li>
    {% endfor %}
</ul>

products/templates/products/list.html

Navigation
<a href="{% url 'list' %}">Articles</a>
<a href="{% url 'list' %}">Products</a>

<br style="margin: 2rem">


Products
<ul>
    {% for product in products %}
        <li><a href="">{{ product }}</a></li>
    {% endfor %}
</ul>

Now try clicking on the Articles and Products links.

If you have noticed, the URL for Articles links goes to the articles page, and the URL for Products link goes to the articles page.

This happens because each app uses a similar URL name for the list view. A solution is to use URL namespacing to create unique list view URLs for the blog and products app.

A solution for conflicting URL names by using URL namespacing

A solution for conflicting URL names is to use the app_name argument in your app URL configuration to identify and associate app-level URLs to their own app uniquely.

Here’s how to resolve conflicting URL names in your URL namespacing configuration.

Step 1: Add an app_name argument for each of your apps.

Open urls.py of the blog app and add the following line above urlpatterns variable:

app_name = 'blog'

So, your final urls.py will look like this:

from django.urls import path

from .views import index, article

app_name = 'blog'
urlpatterns = [
    path('', index, name='list'),
    path('<int:id>/', article,),
]

Do the same for the products app:

from django.urls import path

from .views import products, product

app_name = 'products'
urlpatterns = [
    path('', products, name='list'),
    path('<int:id>/', product),
]

Now, update your templates to use the correct URL names by specifying the app name in your template url tag:

blog/templates/list.html

Navigation
<a href="{% url 'blog:list' %}">Articles</a>
<a href="{% url 'products:list' %}">Products</a>

<br style="margin: 2rem">

Articles
<ul>
    {% for article in articles %}
        <li><a href="">{{ article }}</a></li>
    {% endfor %}
</ul>

products/templates/products/list.html

Navigation
<a href="{% url 'blog:list' %}">Articles</a>
<a href="{% url 'products:list' %}">Products</a>

<br style="margin: 2rem">


Products
<ul>
    {% for product in products %}
        <li><a href="">{{ product }}</a></li>
    {% endfor %}
</ul>

And voila!

Your site navigation works correctly after implementing the correct URL namespacing. I showed you an actual example for a project because I have done this many times and get frustrated when my links do not work. Or they take me to a different page I did not intend to. When the only solution is to name URLs used in my Django applications uniquely.

By using URL namespacing, I am able to identify the errors in my URLs and adjust them correctly. With that, I am able to prevent the reverse() method and {% url %} template tag from returning an incorrect URL. Thus, I can avoid URL-pattern mismatches, as seen in our example above.

Related Questions and Debugging

What is the difference between namespace and app_name in Django

Django namespace helps achieve uniquely name URLs across your Django applications. Thus, namespace helps avoid conflicting URL names from different apps or multiple instances of an app using the same URL name.

On the other hand, app_name is the argument that you pass in your app-level URL configuration (app urls.py) defining the name of the app. Therefore, you can use the app name to uniquely identify URLs that fall under that app.

Each application namespace is defined using the app_name argument inside the app-level URL configuration file (app/urls.py).

How to solve specifying a namespace in include() without providing an app_name is not supported in Django

When you get the specifying a namespace in include() without providing an app_name error in Django, you should check that you have declared the app_name variable in your apps’ urls.py files. In short, ensure you have correctly implemented URL namespacing in your Django project.

Check you’re using the correct syntax:

app_name = 'your_app_name'

How to solve NoReverseMatch: is not a registered namespace in Django

You should declare the app_name argument in each app urls.py file you include/use in your URL name. Ensure you have app_name in your urls.py of each app.

“NoReverseMatch: is not a registered namespace” is a common error you will probably encounter when working with URL namespacing in Django. Here are the common reasons you may get the NoReverseMatch error type.

Reasons that lead to NoReverseMatch error type in Django

  1. You have a mistyped/typo error in your namespace keyword. The namespace keyword in your reverse function or your template url tag does not match the one declared in the app_name argument.
  2. You have not declared the app_name argument in your app’s urls.py file

Solutions to NoReverseMatch error type in Django

  1. Check that the named URL matches an already created URL in an app with its URL namespace declared.
  2. Check that you do not have any typos in your namespace URL names
  3. Create a namespace for apps using the same URL names. Thus, declare app_name arguments in your apps’ url.py and change your named-URL instances in templates and reverse() methods.

What is the difference between instance namespace and application namespace in Django?

In Django urls, instance namespace is an URL naming configuration that happens within two different instances of the same Django app using the same URL configuration. On the other hand, application namespace help realizes unique URL naming for different applications using the same URL name.

Instance namespaceApplication namespace
Used for different instances of a Django applicationUsed for different Django apps in your project

The END

The code used in this example can be found here on GitHub.

Share your love
Badi
Badi

Badi here, creator of ngangasn.com— A website dedicated to providing helpful information and how-to's of web development and hosting. Inspired by a fascination to write the most efficient code to make a computer laugh, & humans, Steve has a passion for organizing characters to create code and informative content.
What makes me happy?
Well, nothing like the feeling of finally figuring out that one pesky bug that's been driving me crazy.

Leave a Reply

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