'UnboundLocalError at /api/registration/ even though I tried fixing it
Screenshot of the Error is at Error
The Error I face is:
UnboundLocalError at /api/registration/
local variable 'data' referenced before assignment
Request Method: POST
Request URL: http://217.160.170.83:81/api/registration/
Django Version: 3.2.12
Exception Type: UnboundLocalError
Exception Value:
local variable 'data' referenced before assignment
Exception Location: /var/www/LWD/userAccount/views.py, line 128, in get_response_data
Python Executable: /usr/bin/python3
Python Version: 3.8.10
Python Path:
['/var/www/LWD',
'/usr/lib/python38.zip',
'/usr/lib/python3.8',
'/usr/lib/python3.8/lib-dynload',
'/usr/local/lib/python3.8/dist-packages',
'/usr/lib/python3/dist-packages']
Server time: Sat, 26 Mar 2022 19:05:05 +0000
My Project Repository Link: https://github.com/Bilal815/LWD
LWD/userAccount/views.py:
from django.conf import settings
from django.shortcuts import get_object_or_404
from rest_framework.response import Response
from rest_framework import permissions, status, viewsets
from rest_framework.views import APIView
from rest_framework.generics import (
ListAPIView,
RetrieveAPIView,
CreateAPIView,
GenericAPIView,
RetrieveUpdateAPIView,
UpdateAPIView,
)
from rest_framework.exceptions import PermissionDenied, NotAcceptable, ValidationError
from allauth.account.views import ConfirmEmailView
from allauth.socialaccount.providers.facebook.views import FacebookOAuth2Adapter
from allauth.socialaccount.providers.twitter.views import TwitterOAuthAdapter
from allauth.socialaccount.providers.google.views import GoogleOAuth2Adapter
from allauth.socialaccount.providers.oauth2.client import OAuth2Client
from rest_auth.registration.views import SocialConnectView, SocialLoginView
from rest_auth.social_serializers import TwitterConnectSerializer
from allauth.account.models import EmailAddress, EmailConfirmationHMAC
from rest_auth.views import (
LoginView,
PasswordResetView,
PasswordResetConfirmView,
PasswordChangeView,
LogoutView,
)
from rest_auth.serializers import PasswordResetConfirmSerializer
from rest_auth.registration.views import RegisterView, VerifyEmailView
from rest_auth.registration.serializers import VerifyEmailSerializer
from rest_auth.app_settings import JWTSerializer
from rest_auth.utils import jwt_encode
from django.views.decorators.debug import sensitive_post_parameters
from django.utils.decorators import method_decorator
from django.contrib.auth.models import User, Permission
from django.utils.translation import ugettext_lazy as _
from .models import Profile, Address, SMSVerification, DeactivateUser, NationalIDImage
from .serializers import (
ProfileSerializer,
UserSerializer,
AddressSerializer,
CreateAddressSerializer,
SMSVerificationSerializer,
SMSPinSerializer,
DeactivateUserSerializer,
PermissionSerializer,
PasswordChangeSerializer,
UserPermissionSerializer,
NationalIDImageSerializer,
)
from .send_mail import send_register_mail, send_reset_password_email
sensitive_post_parameters_m = method_decorator(
sensitive_post_parameters("password1", "password2")
)
class DeactivateUserView(CreateAPIView):
permission_classes = [permissions.IsAuthenticated]
serializer_class = DeactivateUserSerializer
def create(self, request, *args, **kwargs):
user = request.user
# TODO validation and try exception
serializer = self.get_serializer(data=request.data)
serializer.is_valid(raise_exception=True)
serializer.save(user=user)
return Response("your account will deactivate after 30 days.")
class CanselDeactivateUserView(APIView):
permission_classes = [permissions.IsAuthenticated]
def post(self, request, *args, **kwargs):
user = request.user
# TODO validation and try exception
deactivate = DeactivateUser.objects.get(user=user)
deactivate.deactive = False
deactivate.save()
user.is_active = True
user.save()
return Response("your account will activated.")
class LoginAPIView(LoginView):
queryset = ""
def get_response(self):
serializer_class = self.get_response_serializer()
if getattr(settings, "REST_USE_JWT", False):
data = {"user": self.user, "token": self.token}
serializer = serializer_class(
instance=data, context={"request": self.request}
)
else:
serializer = serializer_class(
instance=self.token, context={"request": self.request}
)
response = Response(serializer.data, status=status.HTTP_200_OK)
deactivate = DeactivateUser.objects.filter(user=self.user, deactive=True)
if deactivate:
deactivate.update(deactive=False)
return response
def post(self, request, *args, **kwargs):
self.request = request
self.serializer = self.get_serializer(
data=self.request.data, context={"request": request}
)
self.serializer.is_valid(raise_exception=True)
self.login()
return self.get_response()
class RegisterAPIView(RegisterView):
@sensitive_post_parameters_m
def dispatch(self, *args, **kwargs):
return super(RegisterAPIView, self).dispatch(*args, **kwargs)
def get_response_data(self, user):
if getattr(settings, "REST_USE_JWT", False):
data = {"user": user, "token": self.token}
return JWTSerializer(data).data
def create(self, request, *args, **kwargs):
serializer = self.get_serializer(data=request.data)
serializer.is_valid(raise_exception=True)
user = self.perform_create(serializer)
headers = self.get_success_headers(serializer.data)
return Response(
self.get_response_data(user),
status=status.HTTP_201_CREATED,
headers=headers,
)
def perform_create(self, serializer):
user = serializer.save(self.request)
if getattr(settings, "REST_USE_JWT", False):
self.token = jwt_encode(user)
email = EmailAddress.objects.get(email=user.email, user=user)
confirmation = EmailConfirmationHMAC(email)
key = confirmation.key
# TODO Send mail confirmation here .
# send_register_mail.delay(user, key)
print("account-confirm-email/" + key)
return user
class ResendSMSAPIView(GenericAPIView):
permission_classes = (permissions.AllowAny,)
serializer_class = SMSVerificationSerializer
allowed_methods = ("POST",)
def resend_or_create(self):
phone = self.request.data.get("phone")
send_new = self.request.data.get("new")
sms_verification = None
user = User.objects.filter(profile__phone_number=phone).first()
if not send_new:
sms_verification = (
SMSVerification.objects.filter(user=user, verified=False)
.order_by("-created")
.first()
)
if sms_verification is None:
sms_verification = SMSVerification.objects.create(user=user, phone=phone)
return sms_verification.send_confirmation()
def post(self, request, *args, **kwargs):
success = self.resend_or_create()
return Response(dict(success=success), status=status.HTTP_200_OK)
class VerifySMSView(APIView):
permission_classes = (permissions.AllowAny,)
allowed_methods = ("POST", "OPTIONS", "HEAD")
def get_serializer(self, *args, **kwargs):
return SMSPinSerializer(*args, **kwargs)
def post(self, request, pk):
serializer = self.get_serializer(data=request.data)
serializer.is_valid(raise_exception=True)
pin = int(request.data.get("pin"))
# TODO get user SMSVerification instead of below confirmation variable
confirmation = get_object_or_404(SMSVerification, pk=pk)
confirmation.confirm(pin=pin)
return Response("Your Phone Number Is Verfied.", status=status.HTTP_200_OK)
class ProfileAPIView(APIView):
permission_classes = [permissions.IsAuthenticated]
def get(self, request, pk):
profile = Profile.objects.get(pk=pk)
serializer = ProfileSerializer(profile, context={"request": request})
return Response(serializer.data, status=status.HTTP_200_OK)
class UserDetailView(RetrieveAPIView):
permission_classes = [permissions.IsAuthenticated]
serializer_class = UserSerializer
queryset = User.objects.all()
lookup_field = "username"
class ListAddressAPIView(ListAPIView):
permission_classes = [permissions.IsAuthenticated]
serializer_class = AddressSerializer
def get_queryset(self):
user = self.request.user
queryset = Address.objects.filter(user=user)
return queryset
class AddressDetailView(RetrieveAPIView):
permission_classes = [permissions.IsAuthenticated]
serializer_class = AddressSerializer
queryset = Address.objects.all()
def retrieve(self, request, *args, **kwargs):
user = request.user
address = self.get_object()
if address.user != user:
raise NotAcceptable("this addrss don't belong to you")
serializer = self.get_serializer(address)
return Response(serializer.data, status=status.HTTP_200_OK)
class createAddressAPIView(CreateAPIView):
permission_classes = [permissions.IsAuthenticated]
serializer_class = CreateAddressSerializer
queryset = ""
def create(self, request, *args, **kwargs):
serializer = self.get_serializer(data=request.data)
serializer.is_valid(raise_exception=True)
serializer.save(user=request.user, primary=True)
return Response(serializer.data, status=status.HTTP_201_CREATED)
class FacebookConnectView(SocialLoginView):
adapter_class = FacebookOAuth2Adapter
class TwitterConnectView(SocialLoginView):
serializer_class = TwitterConnectSerializer
adapter_class = TwitterOAuthAdapter
class GoogleLogin(SocialLoginView):
adapter_class = GoogleOAuth2Adapter
client_class = OAuth2Client
callback_url = "https://www.google.com"
class PasswordResetView(APIView):
def post(self, request, *args, **kwargs):
email = request.data.get("email", None)
try:
user = User.objects.get(email=email)
except User.DoesNotExist:
raise NotAcceptable(_("Please enter a valid email."))
send_reset_password_email.delay(user)
return Response(
{"detail": _("Password reset e-mail has been sent.")},
status=status.HTTP_200_OK,
)
class PasswordResetConfirmView(GenericAPIView):
permission_classes = (permissions.AllowAny,)
serializer_class = PasswordResetConfirmSerializer
@sensitive_post_parameters_m
def dispatch(self, *args, **kwargs):
return super(PasswordResetConfirmView, self).dispatch(*args, **kwargs)
def post(self, request, *args, **kwargs):
serializer = self.get_serializer(data=request.data)
serializer.is_valid(raise_exception=True)
serializer.save()
return Response({"detail": _("Password has been reset with the new password.")})
class PasswordChangeView(GenericAPIView):
permission_classes = (permissions.IsAuthenticated,)
serializer_class = PasswordChangeSerializer
@sensitive_post_parameters_m
def dispatch(self, *args, **kwargs):
return super(PasswordChangeView, self).dispatch(*args, **kwargs)
def post(self, request, *args, **kwargs):
serializer = self.get_serializer(data=request.data)
serializer.is_valid(raise_exception=True)
serializer.save()
return Response({"detail": _("Congratulations, password has been Changed.")})
class VerifyEmailView(APIView, ConfirmEmailView):
permission_classes = (permissions.AllowAny,)
allowed_methods = ("POST", "OPTIONS", "HEAD")
def get_serializer(self, *args, **kwargs):
return VerifyEmailSerializer(*args, **kwargs)
def post(self, request, *args, **kwargs):
serializer = self.get_serializer(data=request.data)
serializer.is_valid(raise_exception=True)
self.kwargs["key"] = serializer.validated_data["key"]
confirmation = self.get_object()
confirmation.confirm(self.request)
return Response({"detail": _("ok")}, status=status.HTTP_200_OK)
class RetrievePermissionView(RetrieveAPIView):
serializer_class = UserPermissionSerializer
queryset = User.objects.all()
lookup_field = "username"
class UpdatePermissionView(UpdateAPIView):
serializer_class = UserPermissionSerializer
queryset = User.objects.all()
lookup_field = "username"
def partial_update(self, request, *args, **kwargs):
kwargs["partial"] = True
return self.update(request, *args, **kwargs)
# def update(self, request, *args, **kwargs):
# partial = True
# return super(UpdatePermissionView, self).update(request, *args, **kwargs)
class NationalIDImageViewSet(viewsets.ModelViewSet):
serializer_class = NationalIDImageSerializer
queryset = NationalIDImage.objects.all().select_related("user")
LWD/userAccounts/models.py:
import logging
from datetime import datetime, timezone, timedelta
from django.db import models
from django.contrib.auth import get_user_model
from django.db.models.signals import post_save, pre_save
from django.dispatch import receiver
from django.conf import settings
from django.core.cache import cache
from django.core.validators import MaxValueValidator, MinValueValidator, RegexValidator
from rest_framework.authtoken.models import Token
from rest_framework.exceptions import NotAcceptable
from allauth.account.signals import user_signed_up
from phonenumber_field.modelfields import PhoneNumberField
from django_countries.fields import CountryField
from randompinfield import RandomPinField
import phonenumbers
from twilio.rest import Client
from twilio.base.exceptions import TwilioRestException
from .signals import register_signal
from .managers import NationalIDImageManager
from core.models import TimeStampedModel
from core.handle_images import compress_image
User = get_user_model()
def user_directory_path(instance, filename):
# file will be uploaded to MEDIA_ROOT/users/<username>/<filename>
return "users/{0}/{1}".format(instance.user.username, filename)
def national_image_path(instance, filename):
return f"national/{instance.user.username}/images/{filename}"
class Profile(TimeStampedModel):
GENDER_MALE = "m"
GENDER_FEMALE = "f"
OTHER = "o"
GENDER_CHOICES = (
(GENDER_MALE, "Male"),
(GENDER_FEMALE, "Female"),
(OTHER, "Other"),
)
user = models.OneToOneField(User, related_name="profile", on_delete=models.CASCADE)
profile_picture = models.ImageField(upload_to=user_directory_path, blank=True)
phone_number = PhoneNumberField(blank=True)
gender = models.CharField(max_length=1, choices=GENDER_CHOICES, blank=True)
about = models.TextField(blank=True, null=True)
birth_date = models.DateField(blank=True, null=True)
def __str__(self):
return "%s" % self.user.username
@property
def last_seen(self):
return cache.get(f"seen_{self.user.username}")
@property
def online(self):
if self.last_seen:
now = datetime.now(timezone.utc)
if now > self.last_seen + timedelta(minutes=settings.USER_ONLINE_TIMEOUT):
return False
else:
return True
else:
return False
@receiver(post_save, sender=User)
def create_user_profile(sender, instance, created, *args, **kwargs):
if created:
Profile.objects.create(user=instance)
class Address(TimeStampedModel):
user = models.ForeignKey(User, related_name="address", on_delete=models.CASCADE)
country = CountryField(blank=False, null=False)
city = models.CharField(max_length=100, blank=False, null=False)
district = models.CharField(max_length=100, blank=False, null=False)
street_address = models.CharField(max_length=250, blank=False, null=False)
postal_code = models.CharField(max_length=20, blank=True, null=True)
primary = models.BooleanField(default=False)
phone_number = PhoneNumberField(null=True, blank=True)
building_number = models.IntegerField(
blank=True, null=True, validators=[MinValueValidator(1)]
)
apartment_number = models.IntegerField(
blank=True, null=True, validators=[MinValueValidator(1)]
)
class SMSVerification(TimeStampedModel):
user = models.OneToOneField(User, related_name="sms", on_delete=models.CASCADE)
verified = models.BooleanField(default=False)
pin = RandomPinField(length=6)
sent = models.BooleanField(default=False)
phone = PhoneNumberField(null=False, blank=False)
def send_confirmation(self):
logging.debug("Sending PIN %s to phone %s" % (self.pin, self.phone))
if all(
[
settings.TWILIO_ACCOUNT_SID,
settings.TWILIO_AUTH_TOKEN,
settings.TWILIO_FROM_NUMBER,
]
):
try:
twilio_client = Client(
settings.TWILIO_ACCOUNT_SID, settings.TWILIO_AUTH_TOKEN
)
twilio_client.messages.create(
body="Your forgeter activation code is %s" % self.pin,
to=str(self.user.profile.phone_number),
from_=settings.TWILIO_FROM_NUMBER,
)
self.sent = True
self.save()
return True
except TwilioRestException as e:
logging.error(e)
else:
logging.warning("Twilio credentials are not set")
def confirm(self, pin):
if pin == self.pin and self.verified == False:
self.verified = True
self.save()
else:
raise NotAcceptable("your Pin is wrong, or this phone is verified before.")
return self.verified
@receiver(post_save, sender=Profile)
def send_sms_verification(sender, instance, *args, **kwargs):
try:
sms = instance.user.sms
if sms:
pin = sms.pin
sms.delete()
verification = SMSVerification.objects.create(
user=instance.user,
phone=instance.user.profile.phone_number,
sent=True,
verified=True,
pin=pin,
)
except:
if instance.user.profile.phone_number:
verification = SMSVerification.objects.create(
user=instance.user, phone=instance.user.profile.phone_number
)
# TODO Remove send confirm from here and make view for it.
verification.send_confirmation()
# if instance.user.profile.phone_number:
# verification = SMSVerification.objects.create(user=instance.user, phone=instance.user.profile.phone_number)
# # TODO Remove send confirm from here and make view for it.
# verification.send_confirmation()
class DeactivateUser(TimeStampedModel):
user = models.OneToOneField(
User, related_name="deactivate", on_delete=models.CASCADE
)
deactive = models.BooleanField(default=True)
class NationalIDImage(models.Model):
user = models.ForeignKey(
User, related_name="national_ids", on_delete=models.CASCADE
)
image = models.ImageField(upload_to=national_image_path, blank=True)
is_deleted = models.BooleanField(default=False)
objects = NationalIDImageManager()
def __str__(self):
return self.user.username
def save(
self,
force_insert=False,
force_update=False,
using=None,
update_fields=None,
*args,
**kwargs,
):
# if size greater than 300kb then it will send to compress image function
image = self.image
if image and image.size > (0.3 * 1024 * 1024):
self.image = compress_image(image)
super(NationalIDImage, self).save(*args, **kwargs)
P.S. I tried fixing it by commenting on the data clean-up for phone number and birthdate but it did not work. Things work well on local but I have no idea of what happened here on the server. This is my first time on the server and I need it done as I want to add this to my portfolio.
Please help!
Solution 1:[1]
Error is in this part:
def get_response_data(self, user):
if getattr(settings, "REST_USE_JWT", False):
data = {"user": user, "token": self.token}
return JWTSerializer(data).data
You only create data when if getattr(settings, "REST_USE_JWT", False) is true.
So what happens if it's false? data is not created, but you reference it in JWTSerializer(data).
You need to provide something in else like:
def get_response_data(self, user):
if getattr(settings, "REST_USE_JWT", False):
data = {"user": user, "token": self.token}
else:
data = {# something goes here}
return JWTSerializer(data).data
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | Bartosz Stasiak |
