Coding Mom
Coding Mom

Reputation: 17

How to fix the URL not always redirecting without a trailing slash in Django

I am developing a web app in Python with Django and my url's are not consistently loading the correct view if a trailing slash is not added. The about page loads fine with and without a trailing slash yet my contact page only works if a trailing slash is added. It also affects some other pages as well. It ends up going to my single_slug function which is the last pattern in urls.py. It should do that if there is not a match in the url's but the trailing slash is obstructing the match somehow. It ends up returning HttpResponse(f"{single_slug} does not correspond to anything!").

I have attempted to add APPEND_SLASH = True in my settings.py yet it didn't change anything as it already is True by default.

Here is my views.py:

from django.http import HttpResponse
from .models import Move, Artist
from django.contrib.auth.forms import UserCreationForm, AuthenticationForm
from django.contrib.auth import login, logout, authenticate
from django.shortcuts import render, redirect
from django.contrib import messages
from .forms import NewUserForm, ContactForm


# Create your views here.
def homepage(request):
    return render(request, 'main/home.html'

def about(request):
    return render(request, 'main/about.html')

def contact(request):
    form_class = ContactForm

    return render(request, 'main/contact.html', {
        'form': form_class,
    })

def single_slug(request, single_slug):
    artists = [a.artist_slug for a in Artist.objects.all()]
    if single_slug in artists:        
        artists = Artist.objects.filter(artist_slug__icontains=single_slug)
        return render(request, 'main/artist_detail.html', {'artists': artists})


    moves = [m.move_slug for m in Move.objects.all()]
    if single_slug in moves:
        moves = Move.objects.filter(move_slug__icontains=single_slug)
        return render(request, 'main/move_detail.html', {'moves': moves})

    return HttpResponse(f"{single_slug} does not correspond to anything!")

Here is my models.py:

class Move(models.Model):
        move_title = models.CharField(max_length=200)
        move_slug = models.SlugField(unique=True, max_length=250)

        def __str__(self):
            return self.move_title

        def save(self, *args, **kwargs):
            self.move_slug = slugify(self.move_title)
            super(Move, self).save(*args, **kwargs)

class Artist(models.Model):
        artist_name = models.CharField(max_length=200)
        artist_slug = models.SlugField(unique=True, max_length=250)

        def __str__(self):
            return self.artist_name

        def save(self, *args, **kwargs):
            self.artist_slug = slugify(self.artist_name)
            super(Artist, self).save(*args, **kwargs)

Here is my urls.py:

from django.urls import path
from django.conf.urls import url
from . import views



app_name = 'main'  # here for namespacing of urls.

urlpatterns = [

    path('', views.homepage, name="homepage"),
    path('about/', views.about, name="about"),
    path('contact/', views.contact, name="contact"),
    path('<single_slug>', views.single_slug, name="single_slug"),


]

Here is my about.html:

{% extends 'main/header.html' %}

{% block content %}

{% endblock %}

Here is my contact.html:

{% extends 'main/header.html' %}

{% block content %}
<h1>Contact</h1>
<form role="form" action="" method="post">
    {% csrf_token %}
    {{ form.as_p }}
    <button type="submit">Submit</button>
</form>
{% endblock %}

Upvotes: 1

Views: 1177

Answers (1)

Alasdair
Alasdair

Reputation: 308769

Django tries to match all URL patterns before it appends a slash, so the single_slug pattern will prevent this since about and contact look like slugs. /about and /contact should be treated the same way for the code you have posted, so I can’t explain why you are seeing different behaviour for them.

If you add a trailing slash to your single_slug path, then /about and /contact should be redirected to append a slash, and match the correct pattern.

path('<single_slug>/', views.single_slug, name="single_slug")

Upvotes: 1

Related Questions