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)
Related
I'm trying to use django filter with APIVIew like I saw in this post and I'm geting an unexpected behavior:
If the word passed on filter doesn't exists, it return nothing - OK
If the word passed on filter exists, it return the complete queryset.
I tried to use filters with ModelViewSet before and it works, but I have no success with APIView. I'm using the following code:
views:
from rest_framework import status
from rest_framework.response import Response
from rest_framework.views import APIView
from core.models import Profile
from core.serializers import ProfileSerializer
from django_filters.rest_framework import DjangoFilterBackend
class ProfileFilter(DjangoFilterBackend):
def filter_queryset(self, request, queryset, view):
filter_class = self.get_filter_class(view, queryset)
if filter_class:
return filter_class(request.query_params, queryset=queryset, request=request).qs
return queryset
class ListProfileView(APIView):
serializer_class = ProfileSerializer
filter_fields = ('nome', 'link')
queryset = Profile.objects.all()
def get(self, request, format=None):
queryset = Profile.objects.all()
ff = ProfileFilter()
filtered_queryset = ff.filter_queryset(request, queryset, self)
if filtered_queryset.exists():
serializer = self.serializer_class(queryset, many=True)
return Response(serializer.data, status=status.HTTP_200_OK)
else:
return Response([], status=status.HTTP_200_OK)
def post(self, request, format=None):
serializer = self.serializer_class(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)
model:
from django.db import models
class Profile(models.Model):
nome = models.CharField(max_length=200, null=False, blank=False)
link = models.CharField(max_length=200, null=False, blank=False)
serializers:
from rest_framework.serializers import ModelSerializer
from core.models import Profile
class ProfileSerializer(ModelSerializer):
class Meta:
model = Profile
fields = '__all__'
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)
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)
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()
When I am calling is_valid on my serializer, some of the data passed to the serializer is not getting saved. The files field is available in the serializer.initial_data, but does not get saved in serializer.validated_data. Any ideas?
Serializer:
class SomeSerializer(serializers.Serializer):
email = serializers.EmailField()
files = serializers.ListField(
child=serializers.FileField()
)
And the following view:
class SomeView(mixins.CreateModelMixin, generics.GenericAPIView):
permission_classes = (permissions.IsAuthenticated,)
serializer_class = SomeSerializer
def post(self, request, *args, **kwargs):
serializer = self.get_serializer(data=request.data)
serializer.is_valid(raise_exception=True)
email = serializer.validated_data["email"]
files = serializer.validated_data.get("files")
#Do something here
return response