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!
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
I literally searched similar questions but didn't a answer that solves my question
I want a functionality like a question can have multiple answers
my models.py
class QuestionModel(models.Model):
question = models.TextField()
author = models.ForeignKey(User, on_delete=models.CASCADE)
doubt_class_id = models.ForeignKey(DoubtClasses, on_delete=models.CASCADE)
conceptual_class_id = models.ForeignKey(LiveClass_details, on_delete=models.CASCADE, null=True, blank=True)
status = models.BooleanField(default=False)
mentor = models.ForeignKey(Mentor, on_delete=models.CASCADE, null=True, blank=True)
def __str__(self):
return self.question
def clean(self):
if self.doubt_class_id and self.conceptual_class_id :
raise ValidationError("only one field can be set")
class AnswersModel(models.Model):
answer = models.TextField()
question_id = models.ForeignKey(QuestionModel, on_delete=models.CASCADE)
my urls.py
path('questions/', views.QuestionModelView.as_view()),
path('questions/<int:id>/', views.QuestionModelViewID.as_view()),
path('questions/<int:id>/answer/', views.AnswerModel.as_view()),
my views.py
# Create your views here.
class QuestionModelView(mixins.ListModelMixin, mixins.CreateModelMixin,GenericAPIView):
queryset = models.QuestionModel.objects.all()
serializer_class = serializers.QuestionModel_serializer
permission_classes = [IsAuthenticated]
def get(self, request):
return self.list(request)
def post(self, request):
return self.create(request)
class QuestionModelViewID(mixins.ListModelMixin, mixins.RetrieveModelMixin, mixins.UpdateModelMixin, mixins.DestroyModelMixin,GenericAPIView):
queryset = models.QuestionModel.objects.all()
serializer_class = serializers.QuestionModel_serializer
permission_classes = [IsAuthenticated]
lookup_field = 'id'
def get(self, request, id=None):
if id:
return self.retrieve(request, id)
else:
return Response(status=status.HTTP_204_NO_CONTENT)
def put(self, request, id=None):
if int(request.POST.get('author')) != self.request.user.id:
return Response("you cannot edit othe user question", status=status.HTTP_405_METHOD_NOT_ALLOWED)
if id:
return self.update(request, id)
else:
return Response(status=status.HTTP_204_NO_CONTENT)
def delete(self, request, id=None):
if int(request.POST.get('author')) != self.request.user.id:
return Response("you cannot destroy othe user question", status=status.HTTP_405_METHOD_NOT_ALLOWED)
if id:
return self.delete(request, id)
else:
return Response(status=status.HTTP_204_NO_CONTENT)
class AnswerModel(mixins.ListModelMixin, mixins.CreateModelMixin, GenericAPIView):
lookup_field = 'id'
serializer_class = serializers.AnswerModel_serializer
def get_queryset(self, *args, **kwargs):
return models.AnswersModel.objects.filter(question_id = self.kwargs['id'])
def get(self, request, id=None):
return self.list(request)
def post(self, request, id=None):
if request.user.is_superuser:
return self.create(request, id)
else:
return Response("only superuser can post a answer", status=status.HTTP_400_BAD_REQUEST)
I want to make a url like questions/id/answers/answer_id where id is the question id and answer_id is the id for a particular answer as a question can have multiple answers but for that i want to add 2 lookup_fields in my view which i am not getting how to add it or please suggest another approach for this query if its not possible to do like that
if you have query like this questions/id/answers/answer_id
you can do like this if I understood your question good.
def get_queryset(self):
id = self.kwargs['id']
answerid = self.kwargs['answer_id']
queryset = Model.objects.get(
id=id,answerid=answerid)
return queryset
or
def get(self, request, id, answer_id):
Questiomn = Model.objects.get(
id=id,answerid=answerid)
I wrote code to create new users via POST and DRF (Django Rest Framework) successfully and I can obtain token correctly, however when I try to POST (via DRF) to fill Profile linked to that user I get
(1048, "Column 'user_id' cannot be null")
This is snippets of my code:
for serializers:
class UserSerializer(ModelSerializer):
class Meta:
model = User
fields = ('username','email','first_name','last_name','password')
def create(self, *args, **kwargs):
user = super().create(*args, **kwargs)
p = user.password
user.set_password(p)
user.save()
return user
def update(self, *args, **kwargs):
user = super().update(*args, **kwargs)
p = user.password
user.set_password(p)
user.save()
return user
class ProfileSerializer(ModelSerializer):
class Meta:
model = Profile
fields = ('bio','birth_date','location','country')
def create(self, *args, **kwargs):
profile = super().create(*args, **kwargs)
profile.save()
return profile
def update(self, *args, **kwargs):
profile = super().update(*args, **kwargs)
profile.save()
return profile
and for views:
class ProfileViewSet(viewsets.ModelViewSet):
"""
API endpoint that allows users to be viewed or edited.
"""
permission_classes = IsAuthenticated,
serializer_class = ProfileSerializer
queryset = Profile.objects.all()
class UserViewSet(viewsets.GenericViewSet,mixins.CreateModelMixin,):
"""
API endpoint that allows users to be viewed or edited.
"""
#permission_classes= (IsAdminUser,)
serializer_class = UserSerializer
queryset = User.objects.all().order_by('-date_joined')
and for models:
#receiver(post_save, sender = settings.AUTH_USER_MODEL)
def create_auth_token(sender,instance=None,created=False, **kwargs):
if created:
Token.objects.create(user=instance)
class Country(models.Model):
iso = models.CharField(max_length = 2,unique = True)
name = models.CharField(max_length = 250)
iso3 = models.CharField(max_length = 6)
phonecode = models.CharField(max_length=6)
def __unicode__(self):
return '%s' % self.name
def __str__(self):
return '%s' % self.name
class Profile(models.Model):
#user = models.OneToOneField(User, on_delete=models.CASCADE,default = "")
user = models.OneToOneField(settings.AUTH_USER_MODEL, on_delete=models.CASCADE,default = "")
bio = models.TextField(max_length=100, blank=True)
birth_date = models.DateField(null=True, blank=True)
location = models.CharField(max_length=254, blank=True)
country = models.ForeignKey(Country,on_delete=models.CASCADE,blank=True,null=True)
def __unicode__(self):
return '%s' % self.user
def __str__(self):
return '%s' % self.user
#receiver(post_save, sender=User)
def update_user_profile(sender, instance, created, **kwargs):
if created:
Profile.objects.create(user=instance)
instance.profile.save()
When I try with Postman and I pass a token for token authentication, it recognize the token correctly but I get this error:
(1048, "Column 'user_id' cannot be null") with Django DRF
I appreciate your help to solve this problem
Create() save to the database, so you need to set profile.user_id before calling the function.
I am trying to make a nested comment functionality using django rest framework.
I am using Django 2.2 and rest framework version 3.10.2 but here i am following a video in youtube that uses Django 1.9.
No matter what value i passed in URL, it always return a validation error stating that
model_qs is empty.
I am not able to solve this issue. Can someone please look into it and
let me point out what i am doing wrong here.
from django.contrib.auth.models import User
from django.contrib.contenttypes.fields import GenericForeignKey
from django.contrib.contenttypes.models import ContentType
urls.py
urlpatterns = [
path('create/', CommentCreateAPIView.as_view(), name='create'),
]
model.py
class CommentManager(models.Manager):
def all(self):
qs = super(CommentManager, self).filter(parent=None)
return qs
def filter_by_instance(self, instance):
content_type = ContentType.objects.get_for_model(instance.__class__)
obj_id = instance.id
qs = super(CommentManager, self).filter(content_type=content_type, object_id=obj_id).filter(parent=None)
return qs
def create_by_model_type(self, model_type, slug, content, user, parent_obj=None):
model_qs = ContentType.objects.filter(model=model_type)
if model_qs.exists():
some_model = model_qs.first().model_class()
obj_qs = some_model.objects.filter(slug=slug)
if obj_qs.exists() and obj_qs.count() == 1:
instance = self.model()
instance.content = content
instance.user = user
instance.content_type = model_qs.first()
instance.object_id = obj_qs.first().id
if parent_obj:
instance.parent = parent_obj
instance.save()
return instance
return None
class Comment(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE, default=1)
content_type = models.ForeignKey(ContentType, on_delete=models.CASCADE)
object_id = models.PositiveIntegerField()
content_object = GenericForeignKey('content_type', 'object_id')
parent = models.ForeignKey('self', null=True, blank=True, on_delete=models.CASCADE)
content = models.TextField()
timestamp = models.DateTimeField(auto_now_add=True)
objects = CommentManager()
class Meta:
ordering = ['-timestamp']
def __unicode__(self):
return str(self.user.username)
def __str__(self):
return str(self.user.username)
def get_absolute_url(self):
return reverse("comments:thread", kwargs={"id": self.id})
def get_delete_url(self):
return reverse("comments:delete", kwargs={"id": self.id})
def children(self): # Replies
return Comment.objects.filter(parent=self)
#property
def is_parent(self):
if self.parent is not None:
return False
return True
serializers.py
def create_comment_serializer(model_type='post', slug=None, parent_id=None, user=None):
class CommentCreateSerializer(ModelSerializer):
class Meta:
model = Comment
fields = [
'id',
'parent',
'content',
'timestamp',
]
def __init__(self, *args, **kwargs):
self.model_type = model_type
self.slug = slug
self.parent_obj = None
if parent_id:
parent_qs = Comment.objects.filter(id=parent_id)
if parent_qs.exists() and parent_qs.count() == 1:
self.parent_obj = parent_qs.first()
return super(CommentCreateSerializer, self).__init__(*args, **kwargs)
def validate(self, data):
model_type = self.model_type
model_qs = ContentType.objects.filter(model=model_type)
print(model_qs) # This always return <QuerySet []>
if not model_qs.exists() or model_qs.count() != 1:
raise ValidationError("This is not a valid content types")
some_model = model_qs.first().model_class()
obj_qs = some_model.objects.filter(slug=self.slug)
if not obj_qs.exists() or obj_qs.count() != 1:
raise ValidationError("This is not a valid slug")
return data
def create(self, validated_data):
content = validated_data.get("content")
if user:
main_user = user
else:
main_user = User.objects.all().first()
model_type = self.model_type
slug = self.slug
parent_obj = self.parent_obj
comment = Comment.objects.create_by_model_type(model_type, slug, content, main_user, parent_obj=parent_obj,)
return comment
return CommentCreateSerializer
views.py
class CommentCreateAPIView(CreateAPIView):
queryset = Comment.objects.all()
# permission_classes = [IsAuthenticated]
def get_serializer_class(self):
model_type = self.request.GET.get("type")
slug = self.request.GET.get("slug")
parent_id = self.request.GET.get("parent_id", None)
return create_comment_serializer(
model_type=model_type,
slug=slug,
parent_id=parent_id,
user=self.request.user
)
I am trying to give a user the option to change his/her first/last name through a ModelForm. When I press submit, I get hit with the UNIQUE constraint failed: auth_user.username error. Here are my codes:
students/forms.py:
class EditProfileForm(UserChangeForm):
def clean_password(self):
# Overriding the default method because I dont want user to change
# password
pass
class Meta:
model = User
fields = (
'first_name',
'last_name',
)
students/views.py:
User = get_user_model()
def student_profile_view(request, slug):
if request.method == 'GET':
# forms
edit_name_form = EditProfileForm(instance=request.user)
context = {
'edit_name_form': edit_name_form,
}
return render(request, "students/profile.html", context)
class ChangeNameView(SuccessMessageMixin, UpdateView):
template_name = 'students/edit_profile.html'
model = User
form_class = EditProfileForm
success_message = "Your name has been updated"
def post(self, request, *args, **kwargs):
form = self.get_form()
if form.is_valid():
form.instance.student_profile = StudentProfile.objects.get(slug=request.user.student_profile.slug)
return self.form_valid(form)
else:
return self.form_invalid(form)
def form_valid(self, form):
"""If the form is valid, save the associated model."""
form.instance.username = self.request.user
self.object = form.save(commit=False)
return super().form_valid(form)
def get_success_url(self):
return reverse('students:student_profile_view', kwargs={'slug': self.object.student_profile.slug})
also fyi, User model is foreign key with StudentProfile.
students/models.py:
class StudentProfile(models.Model):
user = models.OneToOneField(User, related_name='student_profile', on_delete=models.CASCADE)
slug = models.SlugField(blank=True, unique=True)
avatar = models.ImageField(upload_to='student_profile/', null=True, blank=True)
description = models.CharField(max_length=120, null=True, blank=True)
objects = models.Manager()
def __str__(self):
return self.user.username
def get_absolute_url(self):
return reverse("students:student_profile_view", kwargs={"slug": self.slug})
I am pretty new to class based view so maybe I'm doing something wrong there?
I assume you do not have the user within the form so you need the form
def get_context_data (self, *args, **kwargs)
ctx = super().get_context_data(*args, **kwargs)
if self.request.method == 'POST':
ctx['form'] = EditProfileForm(instance=self.request.user)
and remove def form_valid()