Django rest_framework forgot password - python

I'm newbie in Django
I have a trouble with this:
I've already make API for 'request-reset-email', 'password-reset' and 'password-reset-complete'
Here are the code:
file: urls.py
from django.urls import path
from .views import *
from django.contrib.auth import views as auth_view
from rest_framework_simplejwt.views import (
TokenObtainSlidingView,
TokenRefreshSlidingView,
)
urlpatterns=[
path('register/', RegisterView.as_view(), name="register"),
path('login/', LoginAPIView.as_view(), name="login"),
path('email-verify/', VerifyEmail.as_view(), name="email-verify"),
path('token/refresh/', TokenRefreshSlidingView.as_view(), name='token_refresh'),
path('request-reset-email/',RequestPasswordResetEmail.as_view(), name='request-reset-email'),
path('password-reset/<uidb64>/<token>/',PasswordTokenCheckAPIView.as_view(),name='password-reset'),
path('password-reset-complete/',SetNewPasswordAPIView.as_view(),name='password-reset-complete')
]
file Views.py:
from django.shortcuts import render
from rest_framework import exceptions, generics, serializers
from rest_framework.response import Response
from rest_framework import status
from .models import *
from .serializers import *
from rest_framework_simplejwt.tokens import RefreshToken
from .utils import *
from django.contrib.sites.shortcuts import get_current_site
from django.urls import reverse
import jwt
from django.conf import settings
from django.contrib.auth.tokens import PasswordResetTokenGenerator
from django.utils.encoding import smart_str, force_str, smart_bytes, DjangoUnicodeDecodeError
from django.utils.http import urlsafe_base64_decode, urlsafe_base64_encode
# Create your views here.
class RegisterView(generics.GenericAPIView):
queryset = User.objects.all()
serializer_class=RegisterSerializer
def post(self, request):
user = request.data
serializer = self.serializer_class(data=user)
serializer.is_valid(raise_exception=True)
serializer.save()
user_data = serializer.data
user= User.objects.get(email=user_data['email'])
token=RefreshToken.for_user(user).access_token
current_site=get_current_site(request).domain
realtivelink = reverse('email-verify')
absurl='http://'+current_site+realtivelink+"?token="+ str(token)
email_body='Hi '+ user.email+ ' Use link below to verify your email \n' + absurl
data={'email_body':email_body,'to_email':user.email,'email_subject':'Verify your email'}
Util.send_email(data)
return Response(user_data,status= status.HTTP_201_CREATED)
class VerifyEmail(generics.GenericAPIView):
def get(self,request):
token= request.GET.get('token')
try:
payload=jwt.decode(token,settings.SECRET_KEY,algorithms='HS256')
user=User.objects.get(id=payload['user_id'])
if not user.is_verified:
user.is_verified=True
user.save()
return Response({'email':'Successfully activated'},status= status.HTTP_200_OK)
except jwt.ExpiredSignatureError as indentifier:
return Response({'email':'Activation expired'},status= status.HTTP_400_BAD_REQUEST)
except jwt.exceptions.DecodeError as indentifier:
return Response({'email':'Invalid token'},status= status.HTTP_400_BAD_REQUEST)
class LoginAPIView(generics.GenericAPIView):
queryset = User.objects.all()
serializer_class = LoginSerializers
def post(self, request):
serializer = self.serializer_class(data=request.data)
serializer.is_valid(raise_exception=True)
return Response(serializer.data,status=status.HTTP_200_OK )
class RequestPasswordResetEmail(generics.GenericAPIView):
queryset = User.objects.all()
serializer_class=ResetPasswordViaEmailSerializer
def post(self, request):
serializer = self.serializer_class(data=request.data)
email = request.data['email']
if User.objects.filter(email=email).exists():
user = User.objects.get(email=email)
uidb64 = urlsafe_base64_encode(smart_bytes(user.id) )
token = PasswordResetTokenGenerator().make_token(user)
current_site=get_current_site(request=request).domain
realtivelink = reverse('password-reset',kwargs={'uidb64':uidb64,'token':token})
absurl='http://'+current_site+realtivelink
email_body='Hi, \nUse link below to reset your password \n' + absurl
data={'email_body':email_body,'to_email':user.email,'email_subject':'Reset your password'}
Util.send_email(data)
return Response({'successfully':'check your email to reset your password'},status=status.HTTP_200_OK)
class PasswordTokenCheckAPIView(generics.GenericAPIView):
def get(self, request, uidb64,token):
try:
id= smart_str(urlsafe_base64_decode(uidb64))
user= User.objects.get(id=id)
if not PasswordResetTokenGenerator().check_token(user,token):
return Response({'error':'token is not valid, please check the new one'},status=status.HTTP_401_UNAUTHORIZED)
return Response({'sucess':True, 'message':'Credential Valid','uidb64':uidb64, 'token':token},status=status.HTTP_200_OK)
except DjangoUnicodeDecodeError as indentifier:
return Response({'error':'token is not valid, please check the new one'},status=status.HTTP_401_UNAUTHORIZED)
class SetNewPasswordAPIView(generics.GenericAPIView):
queryset = User.objects.all()
serializer_class=ResetPassWordSerializer
def patch(self, request):
serializer=self.serializer_class(data=request.data)
serializer.is_valid(raise_exception=True)
return Response({'sucess':True, 'message':'Password is reset successfully'},status=status.HTTP_200_OK)
APIs've already worked. But I want to make the "PasswordTokenCheckAPIView" have a templete for user to enter the new password and confirm it. So, could you please to give me some way to do this? I've tried to use django.contrib.auth.PasswordResetConfirmView, it appears the template when I click the link I received in mail, but when I confirm change password, there is error
from django.urls import path
from .views import *
from django.contrib.auth import views as auth_view
from rest_framework_simplejwt.views import (
TokenObtainSlidingView,
TokenRefreshSlidingView,
)
urlpatterns=[
path('register/', RegisterView.as_view(), name="register"),
path('login/', LoginAPIView.as_view(), name="login"),
path('email-verify/', VerifyEmail.as_view(), name="email-verify"),
path('token/refresh/', TokenRefreshSlidingView.as_view(), name='token_refresh'),
path('request-reset-email/',RequestPasswordResetEmail.as_view(), name='request-reset-email'),
path('password-reset/<uidb64>/<token>/',auth_view.PasswordResetConfirmView.as_view(),name='password-reset'),
path('password_reset_complete/',auth_view.PasswordResetCompleteView.as_view(),name='password-reset-complete')
]
the error: Reverse for 'password_reset_complete' not found. 'password_reset_complete' is not a valid view function or pattern name.
Thank you very much!

Change
path('password_reset_complete/',auth_view.PasswordResetCompleteView.as_view(),name='password-reset-complete')
to
path('password_reset_complete/',auth_view.PasswordResetCompleteView.as_view(),name='password_reset_complete')
Django reverse checks for name in the path.

Related

Error No URL to redirect to. Either provide a url or define a get_absolute_url method on the Model

i'm working on a django project to create football trainings. I'm testing the model and its saving. The problem appears when I try to save it, must be something about redirection, because in the database the training does get saved, but it doesn't redirect me anywhere and the error comes out.
models.py
from django.db import models
from django.utils import timezone
from users.models import User
class Entrenamiento(models.Model):
autor = models.ForeignKey(User, on_delete=models.CASCADE)
idEntrenamiento = models.AutoField(primary_key=True)
idEquipo = models.IntegerField()
fecha = models.DateTimeField(default=timezone.now)
idDireccionCampo = models.IntegerField()
temporadas = [
('2022/2023','2022/2023'),
('2023/2024','2023/2024'),
('2024/2025','2024/2025'),
('2025/2026','2025/2026')
]
temporada = models.CharField(max_length=50, choices=temporadas, default='2022/2023')
def __str__(self):
return 'Entrenamiento {}'.format(self.idEntrenamiento)
#property
def entreno(self):
return 'Entrenamiento {} de {} para {} con fecha del {}, será en el campo {}'.format(self.idEntrenamiento, self.temporada, self.idEquipo, self.fecha, self.idDireccionCampo)
views.py
from django.conf import settings
from django.contrib.auth.mixins import LoginRequiredMixin, UserPassesTestMixin
from django.contrib.messages.views import SuccessMessageMixin
from django.contrib.auth.models import User
from django.contrib import messages
from django.http import HttpRequest, HttpResponseRedirect
from django.shortcuts import get_object_or_404, render
from django.views.generic import (CreateView, DeleteView, DetailView, ListView,UpdateView)
from django import forms
from django.urls import reverse_lazy
from .models import Entrenamiento
def home(request):
context = {
'entrenamientos': Entrenamiento.objects.all()
}
return render(request, 'entrenamientos/entrenamientos.html', context)
class PostListView(ListView):
model = Entrenamiento
template_name = 'entrenamientos/entrenamientos.html'#<app>/<model>_<viewtype>.html
context_object_name = 'entrenamientos'
ordering = ['-fecha']
class PostDetailView(DetailView):
model = Entrenamiento
class PostCreateView(LoginRequiredMixin, CreateView):
model = Entrenamiento
fields = ['autor','idEntrenamiento','idEquipo','idDireccionCampo','fecha']
widgets = {'fecha': forms.DateInput(attrs={'type': 'date'})}
def form_valid(self,form):
form.instance.autor = self.request.user
return super().form_valid(form)
class PostUpdateView(LoginRequiredMixin, UserPassesTestMixin, UpdateView):
model = Entrenamiento
fields = ['autor','idEntrenamiento','idEquipo']
def form_valid(self,form):
form.instance.autor = self.request.user
return super().form_valid(form)
def test_func(self):
entrenamiento = self.get_object()
if self.request.user == entrenamiento.autor:
return True
return False
class PostDeleteView(DeleteView):
model = Entrenamiento
success_url = '/'
def test_func(self):
entrenamiento = self.get_object()
if self.request.user == entrenamiento.autor:
return True
return False
urls.py
from django.urls import path
from .views import PostListView, PostDetailView, PostCreateView, PostUpdateView, PostDeleteView
from django.contrib.auth.decorators import login_required
app_name = 'entrenamientos'
urlpatterns = [
path('', login_required(PostListView.as_view()), name='entrenamientos'),
path('entrenamiento/<int:pk>/',login_required( PostDetailView.as_view()), name='entrenamiento-detail'),
path('entrenamiento/new/',login_required( PostCreateView.as_view()), name='entrenamiento-create'),
path('entrenamiento/<int:pk>/update/',login_required( PostUpdateView.as_view()), name='entrenamiento-update'),
path('entrenamiento/<int:pk>/delete/',login_required( PostDeleteView.as_view()), name='entrenamiento-delete'),
path('entrenamiento', login_required(PostListView.as_view()), name='entrenamientos')
]
The error:
ImproperlyConfigured at /entrenamientos/entrenamiento/new/
No URL to redirect to. Either provide a url or define a get_absolute_url method on the Model.
I think that something it's wrong with: def form_valid(self,form):
I've tried adding this in the def form_valid but another error appears
# success_url = reverse_lazy('entrenamiento')
# success_message = 'Entrenamiento añadido'
I hope the solution
You have to provide success_url inside your class view. You can do it in one of possibilities, but the first one is enough for this problem:
class PostCreateView(LoginRequiredMixin, CreateView):
...
success_url = reverse_lazy('entrenamientos:entrenamientos')
# OR
def get_success_url(self):
return reverse_lazy('entrenamientos:entrenamientos')
Also look at your urls:
urlpatterns = [
path('', login_required(PostListView.as_view()), name='entrenamientos'),
...
path('entrenamiento', login_required(PostListView.as_view()), name='entrenamientos')
]
You have set two urls with exactly the same name. You should not do that. Always the first one will be rendered with {% url %} tag. Do you even need the second one?

Django Can't See Where I Typed in User ID

So I'm creating a web app in Django, and I encountered this error:
my urls.py:
from django.urls import path
from . import views
urlpatterns = [
path('', views.index, name='index'),
path('<int:user_id>/', views.profile, name="profile"),
#path('signup/', views.signup, name="signup"),
path("signup/", views.signup, name="signup")
]
my views.py:
from django.shortcuts import render, get_object_or_404
from django.contrib.auth import forms
from django.urls import reverse_lazy
from django.http import HttpResponse, Http404
from django.template import loader
from .models import User
from .forms import SignUpForm
from datetime import datetime
def index(request):
cool_people_list = User.objects.order_by("-username")[:5]
_template = loader.get_template("front_page.html")
context = {
"cool_people_list" : cool_people_list,
}
return HttpResponse(_template.render(context, request))
def profile(request, user_id):
try:
user = get_object_or_404(User, pk=user_id)
_template = loader.get_template("profile.html")
context = {
"user" : user
}
return HttpResponse(_template.render(context, request))
except:
raise Http404("The user you are looking for doesn't exist.")
def signup(request):
if request.method == "POST":
form = SignUpForm(request.POST)
if form.is_valid():
rn = str(datetime.today().strftime("%Y-%m-%D"))
rn2 = str(datetime.today)
"""usr_list = User.objects.order_by('-join_date')
latest_usr = usr_list.first()"""
new_user = User(3, str(form.cleaned_data.get("username")), str(form.cleaned_data.get("password")), rn, rn2)
new_user.save()
return render(request, "signup.html")
my models.py:
from django.db import models
from django.core.validators import MinLengthValidator
import datetime
class User(models.Model):
user_id = models.IntegerField(unique=True)
username = models.CharField(max_length=25, validators=[MinLengthValidator(3)])
password = models.CharField(max_length=25, validators=[MinLengthValidator(7)])
join_date = models.DateField()
last_online = models.DateTimeField()
def __str__(self):
return self.username
I kept trying different methods, like manually adding the user ID (temporary fix), but Django can't see where I type in the ID! It doesn't register it when I typed it in what I believe is the correct format for my 'User' model.
You need to save an object in User Model like this...
def signup(request):
if request.method == "POST":
form = SignUpForm(request.POST)
if form.is_valid():
rn = datetime.today().strftime("%Y-%m-%D")
rn2 = datetime.today
new_user = User(username= form.cleaned_data["username"], password=form.cleaned_data["password"], rn=rn, rn2=rn2)
new_user.save()
else:
form.errors
return render(request, "signup.html")

AttributeError: 'set' object has no attribute 'items' Error (Djngo Rest Api)

The following code has been written but still, the following error will happen:
VIEWS PAGE
from django.http.response import HttpResponse
from django.shortcuts import render
from rest_framework import serializers,status
from rest_framework.decorators import api_view
from rest_framework.response import Response
from .serializers import AccountSerializer
import requests, json
# Create your views here.
def home(request):
return render(request,'register.html')
def register(request):
return render(request,'register.html')
def login(request):
return render(request,'login.html')
#api_view(['POST'])
def registeruser(request):
if request.method == "POST":
SaveSerialize = AccountSerializer(data=request.data)
if SaveSerialize.is_valid():
SaveSerialize.save()
return Response(SaveSerialize.data,status=status.HTTP_201_CREATED)
return Response(SaveSerialize.data,status=status.HTTP_404_BAD_REQUEST)
def insertemp(request):
if request.method == "POST":
name = request.POST.get('name')
email = request.POST.get('email')
gender = request.POST.get('gender')
pass1 = request.POST.get('password1')
pass2 = request.POST.get('password2')
if pass1 == pass2:
password = pass1
address1 = request.POST.get('address1')
address2 = request.POST.get('address2')
city = request.POST.get('city')
branch = request.POST.get('branch')
address = f'{address1} {address2} {city} {branch}'
data = {
'name':name,
'email':email,
'gender':gender,
'password':password,
'address':address,
}
headers={'Content-Type: application/json'}
read = requests.post('http://127.0.0.1:8000/registeruser', json=data, headers=headers)
return render(request,'register.html')
else:
return render(request,'register.html')
This is the serializer page:
SERIALIZER PAGE:
from rest_framework import serializers
from .models import Account
class AccountSerializer(serializers.ModelSerializer):
class Meta:
model = Account
fields = "__all__"
MODELS PAGE:
from django.db import models
from django.db.models.base import Model
# Create your models here.
class Account(models.Model):
name=models.CharField(max_length=500)
email=models.EmailField(max_length=254)
gender=models.CharField(max_length=20)
password=models.CharField(max_length=100)
address=models.TextField()
def __str__(self):
return self.name
URLS PAGE:
from django.contrib import admin
from django.urls import path
from . import views
urlpatterns = [
path('admin/', admin.site.urls),
path('',views.home,name='home'),
path('register',views.register,name='register'),
path('login',views.login,name='login'),
path('registeruser',views.registeruser,name='registeruser'),
path('insertemp',views.insertemp,name='insertemp'),
]
this is following error occuring :
AttributeError at /insertemp
'set' object has no attribute 'items'
Request Method: POST
Request URL: http://127.0.0.1:8000/insertemp
Django Version: 4.0
Exception Type: AttributeError
Exception Value:
'set' object has no attribute 'items'
Exception Location: H:\Projects\Advance_projects\STEPON\Login\env\lib\site-packages\requests\models.py, line 451, in prepare_headers
Python Executable: H:\Projects\Advance_projects\STEPON\Login\env\Scripts\python.exe
Python Version: 3.10.1
Python Path:
['H:\\Projects\\Advance_projects\\STEPON\\Login\\login',
'C:\\Users\\sagar\\AppData\\Local\\Programs\\Python\\Python310\\python310.zip',
'C:\\Users\\sagar\\AppData\\Local\\Programs\\Python\\Python310\\DLLs',
'C:\\Users\\sagar\\AppData\\Local\\Programs\\Python\\Python310\\lib',
'C:\\Users\\sagar\\AppData\\Local\\Programs\\Python\\Python310',
'H:\\Projects\\Advance_projects\\STEPON\\Login\\env',
'H:\\Projects\\Advance_projects\\STEPON\\Login\\env\\lib\\site-packages']
You have a typo. Instead of:
headers={'Content-Type: application/json'}
you need this:
headers = {'Content-Type': 'application/json'}

Django Rest Framework Error: JSON parse error - Expecting ':' delimiter: line 4 column 21 (char 103)

I want to save a new user via POST request using the #api_view decorator in DRF but got the following error :
{
"detail": "JSON parse error - Expecting ':' delimiter: line 4 column 21 (char 103)"
}
models.py code:
from django.db import models
from django.contrib.auth.models import User
from PIL import Image
from django.conf import settings
class Profile(models.Model):
user = models.OneToOneField(User, on_delete = models.CASCADE)
image = models.ImageField(default = 'users/default.jpg', upload_to = 'users/profile_pics')
def __str__(self):
return f'{self.user.username} Profile'
def save(self, **kwargs):
super().save()
img = Image.open(self.image.path)
if img.height > 300 or img.width > 300:
output_size = (300, 300)
img.thumbnail(output_size)
img.save(self.image.path)
views.py code:
from django.shortcuts import render, redirect
from django.contrib.auth.models import User
from django.http import HttpResponse, JsonResponse
from rest_framework.parsers import JSONParser
from .serializers import UserSerializer
from rest_framework.decorators import api_view
from rest_framework.response import Response
from rest_framework import status
#api_view(['GET', 'POST'])
def user_list(request):
if request.method == 'GET':
users = User.objects.all().order_by('id')
serializer = UserSerializer(users, many = True)
return Response(serializer.data)
elif request.method == 'POST':
serializer = UserSerializer(data = request.data)
if serializer.is_valid():
serializer.save()
return Response(serializer.data, status = status.HTTP_201_created)
return Response(serializer.errors, status = status.HTTP_400_BAD_REQUEST)
serializers.py code:
from rest_framework import serializer
from django.contrib.auth.models import User
from .models import Profile
from django.contrib.auth.hashers import make_password
class UserSerializer(serializers.ModelSerializer):
id = serializers.IntegerField(read_only = True)
password = serializers.CharField(
required = False,
write_only = True,
style = {"input_type": "password", "placeholder": "Password"}
)
class Meta:
model = User
fields = ['id', 'username', 'email', 'password']
def create(self, validated_data):
validated_data['password'] = make_password(validated_data.get('password'))
return super(UserSerializer, self).create(validated_data)
urls.py code:
from django.urls import path, include
from .views import user_list, user_detail
from rest_framework import routers
urlpatterns = [
path('users/', user_list),
path('users/<int:pk>/', user_detail),
]
I am learning DRF from scratch and am following the documentation accordingly. I am not sure why I am getting the HTTP 400 Bad Request error here. It would be great if anyone can help me out.
This is an example of my POST request:
{
"username": "user_1",
"email": "user1m#gmail.com",
"password" : "testing1234"
}
ID is auto-incremented and a password is required (as mentioned in the serializer.py code)
you should post like this:
{
"username": "user_1",
"email": "user1m#gmail.com",
"password" : "testing1234"
}

Django: how to send argument in HtpResponseRedirect

Views.py
from django.shortcuts import render
from django.template.context_processors import csrf
from django.http import HttpResponseRedirect
from django.shortcuts import render_to_response
from .models import studentDetails
from .forms import loginForm
# Create your views here.
def login(request):
c = {}
c.update(csrf(request))
return render(request, "login.html", c)
def auth_view(request):
username = request.POST.get("username", "")
password = request.POST.get("password", "")
q = studentDetails.objects.get(name=username)
if q.password==password:
return HttpResponseRedirect("/student/accounts/loggedin")
return HttpResponseRedirect("/studemt/accounts/invalid")
def loggedin(request):
username = request.GET.get("username")
return render(request, "loggedin.html", {"full_name": username})
def invalid(request):
return render(request, "invalid_login.html")
def logout(request):
return render(request, "logout.html")
Urls.py
from django.conf.urls import url
from django.contrib import admin
from .views import (
login,
auth_view,
loggedin,
logout
)
urlpatterns = [
url(r"^accounts/login/$", login , name="login"),
url(r"^accounts/auth/$", auth_view ,name="auth_view"),
url(r"^accounts/loggedin/$", loggedin , name="loggedin"),
url(r"^accounts/logout/$", logout, name="logout"),
]
i want to send username from auth_view to loggedin view but i don'y know how to do that.
i have used username = request.GET.get("username") but it is not working.
i want to show username in url also such that it looks like /student/username/
where username will change as different user login.
You should pass parameter in url first:
url(r'^student/(?P<username>\w+)/$', views.userpage, name='userpage)
But better use pk field or something with name + pk, as url parametr, because username can be duplicate.
Now you can pass this parameter in view and don't hardcore url, use reverse with url name instead.
def auth_view(request):
username = request.POST.get("username", "")
password = request.POST.get("password", "")
q = studentDetails.objects.get(name=username)
if q.password==password:
return HttpResponseRedirect(reverse('userpage', args=[q.username]))
return HttpResponseRedirect(reverse('invalid'))

Categories