Django messages not showing up on redirects, only render

636 views Asked by At

For a couple days now, I've been trying to figure out why my messages don't show up on redirects. All of the dependencies are there in my settings.py file as you can see. I don't think that's the problem because I am getting two messages to show up on signup and login if the user's passwords don't match on signup or if the user enters the wrong password on login. I notice it only works on renders, but not on redirects. I'll post an image of my file structure and also the relevant files next.

File structure images:

image 1 book tree

image 2 members and main tree

settings.py

from django.contrib.messages import constants as messages

MESSAGE_TAGS = {
    messages.DEBUG: 'alert-info',
    messages.INFO: 'alert-info',
    messages.SUCCESS: 'alert-success',
    messages.WARNING: 'alert-warning',
    messages.ERROR: 'alert-danger',
}

INSTALLED_APPS = [
    ...
    'django.contrib.messages',
    ...
]

MIDDLEWARE = [
    ...
    'django.contrib.sessions.middleware.SessionMiddleware',
    ...
    'django.contrib.messages.middleware.MessageMiddleware',
    ...
]

TEMPLATES = [
   ...
            'context_processors': [
                ...
                'django.contrib.messages.context_processors.messages',
            ],
        },
    },
]

My urls.py in the main virtual_library folder

from django.contrib import admin
from django.urls import path, include
from django.conf import settings
from django.conf.urls.static import static
from book.views import *

urlpatterns = [
    path('admin/', admin.site.urls),
    
    # Book paths
    path('', include('book.urls')),

    # Added Django authentication system after adding members app
    path('members/', include('django.contrib.auth.urls')),
    path('members/', include('members.urls')),
]+ static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)

My urls.py in the book folder

from django.contrib import admin
from django.urls import path, include
from django.conf import settings
from django.conf.urls.static import static
from .views import *
from book import views

urlpatterns = [
    # Default path
    path('', views.home, name='home'),
    
    # Book paths
    path('create/', views.createbook, name='createbook'),
    path('current/', views.currentbooks, name='currentbooks'),
    path('wanttoread/', views.wanttoreadbooks, name='wanttoreadbooks'),
    path('currentlyreading/', views.currentlyreading, name='currentlyreading'),
    path('read/', views.read, name='read'),
    
    path('book/<int:book_pk>', views.viewbook, name='viewbook'),
    path('book/<int:book_pk>/editbook', views.editbook, name='editbook'),
    path('book/<int:book_pk>/viewonly', views.viewonly, name='viewonly'),
    path('book/<int:book_pk>/delete', views.deletebook, name='deletebook'),
    
    # Genres
    path('genre/', AddGenreView.as_view(), name='addgenre'),
]

My urls.py in the members folder


from django.contrib import admin
from django.urls import path
from django.conf import settings
from django.contrib.auth import views as auth_views
from django.conf.urls.static import static
from members import views
from . import views
from .views import UserEditView, CreateProfilePageView, ShowProfilePageView, EditProfilePageView, PasswordsChangeView

urlpatterns = [
    # User auth
    path('signupuser/', views.signupuser, name='signupuser'),
    path('loginuser/', views.loginuser, name='loginuser'),
    path('logoutuser/', views.logoutuser, name='logoutuser'),
    
    # User settings
    path('edit_settings/', UserEditView.as_view(), name='edit_settings'),
    # path('password/', auth_views.PasswordChangeView.as_view(template_name='registration/change_password.html')),
    path('password/', PasswordsChangeView.as_view(template_name='registration/change_password.html')),
    path('password_success/', views.password_success, name="password_success"),
        
     # User profile
    path('create_profile_page/', CreateProfilePageView.as_view(), name='create_profile_page'),
    path('<int:pk>/edit_profile_page/', EditProfilePageView.as_view(), name='edit_profile_page'),
    path('<int:pk>/profile/', ShowProfilePageView.as_view(), name='show_profile_page'),
]

base.html in the book folder

    <div class="container mt-5">
        {% for message in messages %}
        <div class="container-fluid p-0">
            <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>
        </div>
        {% endfor %} {% block content %}{% endblock %}
    </div>

my currentbooks.html template to view user's books in the book folder

{% extends "book/base.html" %} {% load static %} { % block title % } Your Books { % endblock % } {% block content %}
<div class="row justify-content-center mt-5">
    <div class="col-md-10">
        <h1>{% if book_list %} {{ book_list.count }} total book{{ book_list.count|pluralize }} in your Mibrary...</h1>
    </div>
</div>
<div class="row justify-content-center mt-5">
    <div class="col-md-10">
        {% if page_obj %}
        <div class="container mt-1">
            {% for book in page_obj %}
            <div class="card-body">
                {% if book.book_img %}
                <img src="{{ book.book_img.url }}" alt="{{ book.title }}" class="img-fluid" style="height:150px; width:100px"> {% else %}
                <img src="{% static 'book/images/logo.png' %}" alt="{{ book.title }}" class="img-fluid" style="height:150px; width:100px"> {% endif %}
                <blockquote class="blockquote mt-3">
                    <a href="{% url 'viewonly' book.id %}">
                              <strong><p class="mb-0">{{ book.title|capfirst }}</p></strong>
                          </a>
                    <p class="mb-0">{% if book.summary %}{{ book.summary|truncatechars:80|safe }}{% endif %}</p>
                </blockquote>
                <footer class="blockquote-footer">by <cite title="Source Title">{{ book.author }}</cite></footer>
                <small><p class="mb-0"><em>{{ book.user }}</em></p></small>
            </div>
            <hr> {% endfor %}
            <div class="pagination">
                <span class="step-links mr-2">
                        {% if page_obj.has_previous %}
                            <a href="?page=1">&laquo; first</a>
                            <a href="?page={{ page_obj.previous_page_number }}">previous</a>
                        {% endif %}
                
                        <span class="current mr-2">
                            Page {{ page_obj.number }} of {{ page_obj.paginator.num_pages }}
                        </span> {% if page_obj.has_next %}
                <a href="?page={{ page_obj.next_page_number }}">next</a>
                <a href="?page={{ page_obj.paginator.num_pages }}">last &raquo;</a> {% endif %}
                </span>
            </div>
        </div>
        {% endif %} {% else %}
        <div class="row">
            <div class="col mt-5">
                <a role="button" class="btn btn-outline-primary btn-lg" href="{% url 'createbook' %}">Add book</a>
            </div>
            <div class="col">
                <h2>You haven't added any books yet...</h2>
                <br>
                <img src="../static/book/images/reading-list.svg" class="img-fluid mt-3" style="width:400px;" alt="Responsive image" title="stack of books">
            </div>

        </div>

    </div>
{% endif %} {% endblock %}

views.py for currentbooks

from django.contrib import messages
...
@login_required
def currentbooks(request):
    book_list = Book.objects.filter(user=request.user)
    paginator = Paginator(book_list, 2)
    
    page_number = request.GET.get('page')
    page_obj = paginator.get_page(page_number)
    return render(request, 'book/currentbooks.html', {'page_obj': page_obj, 'book_list': book_list})

my createbook.html to add books in the book folder

{% extends 'book/base.html' %} {% block title %} Add Book{% endblock %} {% block content %}
<div class="container mt-5">
    <h1>Create Book...</h1>
</div>

<div class="form-group mt-3">
    <form method="POST" enctype="multipart/form-data">
        {% csrf_token %} {{ error }} {{ form.media }} {{ form.as_p }}
        <button type="submit" class="btn btn-primary">Save</button>
        <button type="button" class="btn btn-outline-warning" onclick="$('#cancel').click()">Cancel</button>
    </form>
    <form style='display: none;' method="POST" action="{% url 'currentbooks' %}">
        {% csrf_token %}
        <button id="cancel" type="submit">Cancel</button>
    </form>
    </form>
</div>

{% endblock %}

My editbook.html view to delete in the book folder

{% extends "book/base.html" %} {% block title %} Edit Book {% endblock %} {% block content %} {% if user.id == book.user_id %}
<div class="container mt-5">
    <h1>Edit Book...</h1>
    {% if error %}
    <div class="alert alert-danger" role="alert">
        {{ error }}
    </div>
    {% endif %}
</div>
<div class="form-group mt-3">
    <form method="POST" enctype="multipart/form-data">
        {% csrf_token %} {{ form.media }} {{ form.as_p }}
        <button type="submit" class="btn btn-primary">Save</button>
        <button type="button" class="btn btn-warning" onclick="$('#cancel').click()">Cancel</button>
        <button type="button" class="btn btn-danger" onclick="$('#delete').click()">Delete</button>
    </form>
    <form style='display: none;' method="POST" action="{% url 'deletebook' book.id %}">
        {% csrf_token %}
        <button id="delete" type="submit">Delete</button>
    </form>
    <form style='display: none;' method="POST" action="{% url 'currentbooks' %}">
        {% csrf_token %}
        <button id="cancel" type="submit">Cancel</button>
    </form>
</div>
{% else %}
<div class="row justify-content-center mt-5">
    <h1>You are not allowed to edit this book...</h1>
</div>
{% endif %} {% endblock %}

views.py in the book folder

from django.contrib import messages
...
# Create    
@login_required
def createbook(request):
    if request.method == 'GET':
        form = BookForm()
        return render(request, 'book/createbook.html', {'form': form})
    else:
        try:
            form = BookForm(request.POST, request.FILES)
            newbook = form.save(commit=False)
            newbook.user = request.user
            if form.is_valid():
                newbook.save()
                # This message does not show up under the redirect
                messages.success(request, 'Book saved!')
                return redirect('currentbooks')
        except ValueError:
            messages.error(request, 'Bad data passed in. Try again.')
            return render(request, 'book/createbook.html', {'form':BookForm()})

# Delete
@login_required
def deletebook(request, book_pk):
    book = get_object_or_404(Book, pk=book_pk, user=request.user)
    if request.method == 'POST':
        book.delete()
        # This message does not show up under redirect
        messages.info(request, 'Book deleted!')
        return redirect('currentbooks')
  

My loginuser.html to login in the members folder

{% extends 'book/base.html' %} {% block title %} Login {% endblock %} {% block content %}
<div class="container">
    <h1>User Login...</h1>
    <div class="row">
        <div class="col mt-5">
            <form method="POST">
                <div class="form-group">
                    {% csrf_token %} {{ error }}
                    <div class="form-group">
                        <label for="username">Username</label>
                        <input type="text" name="username" class="form-control" id="username" aria-describedby="usernameHelp">
                    </div>
                    <div class="form-group">
                        <label for="password">Password</label>
                        <input type="password" name="password" class="form-control" id="password">
                    </div>
                </div>
                <div class="form-group">
                    <button type="submit" class="btn btn-outline-danger btn-lg">Sign In</button>
                </div>
            </form>
        </div>
        <div class="col">
            <img src="../../static/book/images/studying.svg" class="img-fluid" alt="Responsive image" title="woman reading II">
        </div>
    </div>
</div>
{% endblock %}

views.py in the members folder

from django.shortcuts import render, redirect, get_object_or_404, HttpResponseRedirect
...
from django.contrib import messages
...
# Auth functions
def signupuser(request):
    if request.method == 'GET':
        return render(request, 'registration/signupuser.html', {'form':UserCreationForm()})
    else:
        if request.POST['password1'] == request.POST['password2']:
            try:
                user = User.objects.create_user(request.POST['username'], password=request.POST['password1'])
                user.save()
                login(request, user)
                # This message does not show in the redirect
                messages.success(request, 'User successfully created.')
                return redirect('currentbooks')
            except IntegrityError:
                return render(request, 'registration/signupuser.html', {'form':UserCreationForm()})
        else:
            # This message does show up under render
            messages.error(request, 'Passwords do not match.')
            return render(request, 'registration/signupuser.html', {'form':UserCreationForm()})

def loginuser(request):
    if request.method == 'GET':
        return render(request, 'registration/loginuser.html', {'form':AuthenticationForm()})
    else:
        user = authenticate(request, username=request.POST['username'], password=request.POST['password'])
        
        if user is None:
            messages.error(request, 'Username and password do not match.')
            # This message does show up under render
            return render(request, 'registration/loginuser.html', {'form':AuthenticationForm()})
        else:
            login(request, user)
            # This message does not show up under redirect
            messages.success(request, 'Logged in successfully.')
            return redirect('currentbooks')

@login_required
def logoutuser(request):
    if request.method == 'POST':
        logout(request)
        # This message does not show up. I tried HttpResponseRedirect as a last option.
        messages.success(request, 'Logged out successfully!')
        return HttpResponseRedirect(reverse_lazy('loginuser'))

So ultimately, the messages don't seem to work with redirects, but they do work if I render and declare the folder and template name. Otherwise, no message displays if there is a redirect. I'm not quite sure what is wrong or why redirects are not working with these messages.

1

There are 1 answers

1
Gin Fuyou On

Matt Gleason's answer is incorrect, because messages framework doesn't store it in request object: https://docs.djangoproject.com/en/3.2/ref/contrib/messages/#storage-backends Messages do work with redirects just fine out of the box. Check if everything is OK with your cookies (it's a default storage)