'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