Reputation: 17
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
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