Problems with logging in/out standart django user using class-based views - python

I am trying to create simple application that allows just login existing user and logout if logged in.
views.py
from django.views.generic.edit import FormView
from django.views.generic import DetailView
from django.contrib.auth import logout
from django.contrib.auth.models import User
from django.contrib.auth.forms import AuthenticationForm
from django.core.urlresolvers import reverse_lazy
from django.http import HttpResponseRedirect
class UserDetailView( DetailView ):
model = User
template_name = "main/user_detail.html"
class UserLoginView( FormView ):
form_class = AuthenticationForm
success_url = reverse_lazy("UserDetails")
template_name = "main/user_form.html"
def logout_view(request):
logout(request)
return HttpResponseRedirect('/login/')
urls.py
from django.conf.urls import patterns, include, url
from main import views
urlpatterns = patterns('',),
url( r'users/(?P<pk>\d+)/', views.UserDetailView.as_view(), name="UserDetails"),
url( r"logout/", views.logout_view, name="UserLogOut" ),
url( r"login/", views.UserLoginView.as_view(), name="UserLogIn" ),
)
user_form.html
{% if user.is_authenticated %}
Logout
{{ user.username }}
{% else %}
<form method='post'> {% csrf_token %}
<table>
{{ form.as_table }}
</table>
<input type='submit' value='Submit'>
</form>
{% endif %}
I don't know why, but server returns this error
Request Method: POST
Request URL: http://0.0.0.0:9000/login/
Django Version: 1.6.5
Exception Type: NoReverseMatch
Exception Value:
Reverse for 'UserDetails' with arguments '()' and keyword arguments '{}' not found. 0 pattern(s) tried: []
What's wrong?
UPD
I've tried this dirty hack success_url = reverse_lazy("Main:UserDetails", kwargs={ 'pk':1 } ) just to check that it's working. I've also added
{% if user.is_authenticated %}
Hooray!
{% else %}
What the hell???
{% endif %}
to the user_detail.html and for some reason got What the hell??? instead of Hooray!
Why authentication form doesn't actually authenticates user?

I think the problem is in this statement
success_url = reverse_lazy("UserDetails")
You need to provide user pk to reverse_lazy args, because URL is in form "users/user_id/".
So it's impossible to find out correct success URL.

In this line in your urlconf
url( r'users/(?P<pk>\d+)/', views.UserDetailView.as_view(), name="UserDetails"),
you are defining the url for UserDetails as 'something/users/pk'. But then you are not supplying a pk argument to that url. That's why your error says that the reverse was not found, because it tries to find a pattern which has no arguments.
There are several ways to fix your error, but I think the best solution would be to make the pk argument optional, like this:
url( r'users(?:/(?P<pk>\d+))?/', views.UserDetailView.as_view(), name="UserDetails"),
Hope this helps.

Related

Why am I getting no reverse match error in django 3.2?

I am making a simple todo list application but while adding a delete button, I am receiving the error.
I tried many things searching on internet but couldn't solve the issue, probably because i am new to django.So, your help will be very important.
urls.py(of app):
from django.conf.urls import url
from django.urls import path
from . import views
urlpatterns=[
path('',views.home,name='home'),
url('delete/<str:id>', views.delete_data,name='deldata'),
]
views.py:
from django.shortcuts import get_object_or_404, render,redirect
from todo.models import value
from django.http import HttpResponseRedirect
# Create your views here.
from .forms import TitleForm
from django.urls import reverse
def home(request):
values=value.objects.all()
form=TitleForm
if request.method=='POST':
form=TitleForm(request.POST)
if form.is_valid():
form.save()
return redirect('/')
else:
form=TitleForm()
return render(request,'home.html',{'values':values,'form':form})
#delete
def delete_data(request, id ):
ggwp=value.objects.get(id=id)
if request.method=="POST":
ggwp=value.objects.get(id=id)
ggwp.delete()
return HttpResponseRedirect(reverse('deldata', kwargs={'id':id}))
context={'ggwp':ggwp}
return render(request,'/',context)
models.py:
from django.db import models
# Create your models here.
class value(models.Model):
task=models.CharField(max_length=200)
complete=models.BooleanField(default=False)
created=models.DateTimeField(auto_now_add=True)
def __str__(self):
return self.task
home.html(One and only html page):
<h3>TO DO LIST</h3>
<form method="POST" action="\">
{% csrf_token %}
{{form.task}} <input type='submit' name='add' value="add" >
</form>
{% for val in values %}
{{val}}
<form action="{% url 'deldata' val.id %}" method="POST" class="in-line">
{% csrf_token %}
<input type="submit" value="Delete" >
</form>
{% endfor %}
traceback:
raise NoReverseMatch(msg)
django.urls.exceptions.NoReverseMatch: Reverse for 'deldata' with arguments '(15,)' not
found. 1 pattern(s) tried: ['delete/<str:id>']
[05/Oct/2021 22:37:17] "GET / HTTP/1.1" 500 127858
Its my first question, so sorry if I have made any mistakes while writing the question.
You are using path(…) [Django-doc] syntax with the url(…) function [Django-doc]. You should work with a path(…) here:
urlpatterns=[
path('',views.home,name='home'),
# &downarrow; path, not url
path('delete/<str:id>/', views.delete_data,name='deldata'),
]
Normally paths also end with a slash, altough that is not required, it is common.
Note: As of django-3.1, url(…) [Django-doc] is
deprecated in favor of re_path(…) [Django-doc].
Furthermore a new syntax for paths has been introduced with path converters: you
use path(…) [Django-doc] for that.

Django-Python : invalid literal for int() with base 10: 'None'

I am new to Django. I am trying to build a page which displays all the users who have registered on to my Website.
The logic I tried to use is getting the id of a user in the built-in User Model.
In views.py, I have created a class based view which is a DetailView like this
from django.shortcuts import render
from django.contrib.auth.models import User
from django.views.generic import DetailView
#I have not used a ListView class but I have used a function based View
def home(request):
context = {
'users': User.objects.all(),
}
return render(request, 'home_page/home.html', context)
class UserDetailView(DetailView):
model = User
urls.py:
from django.urls import path
from .views import PostDetailView, UserDetailView
urlpatterns = [
path('', views.home, name='home_page'),
path('users/<pk>/', UserDetailView.as_view(), name='user-detail'),
]
In home.html, I have added this:
{% for user in users %}
<h2><a class="article-title" href="{% url 'user-detail' user.id %}">{{ user.username }}</a></h2>
{% endfor %}
When I clicked on the username it redirects me to localhost:8000/users/None/ and I get this error:
Exception Type: ValueError
Exception Value: invalid literal for int() with base 10: 'None'
Is this the right way to get the is of a user from the User Model?
change your urls.py
from django.urls import path
from .views import PostDetailView, UserDetailView
urlpatterns = [
path('', views.home, name='home_page'),
path('user/<int:pk>/', UserDetailView.as_view(), name='user-detail'),
]
The url waits for an integer, so we have to specify this in the url.
Your view to:
from django.views import View
from django.shortcuts import get_object_or_404
class UserDetailView(View):
def get(self, request, pk):
user = get_object_or_404(User, pk=pk)
return render(request, 'home_page/user_details.html', locals())
I personally don't like using context. I use locals() which passes the variables present in the method to the template.
Create a new html user_details.html file on home_page folder
and your template to:
<h2><a class="article-title" href="{% url 'user-detail' pk=user.pk %}">{{ user.username }}</a></h2>
{% for user in users %}
<h2><a class="article-title" href="{% url 'user-detail' user.id %}">{{ user.username }}</a></h2>
{% endfor %}
Its user, not users in the loop
If you do not have any User(s) yet, the QueryDict will have no elements (i.e. None) which is what I believe the error code is referring to. Once the User(s) have been created, the result should be an Integer (i.e. primary key to the User). In order to bypass this error, check whether the QueryDict has any elements before your for loop i.e.
{% if users %}
{% for user in users %}
<h2><a class="article-title" href="{% url 'user-detail' user.id %}">{{ user.username }}</a></h2>
{% endfor %}
{% else %}
<h2>There are no users loaded yet </h2>
{% endif %}

Django - Signup redirect to login page not working

My Signup view looks like below
from django.contrib.auth.forms import UserCreationForm
from django.views import generic
from django.urls import reverse_lazy
class SignUpView(generic.CreateView):
form_class = UserCreationForm
success_url = reverse_lazy('login')
template_name = 'signup.html'
My urls.py has below redirect rules
from django.urls import path
from .views import SignUpView
urlpatterns = [
path('signup/', SignUpView.as_view(), name='signup'),
]
My signup.html template looks like below
{% extends 'base.html' %}
{% block content %}
<h2>Sign Up</h2>
<form method="post">
{% csrf_token %}
{{ form.as_p }}
<button type="submit">Sign Up</button>
</form>
{% endblock content %}
I am trying to redirect to login page once signup completed. But its not working, and one more observation is I see the POST request status as 200, but if I go to login page, I am unable to login with those new credentials.
What error I am doing, any help appreciated.
Thank you.
I am using Django 2.1.5 with Python 3.7.4
you need to define the model in your createview as like:
class SignUpView(generic.CreateView):
model = user # your model name here
form_class = UserCreationForm
success_url = reverse_lazy('login')
template_name = 'signup.html'
from django.views.generic.edit import CreateView
class SignUpView(CreateView):
maybe you imported in wrong way
and you have to override form_valid() method
def form_valid(self, form):
valid = super(SignUpView, self).form_valid(form)
username, password = form.cleaned_data.get('username'), form.cleaned_data.get('password1')
new_user = authenticate(username=username, password=password)
login(self.request, new_user)
return valid

Django form submission & CSRF (403 Forbidden)

Upon providing valid data and submitting a form, I get the following: Forbidden (CSRF cookie not set.): /membership/success/. I have a {% csrf_token %} in my template and my settings.py middleware is configured for CSRF.
#urls.py
from django.contrib import admin
from django.urls import path, include
from membership import views as ms_views
membership_patterns = ([
path("", ms_views.RegistrationPage.as_view(), name="register"),
path("success/", ms_views.SuccessPage.as_view(), name="success")
], 'membership')
urlpatterns = [
path('admin/', admin.site.urls),
path('membership/', include(membership_patterns, namespace="new_members"))
]
# membership/views.py
from django.shortcuts import render
from django.template.loader import get_template
from django.views import View
from django.http import HttpResponse, HttpResponseRedirect
from membership.forms import RegisterForm
from django.urls import reverse
# Create your views here.
class RegistrationPage(View):
def get(self, request):
register_page = get_template('membership/signup.html')
register_form = RegisterForm()
return HttpResponse(register_page.render({'form' : register_form}))
def post(self, request):
submitted_form = RegisterForm(request.POST)
if submitted_form.is_valid():
return HttpResponseRedirect(reverse('membership:success'))
return HttpResponse(reverse('membership:register'))
class SuccessPage(View):
def get(self, request):
return HttpResponse("Success")
# signup.html
{% extends 'index.html' %}
{% block content %}
<form action="{% url 'membership:success' %}" method='post'>
{% csrf_token %}
{{ form.as_p }}
<button type="submit">Submit</button>
</form>
{% endblock %}
Once the form is submitted and valid, I'm expecting a 302 to occur. Like I said though I get 403 forbidden.
Since your success page has no logic, you can choose to exempt CSRF token for that.
Import the following module
from django.views.decorators.csrf import csrf_exempt
and put #csrf_exempt at the start of function
#csrf_exempt
def get(self, request):
return HttpResponse("Success")
Refer to https://docs.djangoproject.com/en/2.2/ref/csrf/
However, it is better to include {% csrf_token %} for each template you use to ensure consistent passing around of CSRF token

Django login app at suburl, url redirection does not work properly

I have my page deployed at http://example.com. I also have my django application deployed at http://example.com/djangoapp.
I'm using Apache 2.2 with this configuration (/etc/apache2/apache2.conf): WSGIPythonPath /home/brian/djangoprojects/djangoapp.
I also added the line WSGIScriptAlias /djangoapp /home/brian/djangoprojects/djangoapp/djangoapp/wsgi.py to the default Apache Virtual Host file and it works really nice.
However, in my application I'm using the auth module to register and login users, and have some problems with it. Sometimes I got redirected to the main page, http://example.com/, sometimes to http://example.com/register instead of http://example.com/djangoapp/register.
Changes I made in my project:
Edited settings.py and added:
LOGIN_URL = '/djangoapp/accounts/login/'
USE_X_FORWARDED_HOST = True
FORCE_SCRIPT_NAME = '/djangoapp'
SUB_SITE = "/djangoapp"
My urls.py file looks like this:
from django.conf.urls import include, url
from django.contrib import admin
from djangoapp import views
urlpatterns = [
url(r'^admin/', include(admin.site.urls)),
url(r'^$', 'django.contrib.auth.views.login'),
url(r'^logout/$', views.logout_page),
url(r'^accounts/login/$', 'django.contrib.auth.views.login'), # If user is not login it will redirect to login page
url(r'^register/$', views.register),
url(r'^register/success/$', views.register_success),
url(r'^home/$', views.home),
]
And here's my views.py file:
from django.contrib.auth.decorators import login_required
from django.contrib.auth import logout
from django.contrib.auth.models import User
from django.views.decorators.csrf import csrf_protect
from django.shortcuts import render_to_response
from django.http import HttpResponseRedirect
from django.template import RequestContext
from djangoapp.forms import RegistrationForm
#csrf_protect
def register(request):
if request.method == 'POST':
form = RegistrationForm(request.POST)
if form.is_valid():
user = User.objects.create_user(
username=form.cleaned_data['username'],
password=form.cleaned_data['password1'],
email=form.cleaned_data['email']
)
return HttpResponseRedirect('register/success/')
else:
form = RegistrationForm()
variables = RequestContext(request, {
'form': form
})
return render_to_response(
'registration/register.html',
variables,
)
def register_success(request):
return render_to_response(
'registration/success.html',
)
def logout_page(request):
logout(request)
return HttpResponseRedirect('/')
#login_required
def home(request):
return render_to_response(
'home.html',
{'user': request.user}
)
This is the production server and it's available online. I tried to use a work-around, but with no effect. I simply changed links on page and added djangoapp at the beginning, for instance:
{% extends "base.html" %}
{% block title %}Login{% endblock %}
{% block head %}Login{% endblock %}
{% block content %}
{% if form.errors %}
<p>Your username and password didn't match. Please try again.</p>
{% endif %}
<form method="post" action=".">{% csrf_token %}
<table border="0">
<tr><th><label for="id_username">Username:</label></th><td>{{ form.username }}</td></tr>
<tr><th><label for="id_password">Password:</label></th><td>{{ form.password }}</td></tr>
</table>
<input type="submit" value="Login" />
<input type="hidden" name="next" value="/home" />
</form>
Register
{% endblock %}
And I tried to change Register to Register but I'm sure there's got to be a smarter solution. Any advice?
You need to use the {% url %} tag and the reverse function consistently. So:
Register
and
return HttpResponseRedirect(reverse('register_success'))
For this to work you also need to give your URL patterns names:
url(r'^register/$', views.register, name="register"),
url(r'^register/success/$', views.register_success, name="register_success"),
Aso, as I said in the comment, you do not need to set FORCE_SCRIPT_NAME yourself.

Categories

Resources