Url not woking in django - django

My Question is in two fold, both revolving round NoReverseMatch error. First Question: I keep getting NoReverseMatch error each time i call my url({% url 'dashboard' client.pk %}) in other pages that uses a different view(eg DashboardPilot: kindly check the url) but when i use it in dashboard.html it works fine.
Views.py
class Dashboard(LoginRequiredMixin, UserPassesTestMixin, DetailView):
model = ClientProfile
template_name ='accounts/dashboard.html'
context_object_name= 'client'
login_url= 'login'
fields = '__all__'
def test_func(self):
return self.request.user.role == 'client'
urls.py
urlpatterns =[
path('accounts/dashboard/client/<int:pk>', Dashboard.as_view(), name='dashboard'),
path('accounts/dashboard/pilot/<int:pk>', DashboardPilot.as_view(), name='pilot_dashboard'),
path('jobs', JobPage.as_view(), name='job_page'),
path('job/<int:pk>/details', JobDetails.as_view(), name='job_details'),
path('accounts/edit/job/<int:pk>', EditJob.as_view(), name='job_edit'),
]
**models.py**
class ClientProfile(models.Model):
username = models.ForeignKey(User, on_delete= models.CASCADE)
client_firstname=models.CharField(max_length=200)
client_lastname=models.CharField(max_length =150)
role =models.CharField(max_length =150)
client_phone_no=models.CharField(max_length =150)
client_email=models.EmailField(max_length=150)
Second Questions:
I have a view which redirect to a dashboard(uses pk) after signing but i keep getting a reverse error each time it tries to redirect to dashboard.
views.py
def signin (request):
if request.method == 'POST':
username = request.POST['username']
password = request.POST['password']
user = auth.authenticate(username=username, password=password)
if user is not None:
auth.login(request,user)
messages.success(request, 'You are now logged in')
if user.role == 'client':
return redirect ('dashboard')
else:
return redirect ('pilot_dashboard')
else:
messages.error(request, 'Invalid Credentials')
return redirect ('login')
else:
return render (request, 'accounts/signin.html')
urls.py
urlpatterns =[
path('accounts/dashboard/client/<int:pk>', Dashboard.as_view(), name='dashboard'),
path('accounts/dashboard/pilot/<int:pk>', DashboardPilot.as_view(), name='pilot_dashboard'),
path('jobs', JobPage.as_view(), name='job_page'),
path('job/<int:pk>/details', JobDetails.as_view(), name='job_details'),
path('accounts/edit/job/<int:pk>', EditJob.as_view(), name='job_edit'),
]
I i have tried using return redirect(reverse('dashboard', args=[str(self.id)])) but i keep getting self not defined. I will be immensely grateful for any help rendered.

For the first problem, please make sure that client object is present in the template. Most probably, your template context does not have the object client which is why url is not resolved. You can test this by including {{ client }} in the templates that are giving you the error.
Basically you need to pass the correct object inside the url template tag.
You can add the client object in the context if your view does not have the ClientProfile in your template's context.
For the second problem, call the reverse with the kwargs keyword. Also, you are not passing the correct value to resolve the url.
Use:
return redirect(reverse('dashboard', kwargs={"pk": user.clientprofile.id}))

Related

Django Class Based View - Generic detail View must be called with object pk or a slug in URLconf

So I have a program that takes in the currently logged in user and updates their profile image.
Initially I had a function based view, and a url matching pattern (the url for accessing profile, and thereby editing it is localhost:8000/profile)
#views.py
#login_required
def profile(request):
if request.method=="POST":
u_form=UserUpdateForm(request.POST, instance=request.user)
p_form=ProfileUpdateForm(request.POST, request.FILES, instance=request.user.profile)
if u_form.is_valid() and p_form.is_valid():
u_form.save()
p_form.save()
messages.success(request, "Your account has been updated!")
return redirect('profile')
else:
u_form=UserUpdateForm(instance=request.user)
p_form=ProfileUpdateForm(instance=request.user.profile)
context={'u_form':u_form, 'p_form':p_form}
return render(request, 'users/profile.html', context)
#following line in URLpatterns of urls.py
path('profile/', user_views.ProfileUpdateView.as_view(), name='profile'),
It worked fine. However when I tried changing it to a class based view as below, it started giving errors
#views.py
class ProfileUpdateView(UpdateView):
model=Profile
fields=['image']
Case 1: I had this in urls.py URLpatterns
path('profile/', user_views.ProfileUpdateView.as_view(), name='profile'),
It gave an error -
(https://i.stack.imgur.com/6mXfI.png)](https://i.stack.imgur.com/6mXfI.png)
I don't understand why this error popped up because there is no page specific ID, like profile/1, profile/2 - just profile/ because the user is automatically identified by who is currently logged in hence no need to pass in a separate parameter in the url
Case 2: after I added in pk parameter
path('profile/<int:pk>/', user_views.ProfileUpdateView.as_view(), name='profile'),
This error pops up
(https://i.stack.imgur.com/Op9eQ.png)](https://i.stack.imgur.com/Op9eQ.png)
I have been stuck for a day now. I went through the Django documentation and MDN docs as well. Still can't figure out
As far as I can understand, the Profile is a model linked with the user.
If Profile is in OneToOneField with User, then in your class based view, ovverride the get_object method as:
def get_object(queryset=None,**kwargs):
return self.request.user.profile
If your Profile is linked with ForeignKey to User, then your get_object method will change to:
def get_object(queryset=None,**kwargs):
return Profile.objects.get(user=self.request.user)
In your class override get_object method as:
def get_object(self, **kwargs):
return Profile.objects.get(id=kwargs["int"])

Reset Password Form Page not found

I have built a custom password reset in Django, however, after putting the information in 'PasswordResetForm' I get a 404 page not found error.
This is my code for reset_password:
def reset_password(request,username):
if request.method == 'POST':
form = PasswordResetForm(data=request.POST, user=request.user)
if form.is_valid():
form.save()
update_session_auth_hash(request, form.user)
#added this to redirect user to custom url
username = request.user.username
return redirect(reverse('main:home', kwargs={'username': username}))
#return redirect(reverse('main:home'))
else:
return redirect(reverse('main:reset_password'))
else:
form = PasswordResetForm(user=request.user)
args = {'form': form}
return render(request, 'reset_password.html', args)
My urls at myapp/urls.py
urlpatterns=[
path('signup/',views.signup,name='signup'),
path('login',views.user_login,name='user_login'),
path('',views.main_page,name='main_page'),
path('<str:username>', views.home, name='home'),
#replace home/edit with below
path('<str:username>/edit', views.edit_profile, name='edit_profile'),
path('<str:username>/password-reset', views.reset_password, name='reset_password'),
]
and my form for password reset:
class PasswordResetForm(PasswordChangeForm):
class Meta:
model = Profile
fields = ('old_password','new_password1','new_password2')
What seems to be the problem here? I do not know why I am getting this error:
Page not found (404)
Request Method: GET
Request URL: http://127.0.0.1:8000/main/test3-b/login.html?next=/main/test3-b/password-reset
This is my AbstractUser model in models.py (I do not have any other code in my models.py
class Profile(AbstractUser):
bio = models.TextField()
university = models.CharField(max_length=30)
def __str__(self):
return self.username
Your urls.py is not using the same path as the URL you are accessing. The URL example you have given is http://127.0.0.1:8000/main/test3-b/login.html but your password reset url is something like http://127.0.0.1:8000/example-user/password-reset where example-user is the username that you are trying to match inside your path.
Out of interest do you have the URL structure include a username? This is normally not wanted as you would be using request.user to access the current user. You also have the risk a users username could break your patterns as you are using str rather than slug which is safer in URL patterns as otherwise id a user was created with the username of "example/edit" then they would never be able to get to your homepage as it would match the edit_profile entry instead.
I saw that by the form rendered in HTML it does not reset the admin user password, however the others works. In my case, I just extended the user class and inserted the email field.

Django Custom Login - Form is valid but no error

I'm currently trying to figure out how to customize the base Django user login functionality to add e.g. simple-captcha.
I have subclassed "AuthenticationForm" from django.contrib.auth.forms
which first looks great, but if I try to login I'm simply not able to.
I have already debugged the code and currently i only get:
response = wrapped_callback(request, *callback_args,
**callback_kwargs) TypeError: init() takes 1 positional argument but 2 were given
accounts/views.py:
...
login form of django.contrib.auth.forms subclassed (copied) to accounts/forms.py:
...
urls.py:
...
when I used vorujack's way made mistake,finally I found a solution
in url
from django.contrib.auth import views as auth_views
path('login/',auth_views.LoginView.as_view(form_class=forms.new_login_form,
template_name='login.html'), name='login'),
in forms
from django.contrib.auth.forms import AuthenticationForm
class new_login_form(AuthenticationForm):
captcha = CaptchaField(label='验证码', error_messages={"invalid": "验证码错误"})
class Meta:
model = User
fields = ('username', 'password',)
There are a few things wrong here.
The main one is that you've overridden the class init signature so that the first positional argument is request, but you pass the POST data in that position; therefore, the form will never be bound and never valid.
Secondly if the form is invalid you re-instantiate it for some reason, so the template will never show any validation errors. Unless you have a really good reason you should stick to the standard form handling structure shown in the docs.
Putting those together:
def login (request):
if request.method == 'POST':
form = LoginForm(request, data=request.POST)
if form.is_valid():
form.save()
messages.add_message(request, messages.INFO, "You are now logged-In, welcome")
return redirect(reverse('post_list'))
else:
form = LoginForm(request)
args = {'form': form}
return render(request, 'registration/login.html', args)
Note, you don't need the second else block; the single one here is aligned with the first if, and the final return is hit in both cases.
as Daniel said you update init method of form. so you must pass request as first argument.
second is when you validate user info you must authenticate user with authentication backend. but you saved form data.
if you only want to change authentication form you can use login view like this
see below:
urls.py
....
url(r'^accounts/login/$', auth.login, {'authentication_form': LoginForm}, name='login'),
....
if you use django2 and above you can change it like this. first of all create a class based view extended from django.contrib.auth.views.LoginView in this class set form_class to it like this.
from django.conrtib.auth.views import LoginView
...
class NewLoginView(LoginView):
form_class = LoginForm
then you must update your urls like this:
...
url(r'^accounts/login/$', NewLoginView.as_view, name='login'),
...
you must extend your form from django.contrib.auth.forms.AuthenticationForm or you must implement all needed function of this form class.
I finally found a solution, puuh :D
views.py:
...
from django.contrib.auth import update_session_auth_hash, authenticate, login as customlogin
...
def login(request):
if request.method == 'POST':
form = LoginForm(request.POST, request.POST)
if form.is_valid():
username = request.POST['username']
password = request.POST['password']
user = authenticate(request, username=username, password=password)
if user is not None:
customlogin(request, user)
# Redirect to a success page.
return redirect(reverse('post_list'))
return render(request, 'registration/login.html', {'form': form})
else:
return render(request, 'registration/login.html', {'form': LoginForm()})
simply extend the form (Thanks to vorujack)
...
from django.contrib.auth.forms import AuthenticationForm
...
class LoginForm (AuthenticationForm):
captcha = CaptchaField()
urls.py:
url(r'^accounts/login/$', views_accounts.login, name='login'),
the really stupid part is at the login function "form = LoginForm(request.POST, request.POST)"
You really need to pass this for the password and user and beside that and secondary request.POST for the captcha form... Oookay. Anyways, now it works.
Thanks anybody for your help, i really appreciate this community

python - Django redirect to next after login (Generic Form View)

I am using generic form view for authentication, I am getting next parameter in url but unfortunately I don't know how to redirect it to next, after successful login for Generic Form View, here is my view
class LoginView(
views.AnonymousRequiredMixin,
generic.FormView):
form_class = LoginForm
success_url = reverse_lazy('home')
template_name = 'accounts/registered/login.html'
def form_valid(self, form):
username = form.cleaned_data['username']
password = form.cleaned_data['password']
user = authenticate(username=username, password=password)
if user is not None and user.is_active and user.is_seller:
login(self.request, user)
return super(LoginView, self).form_valid(form)
else:
return self.form_invalid(form)
I am getting this
http://127.0.0.1:8000/accounts/login/?next=/accounts/dashboard/
help me out!
So essentially, what the url that you are getting means is that it's trying to go to 127.0.0.1:8000/accounts/dashboard/, but because the user needs to be logged in, it's going to the login page first. Essentially, this means that your view is not logging the user in for some reason.
Try using (or extending) Django's built in LoginForm class (https://docs.djangoproject.com/en/2.0/topics/auth/default/#django.contrib.auth.views.LoginView)
Alternatively, go with a broader solution suite, such as django allauth (https://github.com/pennersr/django-allauth/blob/master/docs/index.rst)
You should use HttpRedirectResponse:
views.py
from django.http import HttpResponseRedirect
def login(request):
# You logic goes here
return HttpResponseRedirect('dashboard')
def dashboard(request):
context = {
# User information goes here
}
return render(request, 'dashboard', context)
Do not forget to add this call to the login method in your urls.py:
path('login', views.login, name='login'),
path('dashboard', views.dashboard, name='dashboard'),
You should also take a look at https://docs.djangoproject.com/en/2.0/ref/request-response/ for a better understanding of how request and response work.
You should also be familiar with https://docs.djangoproject.com/en/2.0/intro/tutorial04/ so that you could understand an example of HttpResponseRedirect.

using django-email-as-username how can I return with a message to the user?

I am trying to use django-email-as-username and I can't find a way to return to the login page with a message for the user in case the data provided by the user is wrong.
this my urls.py
url(r'^login$', 'django.contrib.auth.views.login', {'authentication_form': EmailAuthenticationForm}, name='login'),
this is my views.py
def login_user(request):
if request.method == 'POST':
email = request.POST.get('email')
password = request.POST.get('password')
if email and password:
user = authenticate(email=email, password=password)
if user:
return HttpResponseRedirect('/')
else:
message = 'No such user'
else:
message = 'both email and password are required!'
else:
message = 'wrong method!'
I think you've made an error in that you're providing your own login_user view in your views.py module, but linking to Django's django.contrib.auth.views.login in your URL conf.
You should probably just use django.contrib.auth.views.login as the login view.
You'll also need to provide a registration/login.html template. You'll be able to get at the error information, as the form is passed through to the context. You can use the admin's login template as an example.
In case of authentication failure, you have to render/redirect your own login page with {{ message }}