Search code examples
djangohttp-redirectdjango-viewsdjango-urlsdjango-2.1

RedirectView give NoReverseMatch


Recently I've changed the paths of the blog posts to give more legible the urls.

Before I've this paths:

path("category/<slug:slug_category>/", views.singleCategory_postList, name="single_category"),
path("<slug:slug_post>/", views.singlePost, name='single_blog_post'),

Now I've this:

path("<slug:slug_category>/", views.singleCategory_postList, name="single_category"),
path("<slug:slug_category>/<slug:slug_post>/", views.singlePost, name='single_blog_post'),

Before get_absolute_url was this:

class Category(models.Model):
.....
    def get_absolute_url(self): 
        return reverse("single_category", kwargs={"slug_category": self.slug_category})


class BlogPost(ModelPost, TimeManager):
.....
    def get_absolute_url(self): 
        return reverse("single_blog_post", kwargs={"slug_post": self.slug_post})

Now is this:

class Category(models.Model):
.....
def get_absolute_url(self): 
    return reverse("single_category", kwargs={"slug_category": self.slug_category})


class BlogPost(ModelPost, TimeManager):
.....
def get_absolute_url(self): 
    return reverse("single_blog_post", kwargs={
                                            "slug_post": self.slug_post,
                                            "slug_category": self.category.slug_category,
                                            })

I'm trying to use the RedirectView for redirect all the old paths; then into urls.py I've this now:

path("category/<slug:slug_category>/", RedirectView.as_view(pattern_name='single_category', permanent=True)),
path("<slug:slug_post>/", RedirectView.as_view(pattern_name='single_blog_post', permanent=True)),

path("categorie/", views.categoryList, name="list_category"),
path("<slug:slug_category>/", views.singleCategory_postList, name="single_category"),

path("", views.postList, name='list_post'),
path("<slug:slug_category>/<slug:slug_post>/", views.singlePost, name='single_blog_post'),

When I use those RedirectView it's shown me this error:

NoReverseMatch at /blog/gis/

Reverse for 'single_blog_post' with keyword arguments '{'slug_post': 'gis'}' not found. 1 pattern(s) tried: ['blog\/(?P[-a-zA-Z0-9_]+)\/(?P[-a-zA-Z0-9_]+)\/$']

If I comment the two RedirectView paths the error disappear and I can use the site without problems but when I use the old paths I see 404 error.

I don't have understood how RedirectView works. Someone can give me an example?


Solution

  • The problem is that your old view only required the post slug, but your new one additionally requires the category slug. However, there's no way a simple RedirectView can do this redirection, because it can only look at the arguments passed in the original URL itself. It doesn't know how to go to the database to find the category slug and use it in the redirection.

    So, you'll need to write the redirect view yourself. It could be pretty simple:

    def redirect_with_category(request, slug):
        post = get_object_or_404(Post, slug=slug)
        return redirect(post, permanent=True)
    

    Note that redirect will automatically call the get_absolute_url method of the Post. Also note you want to use permanent=True to return a 301 rather than a 302.