On Wed, Nov 24, 2010 at 4:20 PM, Jacob Kaplan-Moss <[email protected]> wrote:
> Okay, I think we're narrowing in on things. Just so I'm clear, you've
> got a view that sets a message towards the beginning and then displays
> that message in the template *on the very same request*, yes?

Basically, yes.

> So in essence you're doing something like::
>
>    def my_view(request):
>        set_some_messages(request)
>        response = render_to_response(...)
>        set_some_cookies(response)
>        return resp
>
> But you'd like to collapse `set_some_messages()` and
> `set_some_cookies()` into a single function, so something like::
>
>    def my_view(request):
>        response = render_to_response(...)
>        set_some_cookies_and_messages(request, response)
>        return response
>
> Does that about some it up?

It's a simplification, but yes.

> Because if so, the problem has nothing to do with cookies. It's
> happening because the messages are being fetched in the template,
> which you're rendering into a response "too early". This in fact has
> nothing to do with the request/response cycle or anything, but just
> with the fact that you're fetching messages from a template into a
> response. But remember: you can get a response without rendering a
> template, so you could do something like this::
>
>    def my_view(request):
>        response = HttpResponse()
>        set_some_cookies_and_messages(request, response)
>        response.write(render_to_string(...))
>        return response
>
> render_to_response is a shortcut that collapses a bunch of steps for
> the common case, but does so at the expense of inflexibility.

Right. I do know that, but as I said before, this example is a
simplification. Just for completeness, I'll lay it all out for you.
I'm sure it won't change your mind, but hopefully it'll more clearly
demonstrate the dilema.

I have a set of views that I'd like to potentially show one or more
messages to the user. These messages will be created by one or more
functions that are registered into a module I wrote that finds these
special functions and provides a decorator. The decorator is applied
to the views where the messages should be displayed. These messages
are things like, "Your account will expire soon", and since they'll
keep displaying until the user renews, I provide a link for them to
hide the message. That hiding is accomplished by setting a cookie. I'm
also using a cookie to basically cache the fact that the user has
passed the test with no message and therefore doesn't need the check
for the remainder of their browser session. So, this decorator looks
something like:

def check_alerts(func):
    def decor(request):
        for alert in registered_alerts:
            alert(request)
        return func(request)
    return decor

An example alert function might be:

def account_expiring(request):
    if request.COOKIES.get('account_expiring') == 'no':
        return
    if request.user.get_profile().is_about_to_expire():
        message.warning(request, "Your account will expire soon, yo")
    else:
        request.set_cookie('account_expiring', 'no')

That's obviously not exactly the code, but that's the idea. It works
great, and is the least convoluted thing I could come up with. I
thought of creating an empty response in the decorator, passing it to
the alert functions, then passing it to my decorated views and making
them use it instead of what they're already doing. But some are
generic views and some are not my code, so it'd be very difficult to
hack them all into accepting another argument, or using the decorator
to capture the response given by the view, then transfer cookies from
my fake response to the real one before returning it. All of that is
possible, but seemed more hacky to me than having the ability to set a
cookie from the request. I just thought that if I could get myself
into this situation then I'm sure many others have even more complex
systems, and since there'd already been a couple of solutions proposed
in the community, that perhaps it'd be useful for the framework to
have an easy solution.

> PS: Oh, and BTW, the reason you're seeing this problem with messages,
> specifically, is that messages really aren't designed to be produced
> and consumed in the same view. The canonical use case for messages is
> for use in the redirect-after-POST pattern::
>
>    def my_view(request):
>        form = MyForm(request.POST or None)
>        if form.is_valid():
>            form.save()
>            messages.add_message("It worked!")
>            return redirect('success')
>        ...
>
> If you're producing and consuming messages in the same request you
> might want a different tool, or you'll need to work around the
> assumptions that the messages framework makes.

Yeah. Some of these follow that pattern, and some produce and consume
in the same view. The messages framework seems to handle all of this
just fine. Perhaps I'm missing something, but my tests are passing and
the site is functioning as I expect.

Paul

-- 
You received this message because you are subscribed to the Google Groups 
"Django developers" group.
To post to this group, send email to [email protected].
To unsubscribe from this group, send email to 
[email protected].
For more options, visit this group at 
http://groups.google.com/group/django-developers?hl=en.

Reply via email to