7

I'm trying to run a redirect after I check to see if the user_settings exist for a user (if they don't exist - the user is taken to the form to input and save them).

I want to redirect the user to the appropriate form and give them the message that they have to 'save their settings', so they know why they are being redirected.

The function looks like this:

def trip_email(request):
    try:
        user_settings = Settings.objects.get(user_id=request.user.id)
    except Exception as e:
        messages.error(request, 'Please save your settings before you print mileage!')
        return redirect('user_settings')

This function checks user settings and redirects me appropriately - but the message never appears at the top of the template.

You may first think: "Are messages setup in your Django correctly?"

I have other functions where I use messages that are not redirects, the messages display as expected in the template there without issue. Messages are integrated into my template appropriately and work.

Only when I use redirect do I not see the messages I am sending.

If I use render like the following, I see the message (but of course, the URL doesn't change - which I would like to happen).

def trip_email(request):
    try:
        user_settings = Settings.objects.get(user_id=request.user.id)
    except Exception as e:
        messages.error(request, 'Please save your settings before you print mileage!')
        form = UserSettingsForm(request.POST or None)
        return render(request, 'user/settings.html', {'form': form})

I have a few other spots where I need to use a redirect because it functionally makes sense to do so - but I also want to pass messages to those redirects.

The user_settings function looks like this:

def user_settings(request):
    try:
        user_settings = Settings.objects.get(user_id=request.user.id)
        form = UserSettingsForm(request.POST or None, instance=user_settings)
    except Settings.DoesNotExist:
        form = UserSettingsForm(request.POST or None)
    if request.method == 'POST':
        settings = form.save(commit=False)
        settings.user = request.user
        settings.save()
        messages.warning(request, 'Your settings have been saved!')

    return render(request, 'user/settings.html', {'form': form})

I can't find anything in the documentation saying that you can't send messages with redirects... but I can't figure out how to get them to show.

Edit: This is how I render the messages in the template:

{% for message in messages %}
  <div class="alert {{ message.tags }} alert-dismissible" role="alert">
    <button type="button" class="close" data-dismiss="alert" aria-label="Close">
      <span aria-hidden="true">&times;</span>
    </button>
    {{ message }}
  </div>
{% endfor %}

I'm not sure if it matters - but it looks like it's almost calling 'GET' twice from somewhere.

is calling get twice like this normal?

the URL section looks like this for these two URLS:

# ex: /trips/email
url(r'^trips/email/$', views.trip_email, name='trip_email'),
# ex: /user/settings
url(r'^user/settings/$', views.user_settings, name='user_settings'),
Hanny
  • 580
  • 3
  • 16
  • 44
  • how are rendering the message in the template? – Exprator Jun 27 '17 at 16:02
  • Updated with appropriate code. – Hanny Jun 27 '17 at 16:03
  • What template does `user_settings` use? Do you have that snippet in the related template? – Moses Koledoye Jun 27 '17 at 16:05
  • Well, the messages snippet above is included in my base template. My `settings.html` template extends the `base.html` which includes the messages snippet above. Again, other messages work without issue - just not on redirects. – Hanny Jun 27 '17 at 16:07
  • 2
    try one thing, just keep the message and redirect in that function and remove the try catch and hit the url for that view and check if the messages occurs – Exprator Jun 27 '17 at 16:12
  • 1
    When in `trip_email` I get rid of the try - catch and just have the messages and redirect, I do not see the message. – Hanny Jun 27 '17 at 16:16
  • Any way to rule out caching? For example to add `?random=12345` to the URL? –  Jun 27 '17 at 16:19
  • does it redirect to the proper view? – Exprator Jun 27 '17 at 16:22
  • I've tried to rule out caching by clearing the cache / settings, completely reloading the site, relogging in and hitting that URL. Still no messages. – Hanny Jun 27 '17 at 16:22
  • @Exprator - it does redirect to the appropriate view. – Hanny Jun 27 '17 at 16:23
  • Should probably move this to chat, if I can figure out how. But, if you add an `{%if messages %} ... {% else %}
    No messages for you!
    {%endif %}` does it then show that?
    –  Jun 27 '17 at 16:27
  • Yes, it shows 'No Messages For You!' in the nice info blue. – Hanny Jun 27 '17 at 16:30
  • 1
    Ok, good. It really doesn't register with Django. Weird thing is, I'm doing exactly the same, only with class-base views (in form_valid). So trying to figure out what's special about that. Ok, try this: `response = redirect('viewname') messages.error(request, 'wrong!') return response` (3 lines) –  Jun 27 '17 at 16:33
  • I threw up a screenshot of my console - it almost seems like it's calling GET twice for some reason. Not sure if it's intended, but you can see the 302 redirect get fired, then 2 GET requests to the same URL. – Hanny Jun 27 '17 at 16:44
  • With 273 bytes difference, which could be the message. What's the urls section, you may be hit by a slash redirect. –  Jun 27 '17 at 16:48
  • Hey @hanny remove the return and keep only redirect and check once – Exprator Jun 27 '17 at 16:49
  • @Melvyn updated the question with the URL section. Exprator - if I remove 'return' and just have `redirect('user_settings')` it errors the page out. – Hanny Jun 27 '17 at 16:54
  • It's almost like there's a `` in the page somewhere or some other auto-reload function. Cause there's no redirect in between the two requests. Very puzzling. –  Jun 27 '17 at 17:01
  • Yeah, I don't see anything like that in the Meta tags of the `base.html` template. It's baffling to me as well. – Hanny Jun 27 '17 at 17:06
  • It appears to be some crazy browser thing going on. If I open it in other browsers - it works *as expected*. I don't know why I didn't try that sooner. I'm in browser hell I think. I've cleared every setting I can think of, but Chrome (for whatever reason) keeps double-requesting and botching everything up. Safari, Firefox (even IE) all work as intended. Crazy. My frustration is at a 10 right now, ha.. – Hanny Jun 27 '17 at 17:30
  • Did you try [forget me](https://chrome.google.com/webstore/detail/forget-me-clean-history-c/gekpdemielcmiiiackmeoppdgaggjgda)? And yes, it's truly ugly to figure out **why** a browser decides to do this. –  Jun 28 '17 at 08:04
  • I installed forget me (and the cookie extension it wants also) - thanks for that suggestion! I ended up having to reset Chrome to defaults and blow away all the data before it started acting right again. I feel so dumb! But I had never seen that kind of reaction from Chrome before. Thanks for your help! – Hanny Jun 28 '17 at 12:09

2 Answers2

2

Nope I think the best way is to use your sessions.

from django.contrib import messages << this is optional if you choose to use django messaging

Handle your form

def handle_form(request):
    ...
    request.session['form_message'] = "success or fail message here"

    redirect('/destination/', {})

def page_to_render_errors():
    ...
    message = None
    if( 'form_message' in request.session ):
        message = request.session['form_message']
        del request.session['form_message']
        messages.success(request, message ) #<< rememeber messages.success() along with messages.info() etc... are method calls if you choose to pass it through django's messaging

    return render(request,'template_name.html', {'message_disp':message })
Nimantha
  • 6,405
  • 6
  • 28
  • 69
A H Bensiali
  • 825
  • 1
  • 9
  • 22
1

You cannot view the error message, because it is not getting rendered, and hence there is nowhere for the message to go. The best way to do something like this would be to render an intermediate page, which would display the error message, and redirect after timeout, something of the sort used by payment gateways while redirecting you to your bank.

You can do something like this:

def trip_email(request):
    try:
        user_settings = Settings.objects.get(user_id=request.user.id)
    except Exception as e:
        return render(request, 'no_setting_error.html', {'form': form})

and on the no_setting_error html page, insert Javscript to automatically redirect you after a timeout like:

<script>
    function redirect(){
       window.location.href = "/user_settings";
    }

    setTimeout(redirect, 3000);
</script>

This will redirect you to from the error page to the user_settings page automatically after 3 seconds.

Nimantha
  • 6,405
  • 6
  • 28
  • 69
Rudresh Panchal
  • 980
  • 4
  • 16
  • While this could be a work-around, messages are stored in sessions and carried over. As long as the session is alive, it will be shown. As said, I'm doing exactly this with class-based views, which redirect to success_url. See the `ModelFeedbackMixin` in my answer [here](https://stackoverflow.com/a/44741540/1600649). The uppermost form_valid does `return HttpResponseRedirect(self.get_success_url())`. –  Jun 27 '17 at 17:15