User objects has no attribute profile - django

Can anybody explain me why am in getting this error.
I have two models User and Profile with OnetoOne relations.
models.py
class User(AbstractBaseUser):
phone_number = models.IntegerField(unique=True, verbose_name='phone number')
email = models.EmailField()
class Profile(models.Model):
user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE,)
first_name = models.CharField(max_length=25)
last_name = models.CharField(max_length=25)
and here's the serializer.py
class ProfileSerializer(serializers.ModelSerializer):
class Meta:
model = Profile
fields =["first_name", "last_name"]
class UserSerializer(serializers.ModelSerializer):
profile = ProfileSerializer()
class Meta:
model = User
fields = ["id", "phone_number", "email", "profile",]
Views.py
class UserDetailsView(generics.RetrieveUpdateAPIView):
serializer_class = UserSerializer
def get_queryset(self):
return User.objects.filter(pk=self.kwargs['pk'])

You write the serializer in wrong way. The profile model has user column & user table doesn't have profile column and one thing Use OneToOne filed when creating a profile model against a user. Because one profile can contain one user.
models.py
class User(AbstractBaseUser):
phone_number = models.IntegerField(unique=True, verbose_name='phone
number')
email = models.EmailField()
class Profile(models.Model):
user = models.OneToOneField(settings.AUTH_USER_MODEL,
on_delete=models.CASCADE,)
first_name = models.CharField(max_length=25)
last_name = models.CharField(max_length=25)
serializers.py
class UserSerializer(serializers.ModelSerializer):
class Meta:
model = User
fields = ["id", "phone_number", "email"]
class ProfileSerializer(serializers.ModelSerializer):
user = UserSerializer()
class Meta:
model = Profile
fields =["first_name", "last_name", "user"]
for more information about nested serializer please follow the official documentation

Related

retrieving the last instance of a model in another model's modelSerializer in django rest framework

I am creating rest APIs for a website in which users can purchase one of the provided subscriptions.
In this website there is a user-info API which returns the information about the logged in user which can be used to show their info on the website.
The problem is that, the mentioned API's serializer is a modelSerializer on the "User" model and the information that I want to return is the instance of "Subscription" model which the latest instance of "SubPurchase" model refers to.
These are my serializers, models and views.And I need to somehow return the user's current subscription's ID and name along with the user's information. If you have any further questions, ask me in the comments and I'll answer them.
# models.py
class User(AbstractBaseUser, PermissionsMixin):
userID = models.AutoField(primary_key=True)
username = models.CharField(max_length=100, unique=True, validators=[RegexValidator(regex="^(?=[a-z0-9._]{5,20}$)(?!.*[_.]{2})[^_.].*[^_.]$")])
email= models.EmailField(max_length=100, unique=True, validators=[EmailValidator()])
name = models.CharField(max_length=100)
isSuspended = models.BooleanField(default=False)
isAdmin = models.BooleanField(default=False)
emailActivation = models.BooleanField(default=False)
balance = models.IntegerField(default=0)
objects = UserManager()
USERNAME_FIELD = 'username'
class Subscription(models.Model):
subID = models.AutoField(primary_key=True)
nameOf = models.CharField(max_length=50)
price = models.PositiveIntegerField()
salePercentage = models.PositiveIntegerField(default=0)
saleExpiration = models.DateTimeField(default=datetime.datetime.now, blank=True)
def __str__(self):
return f"{self.nameOf}"
class SubPurchase(models.Model):
price = models.PositiveIntegerField()
dateOf = models.DateTimeField(auto_now_add=True)
user = models.ForeignKey(User, null=True, on_delete=models.SET_NULL)
subscription = models.ForeignKey(Subscription, null=True, on_delete=models.SET_NULL)
def __str__(self):
return self.subscription
# serializers.py
class UserInfoSerializer(serializers.ModelSerializer):
class Meta:
model = get_user_model()
fields = ('userID', 'username','email', 'name', 'balance', 'emailActivation', 'isSuspended')
read_only_fields = ('userID', 'username','email', 'name', 'balance', 'emailActivation', 'isSuspended')
# views.py
class UserInfoViewSet(viewsets.ModelViewSet):
queryset = get_user_model().objects.all()
serializer_class = UserInfoSerializer
def get_queryset(self):
uID = getattr(self.request.user,'userID')
return get_user_model().objects.filter(userID=uID)
def get_object(self):
uID = getattr(self.request.user,'userID')
return self.queryset.filter(userID=uID)
Again, I need to change the UserInfoSerializer in a way that would give me the user's current subscription's name, ID and expiration date which would be 30 days after the purchase date
If you are only interested in the returned data, you can override the function to_representation of your serializer and create a serializer for your related model. If I understood correctly, the current subscription of your user is the last one (if sorted by "dateOf"). So something like that could do the trick
class SubscriptionSerializer(serializers.ModelSerializer):
class Meta:
model = Subscription
fields = ('nameOf', 'id', 'saleExpiration ')
class UserInfoSerializer(serializers.ModelSerializer):
class Meta:
model = get_user_model()
fields = ('userID', 'username','email', 'name', 'balance', 'emailActivation', 'isSuspended')
read_only_fields = ('userID', 'username','email', 'name', 'balance', 'emailActivation', 'isSuspended')
def to_representation(self, instance):
data = super().to_representation(instance)
current_subs = instance.subpurchase_set.order_by('dateOf').last().subscription
data['current_subscription'] = SubscriptionSerializer(instance=current_subs).data
return data
you can use NestedSerializers to achieve what you are looking for
basically, nested serialization is a method in which you can return, create, put..., into a model from another model, it goes like this..
models.py
class User(AbstractBaseUser, PermissionsMixin):
....
#user model data
class SubPurchase(models.Model):
...
user = models.ForeignKey(User, null=True, blank=True, on_delete=models.CASCADE)
serializers.py
class SubscriptionSerializer(serializers.ModelSerializer):
class Meta:
model = Subscription
fields =["anyfield you wanna include"]
class SubPurchaseSerializer(serializers.ModelSerializer):
class Meta:
model = SubPurchase
fields =["anyfield you wanna include"]
class UserInfoSerializer(serializers.ModelSerializer):
subpurchace = SubPurchaseSerializer()
subscription= SubscriptionSerializer() #later included in the fields of this serializer
class Meta:
model = get_user_model()
fields = ('userID','subpurchace', 'subscription', 'username','email', 'name', 'balance', 'emailActivation', 'isSuspended')
read_only_fields = ('userID', 'username','email', 'name', 'balance', 'emailActivation', 'isSuspended')

how to add current active user as foreign key to the create post model in djangorestframework?

how to add current active user as foreign key to the create post model in djangorestframework ?
models:
class DoctorProfile(AbstractBaseUser, PermissionsMixin):
id=models.AutoField(primary_key=True)
name = models.CharField(_('name'), max_length=50, blank=True)
mobile = models.CharField(_('mobile'), unique=True, max_length=10, blank=False)
email = models.EmailField(_('email address'), blank=True)
password = models.CharField(_('password'),max_length=25,blank=False)
otp = models.IntegerField(null=True, blank=True)
class Doctor_clinic(models.Model):
clinic_id = models.AutoField(primary_key=True)
doc_profile = models.ForeignKey(DoctorProfile,on_delete=models.CASCADE)
clinic_name = models.CharField(max_length=150)
clinic_address = models.CharField(max_length=150)
City = models.CharField(max_length=50)
state = models.CharField(max_length=50)
pincode = models.IntegerField()
#how to get the forign key in serializers
I wrote in this way, is this correct/relevent?
class UserSerializer(serializers.ModelSerializer):
# mobile = serializers.RegexField("[0-9]{10}",min_length=10,max_length=10)
password = serializers.CharField(write_only=True)
email=serializers.EmailField(max_length=155,min_length=3,required=True)
name=serializers.CharField(max_length=55,min_length=3,required=True)
class Meta:
model = DoctorProfile
fields = ("name", "email", "password", "mobile","otp")
class ClinicSerializer(serializers.ModelSerializer):
class Meta:
model = Doctor_clinic
fields =('clinic_name','clinic_address', 'City', 'state', 'pincode','doc_profile')
views:
class ClinicRegistrationView(generics.ListCreateAPIView):
serializer_class = ClinicSerializer
queryset = Doctor_clinic.objects.all()
permission_classes = (IsAuthenticated,)
When serializing relations you need to define a seperate field depending on the representation you want, for example write your serializer like this:
class ClinicSerializer(serializers.ModelSerializer):
doc_profile = serializers.StringRelatedField()
class Meta:
model = Doctor_clinic
fields =('clinic_name','clinic_address', 'City', 'state', 'pincode','doc_profile')
permissions.py
use permission classes
class IsOwner(permissions.BasePermission):
def has_object_permission(self, request, view, obj):
return obj.doc_profile == request.user
views.py
def perform_create(self, serializer):
return serializer.save(doc_profile=self.request.user)

How to update Foreign key field using nested serializer in django

I am facing one issue for updating models using django serializer.
Here is my models:
class User(models.Model):
email = models.EmailField(unique=True)
first_name = models.CharField(max_length=30)
last_name = models.CharField(max_length=30)
class UserProfile(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
designation = models.CharField(max_length=200, blank=True)
contact_number = models.CharField(max_length=20, blank=True)
team = models.CharField(max_length=200, blank=True)
manager = models.CharField(max_length=200, blank=True)
joining_date = models.DateField(default=datetime.now)
I need to create a serializer for editing profile details of the current user. In this User details like designation, contact_number , team , manager, joining_date are in UserProfile model and te first_name and last_name are in User model .... At one edit both the models needs to get update
This is my serializer.
class UserSerializer(ModelSerializer):
class Meta:
model = User
fields = ('id', 'first_name','last_name')
class UserProfileSerializer(ModelSerializer):
user = UserSerializer()
class Meta:
model = UserProfile
fields = ('id', 'designation', 'contact_number', 'team', 'manager',
'joining_date','user')
def update(self, instance, validated_data):
user = validated_data.get('user')
instance.user.first_name = user.get('first_name')
instance.user.save()
return instance
I am getting an error {
"user": [
"This field is required."
]
}
Change user field to DictField. In this way, it will not be treated as foreignkey.
In to_representation, serialize user object and you will get data in format in which you want to get.
class UserSerializer(ModelSerializer):
class Meta:
model = User
fields = ('id', 'first_name','last_name')
class UserProfileSerializer(ModelSerializer):
user = serializer.DictField(required=False, write_only=True, default={})
def to_representation(self, instance):
data = super().to_representation(instance)
data.update({'user': UserSerializer(instance.user).data})
return data
class Meta:
model = UserProfile
fields = ('id', 'designation', 'contact_number', 'team', 'manager',
'joining_date','user')
def update(self, instance, validated_data):
user = validated_data.get('user')
instance.user.first_name = user.get('first_name')
instance.user.save()
return instance

Django Rest Framework - OneToOne reverse relation

I have a custom User model and the User Profile model.
class User(AbstractUser):
"""Custom User authentication class to use email as username"""
username = None
email = models.EmailField(verbose_name='email', max_length=255, unique=True,
error_messages={
'unique': _(
"A user is already registered with this email address"),
}, )
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = []
objects = UserManager()
def __str__(self):
return self.email
class UserProfile(models.Model):
user = models.OneToOneField(User, to_field='email', on_delete=models.CASCADE)
emp_id = models.CharField(max_length=20, blank=False, default='0', null=False)
department = models.CharField(max_length=50, blank=True, default='', null=True)
I am trying to write a serializer that combines both these models are produces a nested JSON.
for example:
{
"email":"user#gmail.com",
"is_active":true,
"profile":
{
"emp_id":2,
"department":2
}
}
This is what I tried to do
class UserProfileSerializer(serializers.ModelSerializer):
class Meta:
model = UserProfile
fields = ('id', 'user', 'emp_id', 'department')
class UserPairSerializer(serializers.ModelSerializer):
profile = UserProfileSerializer(read_only=True)
class Meta:
model = User
fields = ('id', 'email', 'is_active', 'profile')
But for some reason, there is neither the field profile in my response nor am I getting any errors.
I tried following this docs: https://www.django-rest-framework.org/api-guide/relations/
What is the issue and how do I solve this?
As per the documentation implicitly refering to this, 'reverse' queries are done using the name of the Model, lowercased (in this case user.userprofile).
So you have two options:
Either you specify a custom related_name on the user field on the UserProfile model.
class UserProfile(models.Model):
user = models.OneToOneField(User, to_field='email', on_delete=models.CASCADE, related_name='profile')
Or, you specify a source argument on your nested serializer (see documentation):
class UserProfileSerializer(serializers.ModelSerializer):
class Meta:
model = UserProfile
fields = ('id', 'user', 'emp_id', 'department')
class UserPairSerializer(serializers.ModelSerializer):
profile = UserProfileSerializer(read_only=True, source='userprofile')
class Meta:
model = User
fields = ('id', 'email', 'is_active', 'profile')

Trying to serialize data from multiple models

I am trying to serialize three django models in a section of my api, but it seems he doesn't like the way I do it .. Im following the documentation of https://www.django-rest-framework.org/api-guide/relations/#nested-relationships
I have tried to create 3 serializers one for each model and then put everything together in the fields of the last
serializers.py
class UserProfileSerializer(serializers.ModelSerializer):
class Meta:
model = UserProfile
fields = ['name', 'user']
class UserCompanySerializer(serializers.ModelSerializer):
class Meta:
model = UserCompany
fields = ['name']
class UserInfoSerializer(serializers.ModelSerializer):
profile = UserProfileSerializer
companys = UserCompanySerializer(many=True)
class Meta:
model = CustomUser
fields = ['email', 'profile', 'companys']
I thought it would work but it returns the error:
ImproperlyConfigured at /user_info
Field name profile is not valid for model CustomUser.
models.py
class UserCompany(models.Model):
name = models.CharField(max_length=150, unique=True)
def __str__(self):
return self.name
class CustomUser(AbstractUser):
username = None
email = models.EmailField(_('email address'), unique=True)
is_active = models.BooleanField(default=False)
companys = models.ForeignKey(UserCompany, on_delete=models.CASCADE, null=True)
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = []
objects = CustomUserManager()
def __str__(self):
return self.email
class UserProfile(models.Model):
name = models.CharField(max_length=300, unique=True)
user = models.OneToOneField(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
def __str__(self):
return self.name