Redirect a URL from a class-based view to another

2

When moving my WordPress blog to Django I changed the structure of the permanent links, before I did not use category in the structure and now yes. More or less like this:

/slug/ ⟼ /cat/slug/

And then I'm getting a lot of 404 errors, because Django only searches in category. So I decided to add a search engine in the class-based view of the categories:

class CategoryDetail(ListView, CacheMixin):
    model = Entry
    paginate_by = 6

    def get_queryset(self):
        self.cat = get_object_or_404(Category, slug=self.kwargs['slug'])
        return Entry.objects.filter(
            category=self.cat, status=Entry.LIVE_STATUS).select_related() \
            .order_by('-pub_date', 'id')

In the function get_queryset I want to add a redirect that calls the class EntryDetail if the slug corresponds to an entry and not a category.

I do it like this:

def get_queryset(self):
    try:
        entry = Entry.objects.get(slug=self.kwargs['slug'])
        return redirect(entry)
    except Entry.DoesNotExist:
        pass
    self.cat = get_object_or_404(Category, slug=self.kwargs['slug'])
    return Entry.objects.filter(
        category=self.cat, status=Entry.LIVE_STATUS).select_related() \
        .order_by('-pub_date', 'id')

I use slug to search the entry (if can not find it , I catch the exception DoesNotExist and I look for the category) and if there is such an entry, I redirect the request to the indicated entry , which contains the get_absolute_url() property as indicated by the documentation with return redirect(entry) . But it does not work.

It also does not work if I use this form of redirect , which matches the URL pattern:

# En urls.py: 
# url(r'^(?P<cat>[-\w]+)/(?P<slug>[-\w]+)/$', EntryDetail.as_view(), name="entry_detail")    
return redirect('entry_detail', cat=entry.category, slug=entry.slug)

The problem, in both cases, is that I get the following error:

TypeError at /el-circulo/
object of type 'HttpResponseRedirect' has no len()

The function len() is used for paging, because the answer I keep sending it to the CBV CategoryDetail .

How can I make the wording I need work?

That is, how can I get out of the class that was called by the request and return the answer with a different class, in this case with EntryDetail .

    
asked by toledano 03.08.2017 в 19:45
source

1 answer

2

I imagine the error:

TypeError at /el-circulo/
object of type 'HttpResponseRedirect' has no len()

It happens since you are returning a HttpResponseRedirect instead of a queryset which is what the get_queryset method would have to return. As I mentioned in my comment, I do not think this method is the right place for a redirect.

What I would do would be to pass the redirection to the get method and leave the part of the queryset as you had it initially:

from django.core.exceptions import ObjectDoesNotExist

class CategoryDetail(ListView, CacheMixin):
    # ...

    def get(self, *args, **kwargs):
        if 'slug' in self.kwargs:
            try:
                entry = Entry.objects.get(slug=self.kwargs['slug'])
                return redirect(entry)
            except ObjectDoesNotExist:
                pass
        return super(CategoryDetail, self).get(*args, **kwargs)

    def get_queryset(self):
        self.cat = get_object_or_404(Category, slug=self.kwargs['slug'])
        return Entry.objects.filter(
            category=self.cat, status=Entry.LIVE_STATUS).select_related() \
            .order_by('-pub_date', 'id')
    
answered by 03.08.2017 / 20:13
source