I am new to Django and I am creating a user change password page. However, I keep encountering a NoReverseMatch error which I suspect is due to my app name but I am not able to resolve it even after spending hours googling for a solution.
My urls.py file:
from os import name
from django.urls import path
from account import views
from django.contrib.auth import views as auth_views # Import Django built-in authentication views
app_name = 'account'
urlpatterns = [
path('test/', views.test_login, name='test'),
path('login/', auth_views.LoginView.as_view(), name='login'),
path('logout/', auth_views.LogoutView.as_view(), name='logout'),
path('password_change/done/', auth_views.PasswordChangeDoneView.as_view(), name='password_change_done'),
path('password_change/', auth_views.PasswordChangeView.as_view(), name='password_change'),
]
My settings.py:
# Login Logic
LOGIN_REDIRECT_URL = 'account:test' # Tells Django which URL to redirect user to after a successful login if no next parameter is present in the request
LOGIN_URL = 'account:login' # The URL to redirect the user to log in - based on the name in the urls.py
LOGOUT_URL = 'account:logout' # The URL to redirect the user to log out - based on the name in the urls.py
my html file
{% extends "base.html" %}
{# This is the template to allow user to change their password #}
{% block title %}Change Your Password{% endblock title %}
{% block content %}
<div class="container">
<div class="row justify-content-center">
<div class="col-8">
<form action="{% url 'account:password_change_done' %}" class="form-signin" method="post">
{% csrf_token %}
<h1 class="h3 mb-3 font-weight-normal text-center">Change your password</h1>
<div class="form-group">
<label for="old_password">Old Password</label>
<input class="form-control" type="password" required id="id_old_password" name="old_password" autocomplete="current-password" placeholder="Old Password" autofocus>
</div>
<div class="form-group">
<label for="new_password1">New Password</label>
<input class="form-control" type="password" required id="id_new_password1" name="new_password1" autocomplete="new-password" placeholder="New Password">
</div>
<div class="form-group">
<label for="new_password2">Confirm Password</label>
<input class="form-control" type="password" required id="id_new_password2" name="new_password2" autocomplete="new-password" placeholder="Confirm Password">
</div>
<small class="form-text text-muted">
{% if form.new_password1.help_text %}
{{ form.new_password1.help_text|safe }}
{% endif %}
</small>
<button type="submit" class="btn btn-primary">Submit</button>
</form>
{% if form.errors %}
{% for field in form %}
{% for error in field.errors %}
<div class="alert alert-danger">
<strong>{{ error|escape }}</strong>
</div>
{% endfor %}
{% endfor %}
{% for error in form.non_field_errors %}
<div class="alert alert-danger">
<strong>{{ error|escape }}</strong>
</div>
{% endfor %}
{% endif %}
</div>
</div>
</div>
{% endblock content %}
Much help is appreciated.
Have added in the html file for referece
A "NoReverseMatch" error means , Django is not being able to process and see the exact url being passed.
Including the "app_name" has said by most Django devs makes the code neat and easy to streamline to as to which url you want and most importantly helps to avoid duplicating urls..
An instance will be having this url path of "home" in your app accounts and also having that same path "home" in some other app, the use of specifying the app_name will help Django , include the urls to their respective apps so you know which requires which .
Your urls are correct to me and since it's a NoReverseMatch error, it will have to be your at your html or view or anywhere where you are calling a url.
Try including the app name in either your html and view on where you are calling the url..
Something like this
{% app_name:name_url %}
And same to the view app_name:name_url
Always make sure there is semi-colon between the app_name and the url ... As it will help you tell Django as to which url from which app!!
Related
I am trying to use Django provided forms instead of manually creating them with HTML. When I do this, however, they do not appear. The questions/answers I have found on this site have so far been unable to solve my issue. (unless I am reading them wrong.)
forms.py
from django import forms
class KeywordForm(forms.Form):
input_keywords = forms.CharField(label="Keywords", max_length='100')
class LocationForm(forms.Form):
input_location = forms.CharField(label="Location", max_length="250")
views.py
from django.shortcuts import render
from .forms import KeywordForm, LocationForm
def search_view(request):
keyword_form = KeywordForm()
location_form = LocationForm()
return render(request, 'search_results.html', {'keyword_form': keyword_form, 'location_form': location_form})
urls.py
from django.urls import path
from . import views
urlpatterns = [
...
path('search/', views.search_view, name='search'),
]
base.html
{% block search %}
<div class="card">
<div class="card-body">
<form class="row align-items-center">
<form action="search" method="GET">
<div class="col-sm-2">
{{ keyword_form }}
</div>
<div class="col-sm-2">
{{ location_form }}
</div>
<!-- <label for="inputKeywords" class="form-label">Keywords</label>-->
<!-- <input class="form-control" id="inputKeywords" type="text" name="inputKeywords" placeholder="Enter Keywords...">-->
<!-- </div>-->
<!-- <div class="col-sm-2">-->
<!-- <label for="inputLocation" class="form-label">Location</label>-->
<!-- <input type="Text" class="form-control" id="inputLocation" name="inputLocation" placeholder="Enter location...">-->
<!-- </div>-->
<div class="col">
<input class="btn btn-primary" type="submit" value="Search">
</div>
</form>
</form>
</div>
</div>
{% endblock %}
Per request: search_results.html, which isn't finished due to the forms not showing up in base.html.
{% extends 'base.html' %}
{% block search %}
<nav class="navbar navbar-expand-lg navbar-light bg-light">
<div class="navbar-nav">
<form action="search" method="GET">
{{ keyword_form }}
{{ location_form }}
<input class="btn btn-primary" type="submit" value="Search">
</form>
</div>
</nav>
{% endblock %}
In base.html replace this:
{% block search %}
<div class="card">
<div class="card-body">
<form class="row align-items-center">
<form action="search" method="GET">
<div class="col-sm-2">
{{ keyword_form }}
</div>
<div class="col-sm-2">
{{ location_form }}
</div>
<div class="col">
<input class="btn btn-primary" type="submit" value="Search">
</div>
</form>
</form>
</div>
</div>
{% endblock %}
with this:
{% block search %}
{% endblock search %}
Let me see if i can explain clearly what's happening here..
You created a view for search_results.html so when you render that page the view passes the context variable to it, which includes the forms. All good 'till here.
From the code you shared i see that then you went ahead and added the Django Template Language to render those forms directly in base.html. But that won't work because base.html doesn't have access to the context variable you're passing to search_results.html.
When you extend a template and you add content within blocks that are present in the parent template, what happens is that the block in question is overwritten.
So in your case, whatever you're writing between search blocks in base.html will be wholly overwritten by what's in between those same blocks in search_results.html.
From what i see there are no errors in the code so I think all you have to do is to work on your search_results.html template. And when you test if it works or not do so on search_results.html, not anywhere else, because that's the template that will have access to the context dictionary.
The problem might also be that for some reason those form elements are empty, or that something is wrong at some other step of the way. The template doesn't mind being passed empty context variables so you should also consider that maybe the forms are being passed to the template but they're just empty. You have to run little tests for these things. Try passing a variable containing a simple string to the template and try to render that. Does it work? Good, at least you know that the problem is somewhere else. Doesn't it? Even better, you're one step closer to the solution.
I'm trying to get into Django and got stuck with DeatailView and RedirectView
I made the following template for rendering posts with enabling post detailed view and like button. When I click on either Like or Detail button none of the requests is sent. I tried changing different methods, but that didn't help either. I trying to get whether I was mistaken in the template or in view logic.
{% extends 'base.html' %}
{% block content %}
{% for post in object_list %}
<div class="card" style="width: 40rem;">
<img src = "{{ post.image.url }}" style="height: 40rem;">
<div class="card-body">
<h5 class="card-tittle">{{post.author.username}}</h5>
<p class="card-text">{{ post.description }}</p>
<p class="card-text">Likes : {{ post.likes.count }}</p>
<p class="id">Post_id: {{ post.id }}</p>
<div class="btn-group-vertical">
{% if user.is_authenticated %}
<form action="{% url 'like_post' %}" method="POST">
{% csrf_token %}
<button type="button" class="btn btn-secondary">Like</button>
</form>
{% endif %}
<form action="{% url 'detail' pk=post.id %}" method="GET">
<button type="button" class="btn btn-secondary">Detail</button>
</form>
<!-- <button type="button" class="btn btn-secondary">down</button> -->
</div>
</div>
</div>
{% endfor %}
{% endblock %}
Posts views.py file
class PostDetail(DetailView):
model = Post
def get_context_data(self, *args, **kwargs):
context = super().get_context_data(*args, **kwargs)
print(context.items())
return context
class PostLikeUpvote(RedirectView):
def get_redirect_url(self, *args, **kwargs):
post_id = kwargs.get('id')
post = get_object_or_404(Post, id=post_id)
user = self.request.user
if user.is_authenticated():
post.likes.add(user)
url_redirect = post.get_redirect_url()
return url_redirect
urls.py
urlpatterns = [
path('admin/', admin.site.urls),
path('accounts/', include('accounts.urls')),
path('new/', PostCreate.as_view(), name='new'),
path('', PostList.as_view(), name='list'),
path('posts/', PostList.as_view(), name='list'),
path('like_post/', PostLikeUpvote.as_view(), name='like_post'),
path('posts/<pk>/', PostDetail.as_view(), name='detail'),
path('bot/webhook', csrf_exempt(BotView.as_view())),
]
Any comments are appreciated.
In order to submit the form, the type of the button should be submit, not button:
{% if user.is_authenticated %}
<form action="{% url 'like_post' %}" method="POST">
{% csrf_token %}
<button type="submit" class="btn btn-secondary">Like</button>
</form>
{% endif %}
otherwise it is a simple button that can for example run a JavaScript function, but it will not (automatically) submit the form. Of course you can write a JavaScript function to submit the form, but unless you have a specific reason for that, it is better to let the browser do the work for you.
I don't know what's happening with my code, once a user that is not authenticated tries to access a page and it redirects to the login page, I can see the next parameter in the browser but after the user logins, it takes the user to the default LOGIN_REDIRECT_URL and not the next page. Also on the template next returns none, so seems the template is not getting thee next value, but in the url it shows the /?next=, thanks in advance.
urls.py
from django.contrib import admin
from django.urls import path, include
from django.contrib.auth import views as auth_views
from blog import views
urlpatterns = [
path('admin/', admin.site.urls),
path('', views.HomeView.as_view(),name="index"),
path('accounts/login/', auth_views.LoginView.as_view(), name='login'),
path('accounts/logout/', auth_views.LogoutView.as_view(next_page='/'), name='logout'),
path('accounts/profile/', views.ProfileView.as_view(), name='profile'),
]
registration/login.html
{% extends 'app/base.html' %}
{% block link %} id="active" {%endblock%}
{% block content %}
<div class="row">
<div class="col-md-3">
</div>
<div class="col-md-6">
<div class="jumbotron" id="font">
{% if next %}
{% if user.is_authenticated %}
<h2 class="customtext" align="center">Your account doesn't have access to this page. To proceed,
please login with an account that has access.</h2>
{% else %}
<h2 class="customtext" align="center">Please login.</h2>
{% endif %}
{% else %}
<h2 class="customtext" align="center">Enter your login details.</h2>
{% endif %}
<form action="{% url 'login' %}" method="POST">
{%csrf_token%}
<div class="form-group">
<input type="text" name="username" placeholder="username" class="form-control">
</div>
<div class="form-group">
<input type="password" name="password" placeholder="password" class="form-control">
</div>
<!-- <div align="center"> -->
{% if form.errors %}
<!-- <p style="color: red; font-style: italic;">Your username or email is does not match.</p> -->
{{form.errors}}
{% endif %}
<!-- </div> -->
<div class="loginbtndiv" align="center">
<input type="submit" class="btn btn-warning btn-lg loginbtn" value="LOGIN">
</div>
<input type="hidden" name="next" value="{{ next }}">
</form>
</div>
</div>
<div>
</div>
</div>
{% endblock %}
I am making an app in django in which i have used the django built in authentication system. Both login and logout links are present in the navbar. I want to make the logout link appear only when the user has logged in and not at all times. How do i do that?
code snippet of project/urls.py:
urlpatterns = [
url(r'^login/$', views.login, {'template_name': 'login.html', 'authentication_form': LoginForm}, name='login'),
url(r'^logout/$', views.logout, {'next_page': '/home'}), ]
code snippet of login.html;
<div class="container">
<section id="content">
{% if form.errors %}
<p>Your username and password didn't match. Please try again.</p>
{% endif %}
{% if next %}
{% if user.is_authenticated %}
<p>Your account doesn't have access to this page. To proceed,
please login with an account that has access.</p>
{% else %}
<p>Please login to see this page.</p>
{% endif %}
{% endif %}
<form action="{% url 'login' %}" method="post" enctype="multipart/form-data">
{% csrf_token %}
<h1>Login Form</h1>
<div class="imgcontainer">
<img src="{% static 'student/patient.jpg' %}" alt="Avatar" class="avatar">
</div>
<div class="username">
{{ form.username.label_tag }}
{{ form.username }}
</div>
<div class="password">
{{ form.password.label_tag }}
{{ form.password }}
</div>
<div class="submitb">
<input type="submit" value="Log In" name="mybtn">
</div>
<div class="resetb">
<input type="submit" value="Reset">
Forgot password?
</div>
<input type="hidden" name="next" value="{{ next }}" />
</form>
code snippet of base.html(only the navbar is shown):
<ul>
<li><a class="active" href="/home">Home</a></li>
<li>About </li>
<li>Sign up</li>
<li>Doctor's login</li>
<li>Patient's login</li>
<li>FAQs</li>
<li>Contact us</li>
<li>Reviews</li>
<li>Logout</li>
</ul>
Thanks for your help in advance.
Put the logout list item in an if block that checks that the user is authenticated like so:
<ul>
...
{% if request.user.is_authenticated %}
<li>Logout</li>
{% endif %}
</ul>
Although using the variable request.user.is_authenticated is one way. To make it simpler create HTML pages such that login and logout button are disintegrated.
Pages which appear after login should only contain the logout option/button. This will smoothen your development process.
This question already has answers here:
What is a NoReverseMatch error, and how do I fix it?
(6 answers)
Closed 6 years ago.
I am new to python & Django. I am getting one error and have absolutely no idea how to solve it.
Any help will be appreciated.
from django.shortcuts import render
# Create your views here.
#log/views.py
from django.shortcuts import render
from django.contrib.auth.decorators import login_required
# Create your views here.
# this login required decorator is to not allow to any
# view without authenticating
#login_required(login_url="login/")
def home(request):
return render(request,"home.html")
The code in urls.py is,
from django.conf.urls import include,url
from django.contrib import admin
from django.contrib.auth import views as auth_views
from log.forms import LoginForm
urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'', include('log.urls')),
url(r'^login/$', auth_views.login ,{'template_name': 'login.html','authentication_form': LoginForm}),
url(r'^logout/$', auth_views.logout, {'next_page': '/login'}),
]
The code in login.html is,
{% extends 'base.html' %}
{% block content %}
{% if form.errors %}
<p>Your username and password didn't match. Please try again.</p>
{% endif %}
{% if next %}
{% if user.is_authenticated %}
<p>Your account doesn't have access to this page. To proceed,
please login with an account that has access.</p>
{% else %}
<p>Please login to see this page.</p>
{% endif %}
{% endif %}
<div class="container">
<div class="row">
<div class="col-md-4 col-md-offset-4">
<div class="login-panel panel panel-default">
<div class="panel-heading">
<h3 class="panel-title">Please Sign In</h3>
</div>
<div class="panel-body">
<form method="post" action="{% url 'django.contrib.auth.views.login' %}">
{% csrf_token %}
<p class="bs-component">
<table>
<tr>
<td>{{ form.username.label_tag }}</td>
<td>{{ form.username }}</td>
</tr>
<tr>
<td>{{ form.password.label_tag }}</td>
<td>{{ form.password }}</td>
</tr>
</table>
</p>
<p class="bs-component">
<center>
<input class="btn btn-success btn-sm" type="submit" value="login" />
</center>
</p>
<input type="hidden" name="next" value="{{ next }}" />
</form>
</div>
</div>
</div>
</div>
</div>
{% endblock %}
{% block javascript %}
<script>
{% if not user.is_authenticated %}
$("ul.nav.navbar-nav.navbar-right").css("display","none");
{% endif %}
</script>
{% endblock %}
Hope this much info will do....
Add a name to the login url pattern:
kwargs = {'template_name': 'login.html','authentication_form': LoginForm}
...
url(r'^login/$', auth_views.login, kwargs=kwargs, name='login'),
# ^^^^
and then use that name in your template:
<form method="post" action="{% url 'login' %}">