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:
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">×</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 %}
« first
previous
{% endif %}
<span class="current mr-2">
Page {{ page_obj.number }} of {{ page_obj.paginator.num_pages }}
</span> {% if page_obj.has_next %}
next
last » {% 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.
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)
I created login\registration form for user. My problem is that when I login I get an error:
Page not found (404) Request Method: GET Request
URL: http://127.0.0.1:8000/accounts/profile/
If login is successful it should redirect me to "home.html". If I login I came to an error above and if I hit "Back" button in browser I am redirected on my "Home.html" and I am successfully logged in.
My other problem is that when I loggout I am redirected to DJANGO default logout page instead of mine "logged_out.html".
Views.py
#login_required
def home(request):
return render(request, 'home.html')
def signup(request):
if request.method == 'POST':
form = UserCreationForm(request.POST)
if form.is_valid():
form.save()
username = form.cleaned_data.get('username')
raw_password = form.cleaned_data.get('password1')
user = authenticate(username=username, password=raw_password)
login(request, user)
return redirect('home')
else:
form = UserCreationForm()
return render(request, 'signup.html', {'form': form})
Urls.py
urlpatterns = [
path('admin/', admin.site.urls),
url(r'^$', views.home, name='home'),
url(r'^login/$', auth_views.LoginView.as_view(), {'template_name': 'login.html'}, name='login'),
url(r'^logout/$', auth_views.LogoutView.as_view(), {'next_page': 'login'}, name='logout'),
url(r'^signup/$', views.signup, name='signup'),
]
login.html
{% extends 'base.html' %}
{% block content %}
<h2>Log in to My Site</h2>
{% if form.errors %}
<p style="color: red">Your username and password didn't match. Please try again.</p>
{% endif %}
<form method="post">
{% csrf_token %}
<input type="hidden" name="next" value="{{ next }}" />
{% for field in form %}
<p>
{{ field.label_tag }}<br>
{{ field }}<br>
{% for error in field.errors %}
<p style="color: red">{{ error }}</p>
{% endfor %}
{% if field.help_text %}
<p><small style="color: grey">{{ field.help_text }}</small></p>
{% endif %}
</p>
{% endfor %}
<button type="submit">Log in</button>
New to My Site? Sign up
</form>
{% endblock %}
logged_out.html
{% extends 'base.html' %}
{% block content %}
<h2>Why are You leaving :(</h2>
{% endblock %}
base.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>{% block title %}Simple is Better Than Complex{% endblock %}</title>
</head>
<body>
<header>
<h1>My Site</h1>
{% if user.is_authenticated %}
logout
{% else %}
login / signup
{% endif %}
<hr>
</header>
<main>
{% block content %}
{% endblock %}
</main>
</body>
</html>
home.html
{% extends 'base.html' %}
{% block content %}
<h2>Welcome, {{ user.username }}!</h2>
{% if request.user.is_staff %}
link to admin panel
<!--Admin-->
{% endif %}
{% endblock %}
LOGIN_REDIRECT_URL = '/'
you need to put this in your settings.py file as you are using django's inbuilt login system, Django always looks for a url 'profile'
I am using Django version 2.
I am working on a blog web app using PostgreSQL database.
I am trying to add a search feature to the web app but when I open the url (http://localhost:8000/search/) to make a search, I get the error below.
Page not found (404)
Request Method: GET
Request URL: http://localhost:8000/search/
Raised by: blog.views.post_detail
No Post matches the given query.
here is the blog/urls.py
from django.contrib.postgres.search import SearchVector
from .forms import CommentForm, SearchForm
from .models import Post, Comment
from django.shortcuts import render, get_object_or_404
from django.urls import path
from . import views
urlpatterns = [
path('', views.PostListView.as_view(), name='home'),
path('<slug:post>/', views.post_detail, name='post_detail'),
path('<int:post_id>/share', views.post_share, name='share'),
path('search/', views.post_search, name='post_search'),
]
here is the views.py
def post_detail(request, post):
post = get_object_or_404(Post, slug=post)
comments = post.comments.filter(active=True)
new_comment = None
if request.method == 'POST':
comment_form = CommentForm(data=request.POST)
if comment_form.is_valid():
new_comment = comment_form.save(commit=False)
new_comment.post = post
new_comment.save()
else:
comment_form = CommentForm()
return render(request, 'detail.html', {'post': post,
'comments': comments, 'new_comment':
new_comment,'comment_form': comment_form})
def post_search(request):
form = SearchForm()
query = None
results = []
if 'query' in request.GET:
form = SearchForm(request.GET)
if form.is_valid():
query = form.cleaned_data['query']
results = Post.objects.annotate(
search=SearchVector('title','body'),
).filter(search=query)
return render(request, 'search.html',
{'form':form,'query':query,'results':results})
Here are the templates files.
For search.html -(page to make query)
{% extends 'base.html' %}
{% block title %}Search{% endblock title %}
{% block page_title %}Search Posts{% endblock page_title %}
{% block content %}
{% if query %}
<h1>Posts containing "{{ query }}"</h1>
<h3>
{% with results.count as total_results %}
Found {{ total_results }} result{{ total_results|pluralize }}
{% endwith %}
</h3>
{% for post in results %}
<h4>{{ post.title }}</h4>
{{ post.body|truncatewords:5 }}
{% empty %}
<p>There is no results for your query.</p>
{% endfor %}
<p>Search again</p>
{% else %}
<h1>Search for posts</h1>
<form action="." method="GET">
{{ form.as_p }}
<input type="submit" value="Search">
</form>
{% endif %}
{% endblock content %}
For the html for post_detail
{% extends 'base.html' %}
{% load blog_tags %}
{% load crispy_forms_tags %}
{% load profanity %}
{% block title %}{{post.title}}{% endblock title %}
{% block navlink %}
<nav>
<ul>
<li class="current">Home</li>
<li>About</li>
<li >Services</li>
</ul>
</nav>
{% endblock navlink %}
{% block page_title %}{{post.title}}{% endblock page_title %}
{% block content %}
{{post.body|markdown}}
<p>Share this post via email</p>
{% with comments.count as total_comments %}
<h2>{{ total_comments }} comment{{ total_comments|pluralize }} </h2>
{% endwith %}
<div class="container">
{% for comment in comments %}
<div class="comment">
<p>Comment {{ forloop.counter }} by <em>{{ comment.name }}</em> - {{comment.created}} </p>
{{ comment.body|censor|linebreaks }}
</div>
{% empty %}
<p>There are no comments yet.</p>
{% endfor %}
{% if new_comment %}
<h2>Your comment has been added</h2>
{% else %}
<h2>Add a new comment</h2>
<form method="post">{% csrf_token %}
{{comment_form|crispy}}
<input class="button_1" type="submit" value="Add comment">
</form>
{% endif %}
</div>
{% endblock content %}
This is probably for one of the strange reason search is here actually matches with slug:post. One of easiest solution for your problem is to re-order urls and make sure /search place before. Like following
urlpatterns = [
path('', views.PostListView.as_view(), name='home'),
path('search/', views.post_search, name='post_search'),
path('<slug:post>/', views.post_detail, name='post_detail'),
path('<int:post_id>/share', views.post_share, name='share')
]
My suggestion for further developement whenever its need to add slug in url we need to make sure there is some prefix before it.
I have a CustomForm that extends from forms.ModelForm and use a FileField like this:
avatar = forms.FileField(required=False, label="avatar")
When I save the model, everything works, and file was saved in directory. But when I re-enter in view (file is over there), and just click in "Save", the file is lost. My views.py is:
def edit_user(request):
if request.method == "POST":
form = CustomForm(request.POST, request.FILES)
if form.is_valid():
user = form.save(commit=False)
user.save()
else:
user= User\
.objects\
.get_or_create(user=request.user,
defaults={'name':request.user.first_name,
'email':request.user.email})
form = CustomForm(instance=user)
return render(request, 'user.html', {'form':form, 'user':user})
I'm using Python 3.6 and Django 2.0.
HTML:
<form method="post" action="{% url 'myprofile' %}"
class="form-horizontal" role="form"
enctype="multipart/form-data">
{% csrf_token %}
{% for field in form %}
<div class="form-group row">
<label class="col-2 col-form-label">{{ field.label_tag }}</label>
<div class="col-10">
{% render_field field class+="form-control" %}
{% if field.errors %}
<br/>
{% for error in field.errors %}
<div class="alert alert-danger alert-dismissable">
<p><strong>{{ error|escape }}</strong></p>
</div>
{% endfor %}
{% endif %}
</div>
{% if field.help_text %}
<p class="help">{{ field.help_text|safe }}</p>
{% endif %}
</div>
{% endfor %}
<input type="submit" value="{% trans 'save' %}" >
</form>
I have spent a few days trying to find an answer to my issue. I have been reading and trying answers given to users with similar problems, but none of them worked.
I created a contact form and it works perfectly if I open the html where the code for the form is. But when I try to display it on index using the include tag, it shows the submit button, the structure and the style, but not the form fields.
This is what I have in my code:
views.py
from django.http import HttpResponse
from django.views import generic
from django.views.generic.edit import CreateView, UpdateView, DeleteView
from django.core.mail import send_mail
from .forms import ContactForm
from django.shortcuts import render
# Create your views here.
def index(request):
return render(request, 'landingpage/index.html', {})
#Contact form
def contact(request):
if request.method == 'POST':
form = ContactForm(request.POST)
if form.is_valid():
name = request.POST.get ('name')
email = request.POST.get ('email')
message = request.POST.get ('message')
send_mail('Subject here', content, contact_email, [‘xxx#gmail.com'], fail_silently=False)
return HttpResponseRedirect('/thanks/')
else:
form = ContactForm()
return render(request, 'landingpage/contact.html', {'form': form})
#Thank you message
def thanks (request):
return render(request, 'landingpage/thanks.html', {})
urls.py
app_name = 'landingpage'
urlpatterns = [
# Landingpage urls
url(r'^$', views.index, name='landing-index'),
url(r'^contact/$', views.contact, name='contact'),
url(r'^thanks/$', views.thanks, name='thanks'),
]
index.html
{% block form %}
{% include 'landingpage/contact.html' with form=form %}
{% endblock form %}
contact.html
{% block form %}
<section id="contact">
<div class="container">
<div class="row">
<div class="col-lg-12 text-center">
<h2 class="section-heading text-uppercase">Contact Us</h2>
</div>
</div>
<div class="row">
<div class="col-lg-12">
{% if form.errors %}
<p style="color: red;">
Please correct the error{{ form.errors|pluralize }} below.
</p>
{% endif %}
<form id="contactForm" name="sentMessage" action="" method="post" novalidate>
{% csrf_token %}
{% for hidden_field in form.hidden_fields %}
{{ hidden_field }}
{% endfor %}
{% if form.non_field_errors %}
<div class="alert alert-danger" role="alert">
{% for error in form.non_field_errors %}
{{ error }}
{% endfor %}
</div>
{% endif %}
{% for field in form.visible_fields %}
<div class="form-group">
{{ field.label_tag }}
{% if form.is_bound %}
{% if field.errors %}
{% render_field field class="form-control is-invalid" %}
{% for error in field.errors %}
<div class="invalid-feedback">
{{ error }}
</div>
{% endfor %}
{% else %}
{% render_field field class="form-control is-valid" %}
{% endif %}
{% else %}
{% render_field field class="form-control" %}
{% endif %}
{% if field.help_text %}
<small class="form-text text-muted">{{ field.help_text }}</small>
{% endif %}
</div>
{% endfor %}
<div class="clearfix"></div>
<div class="col-lg-12 text-center">
<div id="success"></div>
<button id="sendMessageButton" class="btn btn-primary btn-xl text-uppercase" type="submit">Send Message</button>
</div>
</div>
</form>
</div>
</div>
</div>
</section>
{% endblock form%}
This is because your index view does not have form variable in it`s context. You should write it like this:
def index(request):
ctx = {
'form': ContactForm()
}
return render(request, 'landingpage/index.html', ctx)