drf not creating profile without profile key - django

i'm trying to create userprofile while creating user. i'm getting this error:
profile_data = validated_data.pop('profile')
KeyError: 'profile'
when i don't pass profile key while user creation but i have mentioned not required userprofileserialzer in customuserSerializers. i just want to save null if i don't pass profile key.
models.py:
class CustomUser(AbstractBaseUser, PermissionsMixin):
first_name = models.CharField(_('first name'), max_length=50)
last_name = models.CharField(_("last name"), max_length=50)
email = models.EmailField(_('email address'), unique=True)
mobile_number = PhoneNumberField()
is_staff = models.BooleanField(default=False)
is_active = models.BooleanField(default=True)
date_joined = models.DateTimeField(default=timezone.now)
user_type = models.IntegerField(_("user_type"))
otp = models.CharField(_("otp"), max_length=10, default="0")
is_varified = models.BooleanField(default=False)
USER_TYPE_CHOICES = (
(1, 'users'),
(2, 'courier'),
(3, 'admin'),
)
user_type = models.PositiveSmallIntegerField(
choices=USER_TYPE_CHOICES, null=True)
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = []
objects = CustomUserMananager()
def __str__(self):
return self.email
class UserProfile(models.Model):
user = models.OneToOneField(
CustomUser, primary_key=True, related_name='userProfile', on_delete=models.CASCADE,)
gender = models.CharField(max_length=10, blank=True, null=True)
age = models.IntegerField(blank=True, null=True)
image = models.ImageField(
upload_to='api/user_profile/', blank=True, null=True)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
def __unicode__(self):
return self.user.first_name
serializers.py:
class UserProfileSerializer(serializers.ModelSerializer):
class Meta:
model = UserProfile
read_only_fields = ('created_at', 'updated_at',)
exclude = ('user',)
class CustomUserSerializer(serializers.ModelSerializer):
profile = UserProfileSerializer(required=False)
password = serializers.CharField(write_only=True, required=False)
class Meta:
model = CustomUser
fields = ('id', 'first_name', 'last_name', 'email',
'mobile_number', 'password', 'is_active', 'user_type', 'otp', 'profile')
def create(self, validated_data):
profile_data = validated_data.pop('profile')
user = CustomUser.objects.create(**validated_data)
UserProfile.objects.create(user=user, **profile_data)
return user
def update(self, instance, validated_data):
profile_data = validated_data.pop('profile')
# update user data
instance.first_name = validated_data.get(
'first_name', instance.first_name)
instance.last_name = validated_data.get(
'last_name', instance.last_name)
instance.email = validated_data.get('email', instance.email)
# update user profile
if not instance.profile:
UserProfile.objects.create(user=instance, **profile_data)
instance.age = profile_data.get('age', instance.profile.age)
instance.gender = profile_data.get('gender', instance.profile.gender)
instance.save()
password = validated_data.get('password', None)
if password:
instance.set_password(password)
instance.save()
update_session_auth_hash(self.context.get('request'), instance)
return instance
views.py:
#api_view(["POST"])
#permission_classes((AllowAny,))
def register(request):
#permission_classes = [(AllowAny, )]
serializer = CustomUserSerializer(data=request.data)
# print(serializer)
if serializer.is_valid():
serializer.is_active = False
# serializer.make_password(request.data.get('password'))
serializer.save()
user_otp = randint(9999, 99999)
otp_code = str(user_otp)
email = request.data.get('email')
send_mail(
'Otp verification',
otp_code,
'chenaj
il.com',
[email],
fail_silently=False,
)
# serializer.save(otp=user_otp)
otp_update = CustomUser.objects.get(email=request.data.get('email'))
otp_update.otp = user_otp
otp_update.save()
user = CustomUser.objects.get(email=email)
token, created = Token.objects.get_or_create(user=user)
current_time = datetime.datetime.now()
return Response({'status_code': status.HTTP_200_OK, 'status': 'true', 'currentTimeStamp': current_time, 'message': 'User registered successfully, OTP sent to your Mail', 'data': {'id': user.id, 'token': token.key, 'user_type': user.user_type}}, status=status.HTTP_200_OK)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
#api_view(["POST"])
#permission_classes((IsAuthenticated, AllowAny))
def verifyUserOtp(request):
print("data.......////")
serializers = VerifyUserOtpSerializer(data=request.data)
if serializers.is_valid(raise_exception=True):
token = request.data.get('email')
otp = request.data.get('otp')
if CustomUser.objects.filter(otp=otp).exists():
user = CustomUser.objects.get(otp=otp)
user.is_varified = 1
user.save()
token, created = Token.objects.get_or_create(user=user)
print(user.profile.age)
return Response({'status_code': status.HTTP_200_OK, 'status': 'true', 'currentTimeStamp': datetime.datetime.now(), 'data': {'id': user.id, 'first_name': user.first_name, 'last_name': user.last_name, 'email': user.email, 'token': token.key, 'user_type': user.user_type}}, status=status.HTTP_200_OK)
return Response({'message': 'OTP not matched', 'status': 'false', 'status_code': status.HTTP_401_UNAUTHORIZED, 'currentTimeStamp': datetime.datetime.now()}, status=status.HTTP_400_BAD_REQUEST)
and in this verifyuserotp function i'm not able to access profile objects with user.profile.age.

To avoid having this error, you need to provide a default value for .pop method
like None
and whenever the returned value is None, don't create a Profile record.
def create(self, validated_data):
profile_data = validated_data.pop('profile', None)
user = CustomUser.objects.create(**validated_data)
if profile_data:
UserProfile.objects.create(user=user, **profile_data)
return user
This should solve your issue.

Related

how to send an email verification from admin when an email is updated

I joined a project where the code is written on django 2+.
It's a system for patient and doctors.
When a doctor registered a patient, this one gets an email confirmation with a link.
Once he clicks on it she can use the platform.
On her user interface in settings, a patient can update her email and she will get a new link to her new email to confirm that it is her email. Before she clicks on the confirmation link, the email attribute is not changed. only the email candidate is updated and to this one the email is sent.
(if I change the email attribute to the email_candidate one so if she made a mistake on the her email_candidate she won't be able to log in anymore)
Then after the click, the patient email will become the email candidate one.
All this works
on the Patient Support Admin interface, an agent can help patients to update their email also.
But when the action is requested of send an email confirmation the email candidate is not chosen. only the user email is chosen and to it the email confirmation is sent.
I really don't understand how to call maybe the same function of update email.
models.py User
class User(AbstractUser):
objects = UserManager()
is_physician = models.BooleanField(default=False)
is_patient = models.BooleanField(default=False)
title = models.CharField(choices=TITLE_CHOICES,
max_length=10,
blank=True,
null=True)
first_name = models.CharField(max_length=254, blank=True, null=True, )
last_name = models.CharField(max_length=254, blank=True, null=True, )
birthdate = models.DateField(null=True, blank=True)
home_phone = PhoneNumberField(blank=True, null=True)
mobile_phone = PhoneNumberField(blank=True, null=True)
gender = models.CharField(max_length=1,
choices=GENDER_CHOICES,
blank=True,
null=True)
language = models.CharField(max_length=4,
choices=settings.LANGUAGES,
default='en',
blank=True,
null=True)
email = models.EmailField(unique=True, db_index=True,
error_messages={
'unique': "Email already exists."
}
)
email_candidate = models.EmailField(
max_length=254,
blank=True,
null=True,
default=None)
username = models.CharField(
max_length=30,
unique=True,
blank=True,
null=True,
validators=[
validators.RegexValidator(
r'^\w+$',
'Enter a valid username. This value may contain only '
'letters, numbers and _ character.',
'invalid'
),
],
error_messages={
'unique': "Username already exists."
}
)
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = []
ordering = ('created',)
class Meta(object):
verbose_name = 'User'
verbose_name_plural = 'Users'
# abstract = False
permissions = u_perm.user_permissions
#property
def name(self):
return '{} {}'.format(self.last_name, self.first_name, )
models.py Patient has a OneToOne field user
class Patient(models.Model):
user = models.OneToOneField(
settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
physician = models.ForeignKey(Physician,
related_name='patients',
null=True,
blank=True,
on_delete=models.SET_NULL)
address = models.TextField(blank=True, null=True)
city = models.CharField(max_length=85, null=True, blank=True)
country = CountryField(null=True, blank=True)
postal_code = models.CharField(max_length=32, null=True, blank=True)
reminder_hour_default = models.TimeField(
'Send Reminder Time',
default=settings.REMINDER_HOUR_DEFAULT)
is_eligible = models.BooleanField(default=True)
def __str__(self):
return self.user.email
#receiver(post_save, sender=Patient)
#receiver(post_save, sender=User)
def update_status(sender, **kwargs):
def update_patient(instance):
# from pending/disabled to active
current_status = instance.user.status
instance.save()
instance.user.save()
return
def update_user(instance):
pass
instance = kwargs.get('instance')
method_name = get_inner_method(sender)
if instance and method_name:
method_name(instance)
models.py Patient Support
class PatientSupport(Patient):
class Meta:
proxy = True
# Add verbose name
verbose_name = 'Patient Support'
verbose_name_plural = 'Patients Support'
serializers.py UserSerializer with the working endpoint from the patient UI called
update_candidate_email
class UserSerializer(serializers.ModelSerializer):
permission_list = serializers.SerializerMethodField()
permissions = serializers.SerializerMethodField()
user_messages = serializers.SerializerMethodField()
class Meta:
model = User
fields = (
'pk',
'title',
'first_name',
'last_name',
'birthdate',
'email',
'email_candidate',
'home_phone',
'mobile_phone',
'gender',
'language',
'username',
'password',
'is_patient',
)
extra_kwargs = {
'email': {'required': False,
'validators': [],
#'read_only': True,
},
'email_candidate': {'required': False,
'validators': [],
#'read_only': True,
},
'home_phone': {'required': False,
'validators': [], },
'mobile_phone': {'required': False,
'validators': [], },
'is_patient': {'required': False},
'username': {'read_only': True, },
}
def update_candidate_email(self, instance, validated_data, email_candidate):
# if email candidate is None (and changed) -> search for tokens and delete token sent
if instance.email_candidate and email_candidate == None:
instance.email_candidate = email_candidate
instance.save()
ResetPasswordToken.objects.filter(user=instance).delete()
# if email candidate is same to current email -> error - email in use !
if instance.email_candidate == instance.email:
raise serializers.ValidationError(
{'email':
"email candidate cannot be same to current mail"}
)
# if email candidate is not None and already not in use-> save it (email candidate) and send new email replace_email_mail
if email_candidate and email_candidate != instance.email_candidate:
if User.objects.filter(email=email_candidate):
raise serializers.ValidationError(
{'email': "email in use"}
)
ResetPasswordToken.objects.filter(user=instance).delete()
instance.email_candidate = email_candidate
instance.save()
site_domain = Site.objects.filter(name__icontains='admin').first()
# create pass token send mail
token = ResetPasswordToken.objects.create(
user=instance,)
tiny_link = shortener.create(instance,
'https://{}/api/users/verifyMail/?lang={}&token={}&region={}&patient={}'.format(
site_domain.domain,
instance.language if instance.language else "en",
token.key,
settings.REGION_PREFIX,
instance.is_patient
)
)
from messaging.notify import Notify
activate(instance.language)
msg_name = 'EMAIL_VERIFICATION'
if not instance.is_patient:
msg_name = 'EMAIL_VERIFICATION_STAFF'
notify = Notify()
notify.send_notification(
msg_name=msg_name,
users_pk=[instance.pk, ],
context={
'tiny_link': 'https://{}/s/{}/?lang={}&region={}'.format(
site_domain.domain,
tiny_link,
instance.language if instance.language else "en",
settings.REGION_PREFIX),
'email_candidate': email_candidate
})
return
admin.py PatientSupportAdmin from there I need to update the email by sending an
email confiramtion to the email_candidate
class PatientSupportAdmin(admin.ModelAdmin):
list_display = ['pk', 'patient', 'patient_email', 'email_candidate' ]
list_display_links = ('pk', 'patient')
def get_queryset(self, request):
qs = super(PatientSupportAdmin, self).get_queryset(request)
return qs.filter(support_consent=True)
fieldsets = (
('User', {
'fields': (
'patient',
'get_gender',
'birthdate',
'home_phone', 'mobile_phone', 'language',
'email', 'username',
'date_modified',
'date_joined',
'status',
'user',
)}),
('Patient', {'fields': ('physician',
'country',
'id_number',
)}),
def patient(self, obj):
return obj.user.get_full_name()
def patient_email(self, obj):
return obj.user.email
def email_candidate(self, obj):
return obj.user.email_candidate
def birthdate(self, obj):
return obj.user.birthdate or ''
def home_phone(self, obj):
return obj.user.home_phone
def mobile_phone(self, obj):
return obj.user.mobile_phone
def email(self, obj):
return obj.user.email
def username(self, obj):
return obj.user.username or ''
actions = [resend_email_verification,
]
admin.py resend_email_verification(), the one i could use but it takes only the
email still registered as user email and not the candidate email to send to
it the email confirmation
def resend_email_verifcation(modeladmin, request, queryset):
for user in queryset:
if 'users/patient' in request.path:
user = user.user
if user.is_patient and not user.patient.is_eligible:
continue
site_domain = Site.objects.filter(name__icontains='admin').first()
token = ResetPasswordToken.objects.create(
user=user, )
reset_password_token_created.send(
sender=modeladmin.__class__, reset_password_token=token)
So the important part to send email in UserSerializer is
if email_candidate and email_candidate != instance.email_candidate:
You can cheat a little bit to reuse that method with a new action in admin
def send_verification_email_for_email_candidate(modeladmin, request, queryset):
for user in queryset:
email_candidate = user.email_candidate
if not email_candidate:
continue # defensive a little bit to ignore other use cases in UserSerializer
user.email_candidate = f'{email_candidate}random' # to trigger the condition above
UserSerializer().update_candidate_email(user, {}, email_candidate)
But I will recommend rewriting the function or copying that logic part here instead

MultipleObjectsReturned at /profile/ get() returned more than one CustomUser -- it returned 2

CustomUser model is storing user account detail. After logging in, the particular user profile must be fetched using the token generated during signup.
I have made phone_number as the primary key and unique attribute is set to True. My code behaves properly when there is only one user but >1 user, data of all existing users are fetched which is why this error is showing up!
Here is the model structure
class CustomUser(AbstractUser):
first_name = models.CharField(null=True, blank=True, max_length= 50)
last_name = models.CharField(null=True, blank=True, max_length= 50)
username = models.CharField(null=True, blank=True, max_length= 12)
phone_number = models.CharField(primary_key=True, max_length= 10,unique=True)
dob = models.CharField(max_length=12, null=True, blank=True)
email = models.EmailField(null=True, blank=True)
address = models.CharField(max_length= 500,null=True, blank=True)
pincode = models.CharField(max_length=10, blank=True,null=True)
state = models.CharField(max_length= 256,null=True, blank=True)
district = models.CharField(max_length= 56,null=True, blank=True)
otp_verified = models.BooleanField(null=True,blank=True, default=False)
date_joined = models.DateTimeField(null=True,blank=True)
last_login = models.DateTimeField(null=True,blank=True)
loyality_level = models.IntegerField(null=True,blank=True)
loyality_points = models.IntegerField(null=True,blank=True)
gender = models.CharField(max_length= 2,null=True, blank=True)
user_type = models.CharField(max_length= 2,null=True, blank=True)
objects = MyUserManager()
search_fields = ("",)
USERNAME_FIELD = 'phone_number'
def __str__(self):
return self.phone_number
#property
def token(self):
return self._generate_jwt_token()
def _generate_jwt_token(self):
return str(AccessToken.for_user(self))
Here is my view for fetching Profile using APIView
class ProfileView(APIView):
authentication_class = [JWTAuthentication]
permission_classes = [IsAuthenticated]
try:
def get(self, request):
print(request)
user = model_to_dict(request.user)
print(user)
del user['password']
return Response({"ok": True, "userData": user},status=200)
except Exception as e:
print("::",e,"::")
Here is the view for user registration/signup
class CreateUserView(APIView):
permission_classes = (AllowAny, )
def post(self, request):
data = request.data
print(data)
first_name = data.get("first_name")
last_name = data.get("last_name")
email = data.get("email")
dob = data.get("dob")
phone_number = data.get("phone_number")
address = data.get("address")
pincode = data.get("pincode")
state = data.get("state")
district = data.get("district")
password = make_password(data.get("password"))
print(data)
try:
if not CustomUser.objects.filter(phone_number=phone_number).exists():
print(email)
print("entered")
if email == "":
user = CustomUser(
first_name=first_name,
last_name=last_name,
email=email,
dob=dob,
phone_number=phone_number,
address=address,
pincode=pincode,
state=state,
district=district,
password=password,
username="user"
)
user.save()
token = user.token
user = model_to_dict(user)
del user["password"]
else:
user = CustomUser(
first_name=first_name,
last_name=last_name,
email=email,
phone_number=phone_number,
address=address,
pincode=pincode,
state=state,
district=district,
password=password,
dob=dob,
username="user"
)
user.save()
token = user.token
user = model_to_dict(user)
del user["password"]
subject = 'Regarding new user registration'
message = f'Hurrah! your registration is officially complete with this process.'
email = EmailMessage(subject,message, to=[email])
email.send()
else:
return Response({"ok": False, "message": "Your number is already registered!"}, status=401)
except Exception as e:
return Response({"ok": False, "message": "Unsuccessful attempt!" + str(e)}, status=401)
return Response({"ok": True, "message": "User created and confirmation mail sent successfully!", "user": user, "token": token},status=200)
Here is the view for an user to login
class LoginView(APIView):
def post(self,request):
phone_number = request.data.get("phone_number")
password = request.data.get("password")
if CustomUser.objects.filter(phone_number=phone_number).exists():
user = CustomUser.objects.get(phone_number=phone_number)
if check_password(password, user.password):
return Response({"user":model_to_dict(user), "token":user.token}, status =200)
else:
return Response({"message":"Invalid credentials"}, status=401)
else:
return Response({"message":"Invalid credentials"}, status=401)
You have a method definition inside a try, thay's not ok. I think you meanth to put the try inside the method.
try:
def get(self, request):
print(request)
user = model_to_dict(request.user)
print(user)
del user['password']
return Response({"ok": True, "userData": user},status=200)
except Exception as e:
print("::",e,"::")

Change Passwod API using Django Custom user model and serializer

I have a Django application hwere I have extended the User model and created a custom user model for registration/login, now I want to implement a Change Password API which will be used in Android/IOS app development. I would get parameters as:
user_id, old_password, new_password
Using these paramters and custom user model and serializer is there any way I could achieve this.
I have tried a sample example for this, but it failed.
Custom Model:
class User(AbstractBaseUser, PermissionsMixin):
objects = UserManager()
name = models.CharField(max_length=100, blank=True, null=True)
email = models.EmailField(unique=True)
created_at = models.DateField(blank=True, null=True, auto_now=True)
phone_no = models.CharField(max_length=14, blank=True, null=True)
user_android_id = models.CharField(max_length=255, blank=True, null=True)
user_fcm_token = models.CharField(max_length=255, blank=True, null=True)
user_social_flag = models.IntegerField(blank=True, null=True)
user_fb_id = models.CharField(max_length=255, blank=True, null=True)
user_android_app_version = models.CharField(max_length=25, blank=True, null=True)
is_admin = models.BooleanField(default=False)
is_staff = models.BooleanField(default=False)
is_superuser = models.BooleanField(default=False)
is_active = models.BooleanField(default=True)
USERNAME_FIELD = 'email'
def __str__(self):
return self.email
User Manager:
class UserManager(BaseUserManager):
use_in_migrations = True
def create_user(self, email, name, phone_no, created_at, user_android_id, user_fcm_token,
user_social_flag, user_fb_id, user_android_app_version, password=None):
cache.clear()
user = self.model(
email=self.normalize_email(email),
phone_no=phone_no,
created_at=created_at,
user_android_id=user_android_id,
user_fcm_token=user_fcm_token,
user_social_flag=user_social_flag,
user_fb_id=user_fb_id,
user_android_app_version=user_android_app_version,
name=name,
)
user.is_admin = False
user.is_staff = True
user.is_superuser = False
user.set_password(password)
user.save(using=self._db)
return user
def create_staffuser(self, email, name, created_at, phone_no, user_android_id, user_fcm_token,
user_social_flag, user_fb_id, user_android_app_version, password):
cache.clear()
user = self.create_user(
email,
# password=password,
created_at=created_at,
phone_no=phone_no,
user_android_id=user_android_id,
user_fcm_token=user_fcm_token,
user_social_flag=user_social_flag,
user_fb_id=user_fb_id,
user_android_app_version=user_android_app_version,
name=name,
)
user.set_password(password)
user.is_staff = True
user.is_admin = False
user.is_superuser = False
user.save(using=self._db)
return user
def create_superuser(self, email, password):
cache.clear()
user = self.model(
email=self.normalize_email(email),
# password=password,
# phone_no=phone_no,
# created_at=created_at,
# user_android_id=user_android_id,
# user_fcm_token=user_fcm_token,
# user_social_flag=user_social_flag,
# user_fb_id=user_fb_id,
# user_android_app_version=user_android_app_version,
# name=name,
)
user.set_password(password)
user.is_admin = True
user.is_staff = False
user.is_superuser = True
user.save(using=self._db)
return user
Custom User Serializer:
class CustomRegisterSerializer(RegisterSerializer):
email = serializers.EmailField(required=False)
password1 = serializers.CharField(required=False, allow_null=True, allow_blank=True)
name = serializers.CharField(required=False, allow_null=True, allow_blank=True)
phone_no = serializers.CharField(required=False, allow_null=True, allow_blank=True)
user_android_id = serializers.CharField(required=False, allow_null=True, allow_blank=True)
user_fcm_token = serializers.CharField(required=False, allow_null=True, allow_blank=True)
user_social_flag = serializers.IntegerField(required=False, allow_null=True)
user_fb_id = serializers.CharField(required=False, allow_null=True, allow_blank=True)
user_android_app_version = serializers.CharField(required=False, allow_null=True, allow_blank=True)
# created_at = serializers.DateField(format="%Y-%m-%d", input_formats=['%Y-%m-%d', 'iso-8601'])
class Meta:
model = User
fields = ('email', 'password', 'name', 'phone_no', 'user_android_id', 'user_fcm_token',
'user_social_flag', 'user_fb_id', 'user_android_app_version')
def get_cleaned_data(self):
super(CustomRegisterSerializer, self).get_cleaned_data()
return {
'password1': self.validated_data.get('password1', ''),
'email': self.validated_data.get('email', ''),
'phone_no': self.validated_data.get('phone_no', ''),
'name': self.validated_data.get('name', ''),
'user_android_id': self.validated_data.get('user_android_id', ''),
'user_fcm_token': self.validated_data.get('user_fcm_token', ''),
'user_social_flag': self.validated_data.get('user_social_flag', ''),
'user_fb_id': self.validated_data.get('user_fb_id', ''),
'user_android_app_version': self.validated_data.get('user_android_app_version', ''),
}
def create(self, validated_data):
user = User.objects.create_user(**validated_data)
return user
ChangePassword API :
class CustomChangePasswordView(APIView):
"""
User Change Password API
"""
def post(self, request):
data = request.data
u_id = data.get('user_id')
old_password = data.get('user_old_password')
new_password = data.get('user_new_password')
user = User.objects.get(id=u_id)
if user.password != old_password:
return Response({"msg":"Invalid Old Password"}, status=status.HTTP_200_OK)
else:
user.set_password(new_password)
return Response({"msg":"Change successfull!"}, status=status.HTTP_201_CREATED)
Error Response I get:
{
"msg": "Invalid Old Password"
}
What am I missing?
Is there another better way for this?
Update in the CustomChangePasswordView code like this:
if user.check_password(old_password):
user.set_password(new_password)
user.save()
return Response({"msg":"Change successfull!"}, status=status.HTTP_201_CREATED)
else:
return Response({"msg":"Invalid Old Password"}, status=status.HTTP_200_OK)
You can check the documentation on check password in here.

How to Remove validation from left table data in django

2nd Screenshot of APIAPI Sample Screenshot
I'm New in Django, i want to help regarding validations in screenshot there is company_name, location, title and user_location fields except user info with proper validation
but i want to remove validations from company_name, location, title and user_location fields how to do?
Please find the above api screenshot and
Please find the below scripts,
views.py
class UserRegistrationView(generics.CreateAPIView):
"""
Register a new user.
"""
queryset = User.objects.all()
permission_classes = (permissions.AllowAny, )
def get_serializer_class(self, user_type=None):
if user_type == 'student':
return StudentRegistrationSerializer
return ProfessionalRegistrationSerializer
def post(self, request, user_type=None, format=None):
serializer_class = self.get_serializer_class(user_type)
serializer = serializer_class(data=request.data, context={'request': request})
if serializer.is_valid(raise_exception=True)
user = serializer.save(work_status=user_type)
token, created = Token.objects.get_or_create(user=user)
data = BasicUserSerializer(user, context={'request': request}).data
data.update({"token": token.key})
return Response(data)
serializes.py
class ProfessionalRegistrationSerializer(serializers.HyperlinkedModelSerializer):
password = serializers.CharField(max_length=20, write_only=True)
experiences = ExperienceSerializer(required=False)
email = serializers.EmailField()
first_name = serializers.CharField(max_length=30)
last_name = serializers.CharField(max_length=30)
class Meta:
model = User
fields = ('url', 'id', 'first_name', 'last_name', 'email', 'password',
'experiences', 'headline')
def validate_email(self, value):
from validate_email_address import validate_email
if User.all_objects.filter(email=value.lower()).exists():
raise serializers.ValidationError('User with this email already exists.')
# if not validate_email(value.lower(), check_mx=True):
# raise serializers.ValidationError('It looks like you may have entered an incorrect email address.')
return value.lower()
def create(self, validated_data):
experiences = validated_data.pop('experiences')
password = validated_data.pop('password')
email = validated_data.pop('email')
user = User.objects.create(
username=email.lower(),
email=email.lower(),
role_id=1)
user.set_password(password)
user.save()
user_location = experiences.pop('user_location')
if hasattr(user, 'location'):
user.location.location = user_location
user.save()
else:
UserLocation.objects.create(user=user, location=user_location)
Experience.objects.create(user=user)
return user
Another serializes.py for Experiance
class ExperienceSerializer(serializers.HyperlinkedModelSerializer):
user_location = LocationField()
location = LocationField()
class Meta:
model = Experience
fields = ('id', 'company_name', 'company', 'description', 'location',
'title', 'start_date', 'end_date', 'is_current', 'user_location')
I want to Remove Validation from company_name, company, description, location, title, start_date, end_date, user_location
actually these fields are second page means after complete the first step users move on second step so second step fields are optional
class ExperienceSerializer(serializers.HyperlinkedModelSerializer):
user_location = LocationField()
location = LocationField()
class Meta:
model = Experience
fields = ('id', 'company_name', 'company', 'description', 'location',
'title', 'start_date', 'end_date', 'is_current', 'user_location')
def create(self, validated_data):
return Experience.objects.create(field_a='value', field_b='value')
in the above class, what should be do to remove validation of
"error_msg": {
"location": [
"Expected a dictionary of items but got type \"str\"."
],
"start_date": [
"Date has wrong format. Use one of these formats instead: YYYY[-MM[-DD]]."
],
"end_date": [
"Date has wrong format. Use one of these formats instead: YYYY[-MM[-DD]]."
],
"user_location": [
"Expected a dictionary of items but got type \"str\"."
]
}
Experience Model
class Experience(models.Model):
"""
"""
user = models.ForeignKey(settings.AUTH_USER_MODEL, related_name='experiences')
company_name = models.CharField(max_length=200, db_index=True, blank=True)
company = models.ForeignKey('organisations.Organisation', null=True, blank=True, on_delete=models.SET_NULL)
description = models.TextField(null=True, blank=True)
location = models.ForeignKey('regions.Location', null=True, blank=True, on_delete=models.SET_NULL)
start_date = models.DateField(null=True, blank=True)
end_date = models.DateField(null=True, blank=True)
title = models.CharField(max_length=200, db_index=True, blank=True)
is_current = models.BooleanField(default=False)
is_associated = models.BooleanField(default=False)
created_at = models.DateTimeField(_('created at'), auto_now_add=True)
modified_at = models.DateTimeField(_('modified at'), auto_now=True)
class Meta:
db_table = 'experience'
verbose_name = _('experience')
verbose_name_plural = _('experiences')
ordering = ('-start_date',)
def __str__(self):
return getattr(self, 'title', '')
#property
def experience(self):
if self.end_date:
return (self.end_date - self.start_date).days
else:
return (datetime.datetime.now().date() - self.start_date).days
def get_formated_experience(self):
days = self.experience
total_months = round(days/30)
years = int(total_months/12)
months = round(((total_months/12)%1)*12)
year_txt = 'years' if years > 1 else 'year'
month_txt = 'months' if months > 1 else 'month'
return "%s %s %s %s" %(years, year_txt, months, month_txt)
Location Model
class Location(models.Model):
"""
"""
id = models.TextField(primary_key=True)
display_name = models.TextField(null=True, blank=True)
latitude = models.DecimalField(max_digits=15, decimal_places=10, null=True, blank=True)
longitude = models.DecimalField(max_digits=15, decimal_places=10, null=True, blank=True)
created_at = models.DateTimeField(auto_now_add=True)
objects = LocationManager()
You are getting Two types of validation error according to snapshot.
Field is required
Expected a dictionary and got a string
The required field error occurs when you have set field as required in your model. You can change this by adding blank=True in your model for that field.
For second error, your serializer is expecting a dictionary and you are sending a string. You can remove this validation by writing your custom create method.
class ExperienceSerializer(serializers.HyperlinkedModelSerializer):
user_location = LocationField()
location = LocationField()
class Meta:
model = Experience
fields = ('id', 'company_name', 'company', 'description', 'location',
'title', 'start_date', 'end_date', 'is_current', 'user_location')
def create(self, validated_data):
# you create code for that models.
Your seriailzers will be like this
class ProfessionalRegistrationSerializer(serializers.HyperlinkedModelSerializer):
password = serializers.CharField(max_length=20, write_only=True)
experiences = ExperienceSerializer(required=False)
email = serializers.EmailField()
first_name = serializers.CharField(max_length=30)
last_name = serializers.CharField(max_length=30)
class Meta:
model = User
fields = ('url', 'id', 'first_name', 'last_name', 'email', 'password',
'experiences', 'headline')
def validate_email(self, value):
from validate_email_address import validate_email
if User.all_objects.filter(email=value.lower()).exists():
raise serializers.ValidationError('User with this email already exists.')
# if not validate_email(value.lower(), check_mx=True):
# raise serializers.ValidationError('It looks like you may have entered an incorrect email address.')
return value.lower()
def create(self, validated_data):
experiences = validated_data.get('experiences')
password = validated_data.get('password')
email = validated_data.get('email')
user = User.objects.create(
username=email.lower(),
email=email.lower(),
role_id=1)
user.set_password(password)
user.save()
user_location = experiences.get('user_location')
location_object = None
if user_location:
location_object, created = Location.objects.get_or_create(display_name=user_location.get('display_name'), latitude= user_location.get('latitude'), longitude=user_location.get('longitude'))
user_experience = Experience.objects.create(user=user, company_name=experiences.get('company_name'), location=location_object)
return user
class ExperienceSerializer(serializers.HyperlinkedModelSerializer):
user_location = LocationField()
location = LocationField()
class Meta:
model = Experience
fields = ('id', 'company_name', 'company', 'description', 'location',
'title', 'start_date', 'end_date', 'is_current', 'user_location')

Django REST overrride destroy method to make user inactive

I'm trying to first access the users table via the user foreign key present in userinformations models and later override the RetriveUpdateDestroy API view's destroy method to change the status of the user to inactive instead of deleting them. I can't seem to access the is-active field of the in built User database.
views.py
class UserUpdateApiView(RetrieveUpdateDestroyAPIView):
queryset = UserInformation.objects.all()
serializer_class = UserInformationUpdateSerializer
lookup_field = 'pk'
lookup_url_kwarg = 'id'
def destroy(self, request, *args, **kwargs):
try:
user = User.objects.get(pk=self.kwargs["id"])
deleteStatusVal = False
user.is_active = deleteStatusVal
user.save()
return Response(UserSerializer(user).data)
except:
return Response("Nope")
serializers.py
class UserSerializer(ModelSerializer):
password = serializers.CharField(style={'input_type': 'password'}, write_only=True)
email = serializers.EmailField(validators=[required])
class Meta:
model = User
fields = ['username', 'email', 'password', 'is_active']
extra_kwargs = {'password': {'write_only': True},
'is_active': {'read_only': True}}
def validate(self, data):
email = data.get('email', None)
user = User.objects.filter(email=email).distinct()
if user.exists():
raise ValidationError("That email is already registered!")
return data
class UserInformationUpdateSerializer(ModelSerializer):
user = UserSerializer(read_only=True)
class Meta:
model = UserInformation
fields = ['user', 'first_name', 'middle_name', 'last_name', 'phone', 'date_of_birth']
models.py
class UserInformation(BaseModel):
user = models.OneToOneField(User, related_name='user_id')
first_name = models.CharField(max_length=45)
middle_name = models.CharField(max_length=45, null=True)
last_name = models.CharField(max_length=45)
vendor = models.BooleanField(default=False)
phone = models.CharField(max_length=100, validators=[
RegexValidator(regex=r'^\+?8801?\d{9}$', message="Phone number must be entered in the format: '+8801*********'")
], blank=False, unique=True)
date_of_birth = models.DateField()
confirmation_token = models.CharField(max_length=45, null=True)
confirmation_exp = models.DateTimeField(null=True)
pw_reminder_token = models.CharField(max_length=45, null=True)
pw_reminder_exp = models.DateTimeField(null=True)
profile_pic = models.ImageField(blank=True, null=True, upload_to='profile_images/', default='Images/none/no_images.jpg')
cover_photo = models.ImageField(blank=True, null=True, upload_to='cover_images/', default='Images/none/no_images.jpg')
thumbnail_pic = models.ImageField(blank=True, null=True, upload_to='thumbnail_images/', default='Images/none/no_images.jpg')
phone_verified = models.BooleanField(default=False)
email_verified = models.BooleanField(default=False)
reward_points = models.IntegerField(null=False)
ref_code = models.CharField(null=True, max_length=10)
def __str__(self):
return self.user.username
def delete(self, *args, **kwargs):
self.user.delete()
super(UserInformation, self).delete(*args, **kwargs)
If you want to make User as in active while keeping the UserInformation object and Userobject un-deleted in database, you can do something like this:
def destroy(self, request, *args, **kwargs):
user = self.get_object().user
user.is_active = False
user.save()
return Response(UserInformationUpdateSerializer(self.get_object()).data)
You have 'is_active': {'read_only': True}}.
Also,
# this seems redundant
def delete(self, *args, **kwargs):
self.user.delete()
super(UserInformation, self).delete(*args, **kwargs)