LeoFranco LeoFranco - 1 month ago 9
Python Question

Reverse for 'detail' with keyword arguments '{'id': 5}' not found. 1 pattern(s) tried: ['posts/(?P<slug>[\\w-]+)/$']

I'm super stuck with NoReverseMatch at /posts/ error. Maybe I am overlooking something small or maybe this issue is much bigger than where I am digging.

http://imgur.com/nlyMi9V
Error message when models.py is like this:

def get_absolute_url(self):
#return reverse("detail", kwargs={ "slug": self.slug })
return reverse("posts:detail", kwargs={ "slug": self.slug })


http://imgur.com/a/RilrB
Error message when models.py is like this:

def get_absolute_url(self):
return reverse("detail", kwargs={ "slug": self.slug })
#return reverse("posts:detail", kwargs={ "slug": self.slug })





models.py

#from _future_ import __unicode__literals
from django.db import models
from django.core.urlresolvers import reverse
from django.db.models.signals import pre_save

from django.utils.text import slugify

# Create your models here.
# MVC Models Views Controller

def upload_location(instance, filename):
# filebase, extension = filename.spilt(".")
# return "%s/%s.%s" %(instance.id, instance.id, filename)
return "%s/%s" %(instance.id, filename)

class Post(models.Model):
title = models.CharField(max_length=120)
slug = models.SlugField(unique=True)
image = models.ImageField(upload_to=upload_location,
null=True,
blank=True,
width_field="width_field",
height_field="height_field")
height_field = models.IntegerField(default=0)
width_field = models.IntegerField(default=0)
content = models.TextField()
updated = models.DateTimeField(auto_now=True, auto_now_add=False)
timestamp = models.DateTimeField(auto_now=False, auto_now_add=True)

def __unicode__(self):
return self.title

def __str__(self):
return self.title

def get_absolute_url(self):
#return reverse("detail", kwargs={ "slug": self.slug })
return reverse("posts:detail", kwargs={ "slug": self.slug })

class Meta:
ordering = ["-timestamp", "-updated"]


def create_slug(instance, new_slug=None):
slug = slugify(instance.title)
if new_slug is not None:
slug = new_slug
qs = Post.objects.filter(slug=slug).order_by("-id")
exists = qs.exists()
if exists:
new_slug = "%s-%s" %(slug, qs.first().id)
return create_slug(instance, new_slug=new_slug)
return slug

def pre_save_post_receiver(sender, instance, *args, **kwargs):
if not instance.slug:
instance.slug = create_slug(instance)

pre_save.connect(pre_save_post_receiver, sender=Post)


views.py

from django.contrib import messages
from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger
from django.http import HttpResponse, HttpResponseRedirect
from django.shortcuts import render, get_object_or_404, redirect

from .forms import PostForm
# Create your views here.
from .models import Post


def post_create(request):
form = PostForm(request.POST or None, request.FILES or None,)
if form.is_valid():
instance = form.save(commit=False)
instance.save()
# message success
messages.success(request, "Successfully Created!")
return HttpResponseRedirect(instance.get_absolute_url())
context = {
"form": form,
}
return render(request, "post_form.html", context)

def post_detail(request, slug=None):
#instant = Post.objects.get(id=0)
instance = get_object_or_404(Post, slug=slug)
context = {
"title": instance.title,
"instance": instance,
}
return render(request, "post_detail.html", context)

def post_list(request):
queryset_list = Post.objects.all() #.order_by("-timestamp")
paginator = Paginator(queryset_list, 5) # Show 5 contacts per page
page_request_var = "page"
page = request.GET.get(page_request_var)
try:
queryset = paginator.page(page)
except PageNotAnInteger:
# If page is not an integer, deliver first page.
queryset = paginator.page(1)
except EmptyPage:
# If page is out of range (e.g. 9999), deliver last page of results.
queryset = paginator.page(paginator.num_pages)

context = {
"object_list": queryset,
"title": "List",
"page_request_var": page_request_var
}
return render(request, "post_list.html", context)
#return HttpResponse("<h1>List</h1>")


def post_update(request, slug=None):
instance = get_object_or_404(Post, slug=slug)
form = PostForm(request.POST or None, request.FILES or None, instance=instance)
if form.is_valid():
instance = form.save(commit=False)
instance.save()
# message success
messages.success(request, "<a href='#'>Item</a> Saved", extra_tags='html_safe')
return HttpResponseRedirect(instance.get_absolute_url())

context = {
"title": instance.title,
"instance": instance,
"form":form,
}
return render(request, "post_form.html", context)

def post_delete(request, slug=None):
instance = get_object_or_404(Post, slug=slug)
instance.delete()
messages.success(request, "Successfully deleted!")
return redirect("posts:list")


urls.py

from django.conf.urls import url
from django.contrib import admin
from . import views

# from .views import (
# post_list,
# post_create,
# post_detail,
# post_update,
# post_delete,
# )

# video: https://www.youtube.com/watch?annotation_id=annotation_3160187747&feature=iv&index=14&list=PLEsfXFp6DpzQFqfCur9CJ4QnKQTVXUsRy&src_vid=nw3R2TXlkwY&v=1KuyH8JVn6A
# shows a different solution here for version 1.10

urlpatterns = [
#url(r'^$', views.post_home),
# url(r'^$', views.post_list, name='list'),
# url(r'^create/', views.post_create), #name='create'
# url(r'^(?P<slug>[\w-]+)/', views.post_detail, name='detail'),
# url(r'^(?P<slug>[\w-]+)/edit/', views.post_update, name='update'),
# url(r'^(?P<slug>[\w-]+)/delete/', views.post_delete),

url(r'^$', views.post_list, name='list'),
url(r'^create/$', views.post_create, name='create'),
url(r'^(?P<slug>[\w-]+)/$', views.post_detail, name='detail'),
url(r'^(?P<slug>[\w-]+)/edit/$', views.post_update, name='update'),
url(r'^(?P<slug>[\w-]+)/delete/$', views.post_delete),

# url(r'^$', posts.views.post_home),
# url(r'^create/', home_create),
# url(r'^list/', home_list),
# url(r'^detail/', home_detail),
# url(r'^update/', home_update),
# url(r'^delete/', home_delete),

# url(r'^posts/$', "<appname>.views.<function_name>"),
]


post_list.py

{% extends "base.html" %}

{% block head_title %}
{{ instance.title }} | {{ block.super }}
{% endblock head_title %}


{% block content %}

<div class="row justify-content-md-center">
<div class='col-md-8'>
<h1>{{title}}</h1>
</div>

{% for obj in object_list %}

<div class='col-md-8 pt-3'>
<div class="card" style="min-width: 20rem;">
{% if obj.image %}
<img src="{{ obj.image.url }}" class="card-img-top">
{% endif %}
<div class="card-body">
<h4 class="card-title">
<a href='{{ obj.get_absolute_url }}'>{{ obj.title }}</a>
<small>{{ obj.timestamp|timesince }} ago</small>
</h4>
<p class="card-text">{{ obj.content|linebreaks|truncatechars:120 }}</p>
<p class="card-text">{{ obj.updated }}</p>
<p class="card-text">{{ obj.id }}</p>
<!-- <a href='{% url "posts:detail" id=obj.id %}'>{{ obj.title }}</a><br/> -->
<a href="{{ obj.get_absolute_url }}" class="btn btn-primary">View</a>
</div>
</div>
</div>

{% endfor %}

<div class='col-md-8'>
<div class="pagination">
<span class="step-links">
{% if object_list.has_previous %}
<a href="?{{ page_request_var }}={{ object_list.previous_page_number }}">previous</a>
{% endif %}

<span class="current">
Page {{ object_list.number }} of {{ object_list.paginator.num_pages }}.
</span>

{% if object_list.has_next %}
<a href="?{{ page_request_var }}={{ object_list.next_page_number }}">next</a>
{% endif %}
</span>
</div>
</div>

</div>

{% endblock content %}

Answer Source

The error is coming from this line

<!-- <a href='{% url "posts:detail" id=obj.id %}'>{{ obj.title }}</a><br/>  -->

<!-- is an html comment, so Django still tries to reverse the url when it renders the template.

You can either remove the line entirely, change it to a Django comment {# ... #}, or change it to use the slug instead of id.