i have my models and everything like this, when i'm trying to upload a Image this is what i got:
'PhotoSerializer' object has no attribute '_committed
My view:
class UploadPhoto(APIView):
#authentication_classes = (TokenAuthentication,)
permission_classes = ()#(IsAuthenticated,)
def put(self, request, username):
user = User.objects.get(username = username)
userprofile = UserProfile.objects.get(user= user)
photo = PhotoSerializer(data = request.data)
userprofile.photo = photo
userprofile.save()
return Response(status= status.HTTP_200_OK)
Serializer:
class PhotoSerializer(serializers.ModelSerializer):
class Meta:
model = UserProfile
fields = (
'photo',
)
And at least my Model.py
class UserProfile(models.Model):
"""
User Profile
"""
user = models.OneToOneField(User, related_name='userprofile')
GENDER_CHOICES = (
('M', 'Male'),
('F', 'Female'),
)
gender = models.CharField(max_length=1, choices=GENDER_CHOICES, default='M')
phone_regex = RegexValidator(regex=r'^\+?1?\d{9,15}$',message="Phone must be entered in the format: '+999999999'. Up 15 digits allowed.")
#The Field on DataBase after check if it's a valid Phone Number.
# validators should be a list
phone_number = models.CharField(validators=[phone_regex], max_length=15, blank=True)
photo = models.ImageField(upload_to = 'photos/', null = True)
driver_passenger = models.BooleanField(default=True)
rides_given = models.IntegerField(default=0)
rides_taken = models.IntegerField(default=0)
reputation = models.IntegerField(default=0)
I tried some options to upload a photo, but I couldn't implemented so I appreciate your help (:
Well, after a little of trying I Could, upload the Image With this
code hope is useful
View.py
class UploadPhoto(APIView):
#authentication_classes = (TokenAuthentication,)
permission_classes = ()#(IsAuthenticated,)
def put(self, request, username):
user = User.objects.get(username = username)
userprofile = UserProfile.objects.get(user= user)
photo = PhotoSerializer(userprofile,data = request.data)
photo.is_valid(raise_exception=True)
photo.save()
return Response(status= status.HTTP_200_OK)
Related
I would like to create my own endpoint for POST request to two related tables. I have two tables User and Userattribute.
models.py
class User(models.Model):
email = models.CharField(unique=True, max_length=180)
roles = models.JSONField(default=dict)
password = models.CharField(max_length=255, blank=True, null=True)
name = models.CharField(max_length=255, blank=True, null=True)
firebase_id = models.CharField(max_length=255, blank=True, null=True)
created_at = models.DateTimeField(default=now)
progress_sub_step = models.IntegerField(blank=True, null=True)
step_available_date = models.DateTimeField(blank=True, null=True)
progress_step = models.IntegerField(blank=True, null=True)
active = models.IntegerField(default=1)
last_login_at = models.DateTimeField(blank=True, null=True)
class Meta:
managed = False
db_table = 'user'
class Userattribute(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE, primary_key=True, related_name = 'attribute')
attribute = models.ForeignKey(Attribute, on_delete=models.CASCADE)
The table Userattribute contains the field user which is OnetoOne to Id primary key from User table.
I tried to implement POST to two tables in serializers.py In the commented section there is a create definition which works perfectly for me. However, I wouldlike to move it to views.py as register_in_course endpoint
serializers.py
class FilmSerializer(serializers.ModelSerializer):
class Meta:
model = Film
fields = ['tytul', 'opis', 'po_premierze']
class UserattributeSerializer(serializers.ModelSerializer):
class Meta:
model = Userattribute
fields = ['user', 'attribute']
class UASerializer(serializers.ModelSerializer):
class Meta:
model = Userattribute
fields = ['attribute']
class UserSerializer(serializers.ModelSerializer):
attribute = UASerializer(many = False)
class Meta:
model = User
fields = ['email', 'name', 'firebase_id', 'attribute']
# This is what workks perfectly for me, and I want to move it to views.py
# VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV
# def create(self, validated_data):
# attribute_data = validated_data.pop('attribute')
# user = User.objects.create(**validated_data)
# Userattribute.objects.create(user=user, **attribute_data)
# return user
Current views.py:
class UserViewSet(viewsets.ModelViewSet):
queryset = User.objects.all()
serializer_class = UserSerializer
#action(detail = False, methods = ['post'])
def register_in_course(self, request, **kwargs):
data = self.get_object()
user = User.objects.create(email=request.data['email'],
name=request.data['name'],
firebase_id=request.data['firebase_id'])
user_id = User.objects.filter(firebase_id = request.data['firebase_id'])['id']
attribute = Userattribute.objects.create(user = user_id, attribute = request.data['attribute']['attribute'])
user = user.attribute.add(attribute)
serializer = UserSerializer(user, many = false)
return Response(serializer.data)
Using endpoint register_in_course to POST I get following error:
Expected view UserViewSet to be called with a URL keyword argument named "pk". Fix your URL conf, or set the .lookup_field attribute on the view correctly.
urls.py
from django.urls import include, path
from django.conf.urls import url
from rest_framework import routers
from api import views
router = routers.DefaultRouter()
router.register(r'users', views.UserViewSet)
router.register(r'userattribute', views.UserattributeViewSet)
urlpatterns = [
url('', include(router.urls))
]
i removed one line user_id variable and changed attribute variable. please check, maybe it should solve your problem, because you have already have Assigned variable as a User object..
class UserViewSet(viewsets.ModelViewSet):
queryset = User.objects.all()
serializer_class = UserSerializer
#action(detail = False, methods = ['post'])
def register_in_course(self, request, **kwargs):
data = self.get_object()
user = User.objects.create(email=request.data['email'],
name=request.data['name'],
firebase_id=request.data['firebase_id'])
attribute = Userattribute.objects.create(user = user, attribute = request.data['attribute']['attribute']) # changed this line
user = user.attribute.add(attribute)
serializer = UserSerializer(user, many = false)
return Response(serializer.data)
This issue is caused by calling get_object in a view that is defined with detail=False:
#action(detail = False, methods = ['post'])
def register_in_course(self, request, **kwargs):
data = self.get_object() # The problem is caused by this line
It seems you don't need this data, as you are using request.data.
So you can define your view like this:
#action(detail = False, methods = ['post'])
def register_in_course(self, request, **kwargs):
user = User.objects.create(
email=request.data['email'],
name=request.data['name'],
firebase_id=request.data['firebase_id']
)
Userattribute.objects.create(
user=user,
attribute = request.data.get('attribute', {}).get('attribute', {})
)
return Response(UserSerializer(user).data)
I am trying to update the user profile in django rest framework
So i am able to create the user profile simultaneously with user creation using signals
Now i am trying to update the profile created:-
//models.py
class User(AbstractBaseUser,PermissionsMixin):
phone_regex=RegexValidator(regex = r'^[6-9]\d{9}$',message='please enter the correct phonenumber')
#name_regex=RegexValidator(regex=r'/^[A-Za-z]+$/',message='Please enter the correct name')
phone=models.CharField(validators=[phone_regex],max_length=15,unique=True)
date_joined=models.DateTimeField(verbose_name='date joined',auto_now_add=True)
last_login=models.DateTimeField(verbose_name='last login',auto_now=True)
active = models.BooleanField(default=True)
staff = models.BooleanField(default=False) # a admin user; non super-user
admin = models.BooleanField(default=False)
first_login=models.BooleanField(default=True)
USERNAME_FIELD='phone'
REQUIRED_FIELDS = []
class UserProfile(models.Model):
# There is an inherent relationship between the Profile and
# User models. By creating a one-to-one relationship between the two, we
# are formalizing this relationship. Every user will have one -- and only
# one -- related Profile model.
GENDER = (
('M', 'Homme'),
('F', 'Femme'),
)
user = models.OneToOneField(
User,related_name="profile", on_delete=models.CASCADE
)
# Each user profile will have a field where they can tell other users
# something about themselves. This field will be empty when the user
# creates their account, so we specify blank=True.
email=models.EmailField(unique=True,validators=[validate_email],max_length=254,blank=True,null=True)
name=models.CharField(max_length=15,blank=True)
dateofbirth=models.DateField(auto_now=False, null=True, blank=True)
Gender=models.CharField(max_length=1, choices=GENDER,blank=True,null=True)
address1 = models.CharField(
"Address",
max_length=1024,
blank=True,
null=True
)
address2 = models.CharField(
"Society",
max_length=1024,
blank=True,
null=True
)
address3 = models.CharField(
"Landmark",
max_length=1024,
blank=True,
null=True
)
zip_code = models.CharField(
"ZIP / Postal code",
max_length=12,
blank=True,
null=True
)
city = models.CharField(
"City",
max_length=1024,
default ="Gurugram",
blank=True,
null=True
)
country = models.CharField(
"Country",
max_length=10,
default="India",
blank=True,
null=True
)
# In addition to the `bio` field, each user may have a profile image or
# avatar. This field is not required and it may be blank.
# A timestamp representing when this object was created.
created_at = models.DateTimeField(auto_now_add=True,blank=True)
# A timestamp representing when this object was last updated.
updated_at = models.DateTimeField(auto_now=True,blank=True)
def __str__(self):
return self.user.phone
#receiver(post_save, sender=User)
def create_profile_for_user(sender, instance=None, created=False, **kargs):
if created:
UserProfile.objects.get_or_create(user=instance)
// Serializer.py
class UserProfileSerializer(serializers.ModelSerializer):
class Meta:
model = UserProfile
fields=("name",)
class UserSerializer(serializers.ModelSerializer):
user = UserProfileSerializer(many=True)
class Meta:
model = User
fields = ('user', 'phone',)
def create(self, validated_data):
user_data = validated_data.pop('user')
user = User.objects.create(**user_data)
profile = user_data.objects.create(user=user, **validated_data)
return profile
def update(self, instance, validated_data):
print("update function")
# profile_data = validated_data.pop('profile')
# print(profile_data)
profile_data = validated_data.pop('user')
profile = instance.profile
# print("profile is ",profile)
print(profile_data.name)
print("name in validation ",validated_data['name'], " type is ",print(type(validated_data)))
instance.username = validated_data.get('name', instance.username)
instance.email = validated_data.get('email', instance.email)
instance.save()
print("name is ",instance.profile.name )
#profile.Gender = validated_data['Gender'],
#profile.email = validated_data['email'],
#profile.dateofbirth=validated_data['dateofbirth'],
#profile.address1=validated_data['address1'],
##profile.address2=validated_data['address2'],
#profile.address3=validated_data['address3']
# print("1",profile)
#print(profile.Gender)
#print(profile.email)
#print(profile.dateofbirth)
profile.save()
print("2",profile)
print(profile.name)
print("save done")
return instance
//views.py
class ProfileCreateAPIView(CreateAPIView):
def put(self, request, *args, **kwargs):
print("my print 0",request)
header_token = request.META.get('HTTP_AUTHORIZATION', None)
print(header_token)
access_token=header_token.split(' ')[1]
status,user =validate_token(access_token)
print(request.data)
user_profile_serializer = UserProfileSerializer(
instance=user,
data=request.data
)
user_serializer = UserSerializer(
instance=user,
data=request.data)
print("my print 1",user_profile_serializer.is_valid())
print("my print 2",user_serializer.is_valid())
if user_profile_serializer.is_valid() and user_serializer.is_valid():
user_profile_serializer.save()
print("user_profile save done")
user_serializer.save()
print("user save done")
return Response(
status=rt_status.HTTP_200_OK)
# Combine errors from both serializers.
# errors = dict()
# errors.update(user_profile_serializer.errors)
#errors.update(user_serializer.errors)
else:
return Response(status=rt_status.HTTP_400_BAD_REQUEST)
'''
return Response(status=rt_status.HTTP_400_BAD_REQUEST)
'''
Now the issue is when i am hitting the api I am getting user_serializer.is_valid() as TRUE but False from UserProfile.
I feel there is some issue with my getting the profile data.
But I am not able to understand how to resolve the issue .
Any help is much appreciated.
I would like to extend Django's user model using a OneToOneField in my Django api project, but I'm getting a weird error. I'm hoping someone can help me out. Below is my code and the error message.
models.py:
class Profile(models.Model):
yearOfExperience = models.PositiveIntegerField(default=1)
profession = models.CharField(max_length=250, blank=True, null=True)
dp = models.URLField(blank=True, null=True)
qualification = models.CharField(max_length=255, blank=True, null=True)
phoneNumber = models.CharField(max_length=255, blank=True, null=True)
#receiver(post_save, sender=CustomUser)
def create_user_profile(sender, instance=None, created=False, **kwargs):
if created:
Profile.objects.create(user=instance)
instance.profile.save()
serializer:
class ProfileSerializer(serializers.ModelSerializer):
id = serializers.IntegerField(source = 'pk', read_only = True)
username = serializers.CharField(source = 'user.username', read_only = True)
email = serializers.CharField(source = 'user.email', read_only=True)
class Meta:
model = Profile
fields = ('id', 'email', 'username', 'yearOfExperience',
'qualification', 'profession', 'phoneNumber'
)
def create(self, validated_data, instance=None):
if 'user' in validated_data:
user_data = validated_data.pop('user')
user = CustomUser.objects.create(**validated_data)
profile = Profile.objects.update_or_create(user=user, **validated_data)
return user
apiView:
class ProfileListView(generics.ListCreateAPIView):
permission_classes = (IsAuthenticatedOrReadOnly,)
queryset = Profile.objects.all()
serializer_class = ProfileSerializer
def perform_create(self, serializer):
serializer.save(user=self.request.user)
Error message:
File "/home/olaneat/Desktop/filez/project/django/funzone/lib/python3.7/site-packages/django/db/models/base.py", line 500, in __init__
raise TypeError("%s() got an unexpected keyword argument '%s'" % (cls.__name__, kwarg))
TypeError: CustomUser() got an unexpected keyword argument 'yearOfExperience'
I believe you're missing the user one to one field to your profile model so
add it there
class Profile(models.Model):
user = models.OneToOneField(CustomUser, on_delete=models.CASCADE)
...
Since you're using post_save for your profile, there's no need for the .create in your serializer. So something like this:
class ProfileSerializer(serializers.ModelSerializer):
username = serializers.SerializerMethodField(read_only = True)
email = serializers.SerializerMethodField(read_only=True)
class Meta:
model = Profile
fields = ('id', 'email', 'username', 'yearOfExperience',
'qualification', 'profession', 'phoneNumber'
)
def get_username(self, obj):
return obj.user.username
def get_email(self, obj):
return obj.user.email
now just post from the API view and the profile will be created.
If however, you want to keep the .create for the option to add new users from the profile API then perhaps something like this:
class ProfileSerializer(serializers.ModelSerializer):
username = serializers.SerializerMethodField(read_only = True)
email = serializers.SerializerMethodField(read_only=True)
class Meta:
model = Profile
fields = ('id', 'email', 'username', 'yearOfExperience',
'qualification', 'profession', 'phoneNumber'
)
def create(self, validated_data, instance=None):
if 'user' in validated_data:
user = validated_data.pop('user')
else:
user = CustomUser.objects.create(**validated_data)
profile, created_profile = Profile.objects.update_or_create(user=user, **validated_data)
return profile
def get_username(self, obj):
return obj.user.username
def get_email(self, obj):
return obj.user.email
I have a registration form which is an extension of UserCreationForm and I have a UserProfileForm. I am rendering both the forms to the same html during user registration.
The problem is, inputs are getting saved to the inbuilt users model but not to the Profile Model. No data is showing up in Profile Model.
I have tried many ways and looked for many solution but unable to find the mistake.
My forms.py looks like this -
class RegistrationForm(UserCreationForm):
email = forms.EmailField(required=True)
first_name = forms.CharField(required=True)
last_name = forms.CharField(required=True)
username = forms.CharField(required=True)
class Meta:
model = User
fields = ['username',
'first_name',
'last_name',
'email',
'password1',
'password2'
]
def save(self,commit):
user = super(RegistrationForm,self).save(commit=False)
if commit:
user.save()
return user
class UserProfileForm(forms.ModelForm):
class Meta:
model = UserProfile
exclude = ['user']
def save(self,commit):
user = super(RegistrationForm,self).save(commit=False)
USN =self.cleaned_data['USN']
year = self.cleaned_data['year']
sem = super(RegistrationForm,self).save(commit=False)
if commit:
user.save()
return user
Have created UserProfile model in models.py
class UserProfile(models.Model):
alphanumeric = RegexValidator(r'^[0-9A-Z]*$', 'Only alphanumeric
characters are allowed.')
user = models.OneToOneField(User, related_name =
'profile',on_delete=models.CASCADE)
USN = models.CharField(max_length=50, blank=True, null=True, validators=
[alphanumeric])
year = models.IntegerField(default=0)
sem = models.IntegerField(default=0)
def __str__(self):
return self.user.username
def create_profile(sender, **kwargs):
if kwargs['created']:
objects=models.Manager()
user_profile = UserProfile.objects.create(user=kwargs['instance'])
post_save.connect(create_profile, sender = User)
I have used both the forms in Views.py -
def register(request):
if request.method == 'POST':
form_1 = RegistrationForm(request.POST)
form_2 = UserProfileForm(request.POST)
if form_1.is_valid() and form_2.is_valid():
save_1 = form_1.save(commit = False)
save_2 = form_1.save(commit = False)
save_1.save()
save_2.save()
return render(request,'main/home.html')
else:
form_1 = RegistrationForm()
form_2 = UserProfileForm()
args = {'form_1':form_1,'form_2':form_2}
return render(request, 'account/register.html',args)
The username in the profile model object shows correctly, but other fields are not getting updated. I want other fields also getting updated in the profile object.
I have form.py with class RegistrationForm and everything works fine but the extra details like email, first and last name, roles is not saved to my account/User profiles but first and last name + emails is saved under AUTHENTICATION AND AUTHORIZATION/Users
I been trying to figure our if I made some mix up with model, form or views.
What could be the problem? Using python 3 with latest django
2nd
3rd
Models.py
class UserProfile(models.Model):
STUDENT = 1
TOURIST = 2
BUSINESS = 3
ADMIN = 4
ROLE_CHOICES = (
(STUDENT, 'Student'),
(TOURIST, 'Tourist'),
(BUSINESS, 'Business'),
(ADMIN, 'Admin'),
)
user = models.OneToOneField(User, on_delete=models.CASCADE)
# first_name = models.CharField(max_length=100, default='')
# last_name = models.CharField(max_length=100, default='')
email = models.EmailField()
phone = models.IntegerField(default=0)
image = models.ImageField(upload_to='image_profile', blank=True)
role = models.PositiveSmallIntegerField(choices=ROLE_CHOICES, null=True, blank=True)
# admin = UserProfileManager()
def __str__(self):
return self.user.username
def create_profile(sender, **kwargs):
if kwargs['created']:
user_profile = UserProfile.objects.create(user=kwargs['instance'])
post_save.connect(create_profile, sender=User)
forms.py
ROLES = ((0, 'Student'), (1, 'Tourist'), (2, 'Business'))
class RegistrationForm(UserCreationForm):
email = forms.EmailField(required=True)
role = forms.ChoiceField(choices=ROLES)
class Meta:
model = User
fields = (
'username',
'first_name',
'last_name',
'email',
'role',
'password1',
'password2'
)
def save(self, commit=True):
user = super(RegistrationForm, self).save(commit=False)
user.first_name = self.cleaned_data['first_name']
user.last_name = self.cleaned_data['last_name']
user.role = self.cleaned_data['role']
user.email = self.cleaned_data['email']
if commit:
user.save()
return user
views.py
def register(request):
if request.method == 'POST':
form = RegistrationForm(request.POST)
if form.is_valid():
form.save()
messages.success(request, 'Your account has been created!')
return redirect(reverse('city:home'))
else:
form = RegistrationForm()
args = {'form': form}
return render(request, 'account/register_form.html', args)
Admin.py
class UserProfileAdmin(admin.ModelAdmin):
list_display = ('user', 'role', 'email')
def user_info(self, obj):
return obj.role
def get_queryset(self, request):
queryset = super(UserProfileAdmin, self).get_queryset(request)
queryset = queryset.order_by('email')
return queryset
role.short_description = 'User Type'
admin.site.register(UserProfile, UserProfileAdmin)
By given screen shots i think you are using allauth library. If you want to use allauth and modify user model then you have to import AbstractUser class of allauth
from django.contrib.auth.models import AbstractUser
class User(AbstractUser):
phone = models.CharField(_('Telephone'), blank=True, max_length=20)
address = models.CharField(_('Address'), blank=True, max_length=255)