Question

I have a paginated comments page. Pagination is provided by django-endless-pagination. When clicking to new paginated pages a get parameter is append to the url. Such as ?page=4.

Each comment on each paginated page displays a 'reply to' comment form containing a captcha field.

My view uses CreateView and I implement form_invalid myself in order to add some data to the context variable. At the end of my form_invalid method I return self.render_to_response(context)

The Problem

If a user attempts to reply to a comment when on page 4, and that user supplies and invalid captcha, then the pagination get parameter (?page=4) is lost during the response.

How can I redirect to the full path (keeping get params) and pass context data along with it?

Thanks

Était-ce utile?

La solution

This problem is similar to this SO question, but my scenario is a little different given that I want to maintain my form state (the captcha error mentioned in question) in the redirect.

Thank you @petkostas for pointing out HTTP_REFERER

My resolution to this involved storing the context in cache with a cache key derived from the current timestamp. I redirect to the (same) comments url, but in doing this I append the current comment page as a get parameter and also the timestamp as another get parameter.

Then during get requests the view checks for the existence of the timestamp parameter. If it is provided, then a cache.get call is made to retrieve the needed context data. And finally, the cached item is deleted.

from datetime import datetime
from django.core.cache import cache
from django.shortcuts import redirect
from django.utils.dateformat import format

class MyView(CreateView):
    def form_invalid(self, form, **kwargs):
        context = {
            'form': form,
            ... other context stuff ...
        }

        timestamp = format(datetime.now(), u'U')
        cache.set('invalid_context_{0}'.format(timestamp), context)

        page = 1
        full_path = self.request.META.get('HTTP_REFERER')
        if '?' in full_path:
            query_string = full_path.split('?')[1].split('&')
            for q in query_string:
                if q.startswith('page='):
                    page = q.split('=')[1]

        response = redirect('my_comments_page')
        response['Location'] += '?page={0}&x={1}'.format(page, timestamp)
        return response

    def get_context_data(self, **kwargs):
        context = super(MyView, self).get_context_data(**kwargs)
        context.update({
           ... add context stuff ...
        })

        if 'x' in self.request.GET:
            x = self.request.GET.get('x')
            cache_key = 'invalid_context_{0}'.format(x)
            invalid_context = cache.get(cache_key)
            if invalid_context:
                context.update(invalid_context)
                cache.delete(cache_key)
        return context

Autres conseils

I haven't used django-endless-pagination, but Django offers 2 ways to get either the full current request path, or the Refferer of the request: In your view or template (check documentation on how to use request in templates) for the referring requesting page:

request.META.get('HTTP_REFERER')

Or for the current request full path:

request.full_path()
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top