This is my UserProfile model,
class UserProfile(models.Model):
user = models.OneToOneField(User, related_name='profile', on_delete=models.CASCADE, )
badge = models.ImageField(upload_to='media/badges/', null=True)
reputation = models.IntegerField(default=0)
status = models.CharField(max_length=255, null=True, blank=True)
thumbnail = models.ImageField(upload_to='media/user/', blank=True, null=True)
And this is the Serializer class,
class UserProfileSerializer(serializers.ModelSerializer):
thumbnail = serializers.ImageField(max_length=None, use_url=True)
class Meta:
model = models.UserProfile
fields = ('badge', 'reputation', 'status', 'thumbnail',)
My API to update an image looks like this,
class CreateUpdateUserThumbnail(views.APIView):
def post(self, request, **kwargs):
try:
user = User.objects.get(id=kwargs.get('user_id'))
except User.DoesNotExist:
return Response({"Error": "User does not exist"}, status=status.HTTP_404_NOT_FOUND)
request.data['user_id'] = user.id
serializer = UserProfileSerializer(data=request.data)
if serializer.is_valid():
serializer.save()
return Response(serializer.data, status=status.HTTP_201_CREATED)
else:
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
This is the error that I get when I try to upload an image using POSTMAN.
return Database.Cursor.execute(self, query, params)
django.db.utils.IntegrityError: NOT NULL constraint failed: bouncer_userprofile.user_id
How do I associate a user_id with the serializer data?
the request.data is immutable so you should to create the copy first:
data = request.data.copy()
data['user_id'] = user.id
serializer = UserProfileSerializer(data=data)
You need to pass user_profile instance on UserProfileSerializer instantiation
serializer = UserProfileSerializer(instance=user.profile, data=request.data)
Your view will look like this
class CreateUpdateUserThumbnail(views.APIView):
def post(self, request, **kwargs):
try:
user = User.objects.get(id=kwargs.get('user_id'))
except User.DoesNotExist:
return Response({"Error": "User does not exist"}, status=status.HTTP_404_NOT_FOUND)
serializer = UserProfileSerializer(instance=user.profile, data=request.data)
if serializer.is_valid():
serializer.save()
return Response(serializer.data, status=status.HTTP_201_CREATED)
else:
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
Related
After user-registration, user wants to post data into Client model ( OnetoOne relationship with User model ). So, I want to access the requested user object inside the serializer-class to create a new row in Client model associated with the requested user.
models.py
class Client(models.Model):
user= models.OneToOneField(User, on_delete=models.CASCADE, null=False, blank=False)
sex = models.CharField(max_length = 6, blank=False, null=False)
location = models.CharField(max_length = 30, null = False, blank = False)
views.py
class ClientRegister(GenericAPIView):
def post(self, request):
user = request.user
serializer = ClientSerializer(data= request.data)
if serializer.is_valid():
serializer.save()
return Response(status= status.HTTP_201_CREATED)
else:
return Response(data= 'Invalid Form', status= status.HTTP_400_BAD_REQUEST)
serializers.py
class ClientSerializer(serializers.ModelSerializer):
class Meta:
model = Client
fields = ['sex', 'location']
def create(self, validated_data):
sex = validated_data.get('sex')
location = validated_data.get('location')
user = #------ Want requested user object here ------#
if user.is_client:
client = Client(user=user, sex=sex, location=location)
client.save()
return client
I have manually added user oject into the data in serializer = CientSerializer(data=request.data).
But, It didn't work. Please, tell me how to pass it from views.py or how to access it in serializers.py.
Pass user when you do serializer.save in post method of views like
def post(self, request):
u = request.user
serializer = ClientSerializer(data= request.data)
if serializer.is_valid():
serializer.save(user=u)
return Response(status= status.HTTP_201_CREATED)
else:
return Response(data= 'Invalid Form', status= status.HTTP_400_BAD_REQUEST)
Or you can read about passing context from views to serializers and in this context you can pass your required data like -
serializer = ClientSerializer(context = {'request':request}, data=request.data)
then you can have your request object in your serializers and you can get request.user or directly pass it in the context.
Try to pass the user with sex and location in views
class ClientRegister(GenericAPIView):
def post(self, request):
data = request.data
user = request.user
#add user in key
data['user']=user
serializer = ClientSerializer(data=data)
if serializer.is_valid():
serializer.save()
return Response(status= status.HTTP_201_CREATED)
else:
return Response(data= 'Invalid Form', status= status.HTTP_400_BAD_REQUEST)
serializer:
class ClientSerializer(serializers.ModelSerializer):
class Meta:
model = Client
fields = '__all__'
views.py
class ClientRegister(GenericAPIView):
def post(self, request):
user = request.user
serializer = ClientSerializer(context={'user':user}, data= request.data)
if serializer.is_valid():
serializer.save()
return Response(status= status.HTTP_201_CREATED)
else:
return Response(data= 'Invalid Form', status= status.HTTP_400_BAD_REQUEST)
serializers.py
class ClientSerializer(serializers.ModelSerializer):
class Meta:
model = Client
fields = ['sex', 'location']
def create(self, validated_data):
sex = validated_data.get('sex')
location = validated_data.get('location')
user = self.context.get('user')
if user.is_client:
client = Client(user=user, sex=sex, location=location)
client.save()
return client
I've been trying to create a APIView for a post request that saves an image and retrieves the user value in the request to fill one of the fields of the model. However, I've been stuck as all I've been getting here was PlotImage has no user.
How do I pass the current user model in the request to a serializer ?
Models.py
class AppUser(AbstractUser):
email = models.EmailField(...)
....
class ImageModel(models.Model):
image = models.ImageField(...)
user = models.ForeignKey(AppUser,on_delete=models.CASCADE)
mix_id = models.IntegerField()
plot_id = models.IntegerField()
Serializer.py
def PlotImagesInputSerializer(serializers.ModelSerializer):
class Meta:
model = ImageModel
fields = ('plot_id','image','mix_id')
view.py
class MixImagesCreateView(APIView):
parser_classes = [MultiPartParser, FormParser]
permission_classes = (permissions.IsAuthenticated,)
def post(self, request, format=None):
serializer = PlotImagesInputSerializer(data=request.FILES, partial=True)
if serializer.is_valid():
serializer.save()
return Response(serializer.data, status=status.HTTP_201_CREATED)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
You need to save the requested user in ImageModel inside your post method in view.py
Try as follows:
serializer.save(user=self.request.user)
Full code
class MixImagesCreateView(APIView):
parser_classes = [MultiPartParser, FormParser]
permission_classes = (permissions.IsAuthenticated,)
def post(self, request, format=None):
serializer = PlotImagesInputSerializer(data=request.FILES, partial=True)
if serializer.is_valid():
serializer.save(user=self.request.user)
return Response(serializer.data, status=status.HTTP_201_CREATED)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
I got an error message: HyperlinkedIdentityField requires the request in the serializer context. Add context={'request': request} when instantiating the serializer. when I'm using API to get data. What am I doing wrong here?
models.py
class User(AbstractUser):
username = models.CharField(blank=True, null=True, max_length=255)
email = models.EmailField(_('email address'), unique=True)
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = ['username', 'first_name', 'last_name']
def __str__(self):
return "{}".format(self.email)
class UserProfile(models.Model):
user = models.OneToOneField(settings.AUTH_USER_MODEL, on_delete=models.CASCADE, related_name='profile')
title = models.CharField(max_length=5)
dob = models.DateField()
address = models.CharField(max_length=255)
country = models.CharField(max_length=50)
city = models.CharField(max_length=50)
zip = models.CharField(max_length=5)
photo = models.ImageField(upload_to='uploads', blank=True, )
serializers.py
class UserProfileSerializer(serializers.ModelSerializer):
class Meta:
model = UserProfile
fields = ('title', 'dob', 'address', 'country', 'city', 'zip', 'photo')
class UserSerializer(serializers.HyperlinkedModelSerializer):
profile = UserProfileSerializer(required=True)
class Meta:
model = User
fields = ('url', 'email', 'first_name', 'last_name', 'password', 'profile')
extra_kwargs = {'password': {'write_only': True}}
def create(self, validated_data):
profile_data = validated_data.pop('profile')
password = validated_data.pop('password')
user = User(**validated_data)
user.set_password(password)
user.save()
UserProfile.objects.create(user=user, **profile_data)
return user
def update(self, instance, validated_data):
profile_data = validated_data.pop('profile')
profile = instance.profile
instance.email = validated_data.get('email', instance.email)
instance.save()
profile.title = profile_data.get('title', profile.title)
profile.dob = profile_data.get('dob', profile.dob)
profile.address = profile_data.get('address', profile.address)
profile.country = profile_data.get('country', profile.country)
profile.city = profile_data.get('city', profile.city)
profile.zip = profile_data.get('zip', profile.zip)
profile.photo = profile_data.get('photo', profile.photo)
profile.save()
return instance
And views.py
class UserList(ListCreateAPIView):
'''
Return list all users or create a new user
'''
serializer_class = UserSerializer
pagination_class = CustomPagination
def get_queryset(self):
try:
user = User.objects.all()
return user
except:
content = {
'status': 'Not Found'
}
return Response(content, status=status.HTTP_404_NOT_FOUND)
def get(self, request):
users = self.get_queryset()
paginate_queryset = self.paginate_queryset(users)
serializer = self.serializer_class(paginate_queryset, many=True)
return self.get_paginated_response(serializer.data, )
def post(self, request):
try:
serializer = UserSerializer(data=request.data)
if serializer.is_valid():
serializer.save()
return Response(serializer.data, status=status.HTTP_201_CREATED)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
except:
content = {
'status': 'Failed to create new user'
}
return Response(content, status=status.HTTP_400_BAD_REQUEST)
class UserDetail(RetrieveUpdateDestroyAPIView):
def get_queryset(self, pk):
try:
user = User.objects.get(pk=pk)
return user
except User.DoesNotExist:
content = {
'status': 'Not Found'
}
return Response(content, status=status.HTTP_404_NOT_FOUND)
def get(self, request, pk):
try:
user = self.get_queryset(pk)
serializer = UserSerializer(user)
return Response(serializer.data, status=status.HTTP_200_OK)
except NameError:
content = {
'status': 'Failed to get user'
}
return Response(content, status=status.HTTP_400_BAD_REQUEST)
def put(self, request, pk):
try:
user = self.get_queryset(pk)
serializer = UserSerializer(user, request.data)
if serializer.is_valid():
serializer.save()
return Response(serializer.data, status=status.HTTP_200_OK)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
except:
content = {
'status': 'Failed to modify user'
}
return Response(content, status=status.HTTP_400_BAD_REQUEST)
def delete(self, request, pk):
try:
user = self.get_queryset(pk)
user.delete()
return Response("Delete user: " +user.username +"successfully",
status=status.HTTP_200_OK)
except:
content = {
'status': 'Failed to delete user'
}
return Response(content, status=status.HTTP_400_BAD_REQUEST)
I'm try using this
class UserViewSet(viewsets.ModelViewSet):
queryset = User.objects.all()
serializer_class = UserSerializer
and It's worked. I don't know why there is a difference. If I add context={'request': request} to my code. I will get a new error. It's very uncomfortable
I made APIs to create update case But the problem is with task if I pass only one pk like(task=1) while updating or creating through postman then it works fine and case will be created with referencing that task but a task is a manytomany field I need to assign multiple task pk to a case like task = [1,2] Then it is giving error like
"Incorrect type. Expected pk value, received str."
]
class Case(models.Model):
name = models.CharField(max_length=200)
task = models.ManyToManyField('task.Task',blank=True, null=True)
assigned_to = models.ForeignKey("account.User",null=True, blank=True, on_delete=models.SET_NULL)
class CaseSerializer(serializers.ModelSerializer):
class Meta:
model = Case
fields = ('id', 'name', 'task', 'assigned_to')
class CaseCreateView(APIView):
permission_classes = (IsAuthenticated,)
#access_permission('case_create')
def post(self, request, format=None):
serializer = CaseSerializer(data=request.data)
if serializer.is_valid():
serializer.save()
return Response(serializer.data, status=status.HTTP_201_CREATED)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
class CaseUpdateView(APIView):
permission_classes = (IsAuthenticated,)
model = Case
#access_permission('case_edit')
def put(self, request,pk, format=None):
case = get_object(self,pk)
serializer = CaseSerializer(case,data=request.data)
if serializer.is_valid():
serializer.save()
return Response(serializer.data, status=status.HTTP_201_CREATED)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
i'm new in DRF too and most of time i just using Generic but i will try maybe helping you. add read_only_fields=(task, ) in your serializer and then we will adding tasks to Case instance manually.by this way in create method we don't need to 'task' and serializer will be valid.
serializer.py:
class CaseSerializer(serializers.ModelSerializer):
class Meta:
model = Case
fields = ('id', 'name', 'task', 'assigned_to')
read_only_fields = ('task', )
class CaseUpdateView(APIView):
permission_classes = (IsAuthenticated,)
model = Case
#access_permission('case_edit')
def put(self, request,pk, format=None):
case = get_object(self,pk)
serializer = CaseSerializer(case,data=request.data)
if serializer.is_valid():
serializer.save()
task_id_list = request.data['tasks_id'] # depending on request
for task_id in task_id_list: # this way we can add to M2M field manually
task = Task.object.get(id=task_id)
case.task.add(task)
return Response(serializer.data, status=status.HTTP_201_CREATED)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
I have created an api where one can upload pic for profile along with rest of the details. My problem is that if one wants to change the pic, how can it be done.
At present, I am able to save pic for the first time.
models.py
class Profile(models.Model):
User = get_user_model()
branch = models.CharField(max_length=20, null=True)
year = models.IntegerField(null=True)
image = models.ImageField(upload_to="accounts/images/", null=True, blank=True)
user = models.OneToOneField(
User,
on_delete=models.CASCADE,
primary_key=False,
null=True
)
views.py
class ProfileView(APIView):
permission_classes = (IsAuthenticated,)
serializer_class = ProfileSerializer
queryset = Profile.objects.all()
def post(self, request, format=None):
current_user = request.user
param = request.data
profile = Profile.objects.filter(user=current_user.pk)
if profile:
serializer = ProfileSerializer(profile, many=True)
return Response(serializer.data)
else:
serializer = ProfileSerializer(data=param)
if serializer.is_valid(raise_exception=True):
serializer.save(user=current_user)
new_data = serializer.data
return Response(new_data)
return Response(serializer.errors, status=HTTP_400_BAD_REQUEST)
class ProfileView(APIView):
permission_classes = (IsAuthenticated,)
def post(self, request, format=None):
try:
# exist then update
profile = Profile.objects.get(user=request.user)
serializer = ProfileSerializer(profile, data=request.data, partial=True)
if serializer.is_valid():
serializer.save()
return Response(serializer.data)
else:
return Response(serializer.errors, status=HTTP_400_BAD_REQUEST)
except Profile.DoesNotExist:
# not exist then create
serializer = ProfileSerializer(data=param)
if serializer.is_valid():
serializer.save(user=request.user)
return Response(serializer.data)
else:
return Response(serializer.errors, status=HTTP_400_BAD_REQUEST)
or just use UpdateAPIView:
class ProfileView(UpdateAPIView):
permission_classes = (IsAuthenticated,)
serializer_class = ProfileSerializer
queryset = Profile.objects.all()