Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

django template url tag with empty argument

I'm trying to make an article list view of my homepage which works in two ways.
Here is a part of my app url.py:

path('article_list/<slug:tag>', views.article_list, name='article_list'),

I would like to make this one URL cover both all articles case and tag-specified article case, by making the view shows all articles if slug: tag is ''.
Here is a part of my view.py:

def article_list(request, tag):
    if tag == '':
        articles = get_list_or_404(Article)
    else:
        articles = get_list_or_404(Article, tags__name__in=[tag], publish=True)

    context = {
        'tag': tag,
        'articles': articles,
    }
    return render(request, 'blog/article-list.html', context)

Every thing works just fine execpt rethriving all article URL on html with django template {% url %} tag.
I want something like this:

href="{% url 'article_list' '' %}"

How can I make the URL with an empty argument(in this case, empty slug)?

like image 973
Chanwoo Ahn Avatar asked Oct 18 '25 04:10

Chanwoo Ahn


1 Answers

The reason this does not work is because the <slug:…> path converter [Django-doc] matches only non-empty subsequences of the path. Indeed, the class is defined as [GitHub]:

class SlugConverter(StringConverter):
    regex = '[-a-zA-Z0-9_]+'

There are basically two options here: generate two paths (one for tags, one without tags), or implement a path converter/use a regex.

Option 1: two paths

# app/urls.py

from django.urls import path
from app import views

urlpatterns = [
    path('article_list/', views.article_list, name='article_list', kwargs={'slug': ''}),
    path('article_list/<slug:tag>', views.article_list, name='article_list'),
]

Option 2: implement a path converter

It might be worth here to implement a path converter yourself:

# app/converters.py

from django.urls.converters import SlugConverter

class EmptyOrSlugConverter(SlugConverter):
    regex = '[-a-zA-Z0-9_]*'

Then you can register this and use the <emptyorslug:…> path converter:

# app/urls.py

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

register_converter(converters.EmpotyOrSlug, 'emptyorslug')

urlpatterns = [
    path('article_list/<emptyorslug:tag>', views.article_list, name='article_list'),
]

Note that you can slightly improve the readability of your view with:

def article_list(request, tag):
    if not tag:
        articles = get_list_or_404(Article, tags__slug=tag, publish=True)
    else:
        articles = get_list_or_404(Article)

    context = {
        'tag': tag,
        'articles': articles,
    }
    return render(request, 'blog/article-list.html', context)

Note that you probably want to filter on the slug of the tag, not the name.

like image 71
Willem Van Onsem Avatar answered Oct 20 '25 10:10

Willem Van Onsem



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!