CurrentUserDefault doesn't work using Django Rest - django

I'm working with Django / Django Rest Framework and I'm looking for a solution to insert the logged user id automatically.
i tried to use, user = serializers.HiddenField(default=serializers.CurrentUserDefault()) :
But i doesn't work
This is my serializer class
from rest_framework import serializers
from contact.models import Contact
class ContactSerializer(serializers.ModelSerializer):
user = serializers.HiddenField(default=serializers.CurrentUserDefault())
class Meta:
model = Contact
fields = '__all__'
My View :
class ContactView(ListModelMixin, viewsets.GenericViewSet):
queryset = Contact.objects.all()
serializer_class = ContactSerializer
def create(self, request):
serializeObject = ContactSerializer(data = request.data, many=True)
if serializeObject.is_valid():
serializeObject.save()
contactObject = Contact.objects.all()
contactSerializer = ContactSerializer(contactObject, many=True)
return Response(contactSerializer.data, status = status.HTTP_201_CREATED)
return Response(serializeObject.errors, status.HTTP_400_BAD_REQUEST)

When you use CurrentUserDefault you need to pass the request in the context to your serializer as that is where the serializer will get the current user from. See Including extra context [DRF docs]:
class ContactView(ListModelMixin, viewsets.GenericViewSet):
queryset = Contact.objects.all()
serializer_class = ContactSerializer
def create(self, request):
serializeObject = ContactSerializer(data = request.data, many=True, context={'request': request})
...

Related

How can I update specific field after retrieved in django rest framework

How can I update specific field after retrieved in django rest framework
# Models.py
class Article(models.Model):
title = models.CharField(max_length=255)
body = models.TextField()
view = models.IntegerField(default=0)
def __str__(self):
return self.title
I want to update view after read a specific data.
# Views.py
class ArticleDetail(generics.RetrieveUpdateAPIView):
queryset = Article.objects.all()
serializer_class = ArticleSerializer
# Update view + 1
# serializers.py
class ArticleSerializer(serializers.ModelSerializer):
class Meta:
model = Article
fields = "__all__"
Please help me
If you want your field to be incremented only on a GET request, you can update it in the retrieve method:
# views.py
class ArticleDetail(generics.RetrieveUpdateAPIView):
queryset = Article.objects.all()
serializer_class = ArticleSerializer
def retrieve(self, request, *args, **kwargs):
instance = self.get_object()
instance.view = instance.view + 1
instance.save()
serializer = self.get_serializer(instance)
return Response(serializer.data)
If you want it to be incremented with both GET and PATCH, you could update it in get_object instead:
# views.py
class ArticleDetail(generics.RetrieveUpdateAPIView):
queryset = Article.objects.all()
serializer_class = ArticleSerializer
def get_object(self):
instance = super(ArticleDetail, self).get_object()
instance.view = instance.view + 1
instance.save()
return instance

How to use hyperlinkedModelSerializer in django rest framework

How to use hyperlinkedModelSerializer in django rest framework My output shows:
HyperlinkedRelatedField requires the request in the serializer context. Add context={'request': request} when instantiating the serializer.
The code is given below:
serailizers.py
#Program Serializer
class ProgramSerializer(serializers.ModelSerializer):
class Meta:
model = Program
fields = '__all__'
#Program MiniSerializer
class ProgramMiniSerializer(serializers.HyperlinkedModelSerializer):
programCode = serializers.HyperlinkedRelatedField(many=True,view_name='program-detail', read_only=True)
class Meta:
model = Program
fields = ('programCode', 'pro_name', 'url', 'DepartmentID')
viewsets.py
class ProgramViewSet(viewsets.ModelViewSet):
queryset = Program.objects.all()
serializer_class = ProgramSerializer
filterset_class = ProgramFilter
filter_backends = (django_filters.rest_framework.DjangoFilterBackend,)
__basic_fields = ( 'programCode', 'pro_name','pro_shortForm', 'DepartmentID')
filter_backends = (filters.DjangoFilterBackend, SearchFilter, OrderingFilter)
filter_fields = ('programCode', 'DepartmentID')
search_fields = ('DepartmentID')
def list(self, request, *args, **kwargs):
programs = Program.objects.all()
serializer = ProgramMiniSerializer(programs, many=True)
return Response(serializer.data)
def get_queryset(self):
programs = Program.objects.all()
return programs
def retrieve(self, request, *args, **kwargs):
params=kwargs
print(params['pk'])
# programs = Program.objects.all()
programs = Program.objects.filter(DepartmentID = params['pk'])
serializer = ProgramMiniSerializer(programs, many=True)
return Response(serializer.data)
In list and retrieve methods where you initialize serializer, you need to pass context to it, like this:
serializer = ProgramMiniSerializer(
programs,
many=True,
context={
'request': request,
},
)

Allow partial update in serializer_class in Django REST

I am trying to partially update my ProfileSerializer when i am making PATCH request. However i am not able to make it beacuse by default Serializer doesn't allow partial changes to be made. I am using Django Rest Framwork UpdateModelMixin to handle my patch request. Where can i set partial=True in my case?
View:
class ProfileViewPartialUpdate(GenericAPIView, UpdateModelMixin):
queryset = Profile.objects.all()
serializer_class = ProfileSerializer
lookup_field = 'token'
lookup_url_kwarg = 'pk'
def patch(self, request, *args, **kwargs):
return self.partial_update(request, *args, **kwargs)
Serializer:
class ProfileSerializer(serializers.ModelSerializer):
class Meta:
model = Profile
fields = ('token', 'bio', 'name', 'email', 'sport', 'location', 'image')
View:
from rest_framework import generics
class ProfileViewPartialUpdate(generics.RetrieveUpdateAPIView):
queryset = Profile.objects.all()
serializer_class = ProfileSerializer
lookup_field = 'pk'
Serializer:
class ProfileSerializer(serializers.ModelSerializer):
class Meta:
model = Profile
fields = ('token', 'bio', 'name', 'email', 'sport', 'location', 'image')
Look at this snippet code from one of my projects. You can modify accordingly. Add this to ProfileViewPartialUpdate class instead of patch.
def partial_update(self, request, slug):
user = self.request.user
get_blog = Blog.objects.get(slug=slug)
instance = self.get_object()
serializer = BlogSerializer(instance, data=request.data)
if serializer.is_valid():
serializer.save()
return Response(data=serializer.data, status=HTTP_201_CREATED)
return Response(data="wrong parameters", status=HTTP_400_BAD_REQUEST)
Hope this might help

DRF query the foreign key value with filter

How to query the foreign key value with filter condition in django rest framework. I'm retrieving the value by DRF StringRelatedField method, but i don't have any idea how to filter while query itself
models.py
class User(models.Model):
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
class Score(models.Model):
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
user_id = models.ForeignKey(User, related_name='score', on_delete=models.CASCADE)
score = models.FloatField(null=False)
serilizer.py
class UserDetailsSerializer(serializers.ModelSerializer):
score = serializers.StringRelatedField(many=True)
class Meta:
model = User
fields = ('id', 'score', )
views.py
class UserDetailsRetrieveViewSet(viewsets.ModelViewSet):
def list(self, request):
queryset = User.objects.filter(score>=10)
serializer = UserDetailsSerializer(queryset, many=True)
Assuming that you need to filter User objects while viewing the API and your API is /api/v1/user/. This filtering can be achieved by two ways,
1: Using django queryset filter
You must pass the filter parameter through URL like this, /api/v1/user/?score=10. re-write your view like following,
class UserDetailsRetrieveViewSet(viewsets.ModelViewSet):
def list(self, request):
score = request.GET.get('score', None)
queryset = User.objects.all()
if score:
queryset = queryset.filter(score__gte=score)
serializer = UserDetailsSerializer(queryset, many=True)
return Response(data=serializer.data)
2. Using django-filter package
If you are trying to use the package, do not forget to install it.Your view will be like this,
class UserDetailsRetrieveViewSet(viewsets.ModelViewSet):
queryset = # your queryset
serializer_class = # your serializer
filter_backends = (DjangoFilterBackend,)
filter_fields = ('score',)
def list(self, request):
queryset = self.filter_queryset(self.get_queryset())
page = self.paginate_queryset(queryset)
if page is not None:
serializer = self.get_serializer(page, many=True)
return self.get_paginated_response(serializer.data)
serializer = self.get_serializer(queryset, many=True)
return Response(serializer.data)
def get_queryset(self):
if self.action == 'list':
return User.objects.all()
else:
return # default queryset
Let me know if it works.

How I can pass over a field validation in a serializer in Django Rest Framework

I have a Location model and I need to create a Location without specifying a user, if user in empty then the user will be placed in request.user in the viewset.
This is my model:
class Location(models.Model):
user = models.ForeignKey(User)
name = models.CharField(max_length=100)
serializer:
class LocationSerializer(serializers.ModelSerializer):
def is_valid(self):
if not 'user' in self.init_data:
# avoid this validation.. I manage this in the viewset
pass
return not self.errors
class Meta:
model = Location
and viewset
class LocationViewSet(ModelViewSet):
"""
API endpoint that allows location to be created or viewed.
"""
model = Location
serializer_class = LocationSerializer
renderer_classes = (JSONRenderer, JSONPRenderer)
def get_queryset(self):
return self.request.user.locations.filter(deleted=False)
def create(self, request, *args, **kwargs):
serializer = self.get_serializer(data=request.DATA, files=request.FILES)
if serializer.is_valid():
self.pre_save(serializer.object)
if not self.object.user:
self.object.user = request.user
self.object = serializer.save(force_insert=True)
self.post_save(self.object, created=True)
headers = self.get_success_headers(serializer.data)
return Response(serializer.data, status=status.HTTP_201_CREATED,
headers=headers)
Thanks for any suggestion
You can use required=False in serializer:
class LocationSerializer(serializers.ModelSerializer):
user = serializers.RelatedField(required=False)
EDIT
Also you can simplify your viewset with:
class LocationViewSet(ModelViewSet):
def pre_save(self, obj):
if obj.user_id is None:
obj.user = self.request.user
This avoid copying code from DRF core.