PUT request doesn't update - Django Rest Framework - django-rest-framework

I'm trying to build a todos app using django-rest-framework and when I send PUT request to change the content of the task, the content is still the same. It seems that the serializer.save() is not working as I expected.
Here are the code:
views.py
from rest_framework.response import Response
from rest_framework.decorators import api_view
from .models import Note
from .serializers import NoteSerializer
#api_view(['PUT'])
def updateNote(request, pk):
note = Note.objects.get(id=pk)
serializer = NoteSerializer(instance=note, data=request.data)
if serializer.is_valid():
serializer.save()
return Response(serializer.data)
models.py
from django.db import models
class Note(models.Model):
body = models.TextField(null=True, blank=True)
updated = models.DateTimeField(auto_now=True)
created = models.DateTimeField(auto_now_add=True)
def __str__(self):
return self.body[0:50]
serializers.py
from rest_framework.serializers import ModelSerializer
from .models import Note
class NoteSerializer(ModelSerializer):
class Meta:
model = Note
fields = '__all__'
I'm learning django so this is kinda new to me. I had searched for this problem but I'm kinda new to django so I don't understand these answers much. Any help would be appreciated.

#api_view(['PUT'])
def updateNote(request, self, pk):
note = get_object_or_404(Note.objects.all(), pk=pk)
serializer = NoteSerializer(instance=note, data=request.data, partial=True)
if serializer.is_valid():
serializer.save()
return Response(serializer.data)

Related

Rename field in Serializer.data

I am currently implementing an API client for which I want to validate the request sent using serializers.
To do so, I create my serializer like this:
class TransactionRequestSerializer(serializers.Serializer):
counterparty = serializers.UUIDField(required=False)
from_datetime = serializers.DateTimeField(required=False, source='from')
to_datetime = serializers.DateTimeField(required=False, source='to')
transaction_type = serializers.CharField(required=False, source='type')
Issue is that source doesn't fit my usage, because when I do serializer.data, I get:
{'from_datetime': '2020-07-07T16:08:00.313236+02:00'}
Instead of
{'from': '2020-07-07T16:08:00.313236+02:00'}
Those data are then passed as params for my request, like requests.get('', params=params)
Of course, I cannot name the field "from" as it is reserved. Any idea about how can I get "from" in my serializer.data?
I tink this has already been answered.
Please take a look at this question: How to change field name in Django REST Framework
I think the same solution will work for you.
I think it's not possible, so I switched to Serializer.validated_data instead so I can use source.
this example as same the question :
model:
from django.db import models
class ReceiveCallbackUrl(models.Model):
From = models.CharField(max_length=14)
to = models.CharField(max_length=14)
message = models.CharField(max_length=255)
messageid = models.IntegerField()
serializer:
from rest_framework.serializers import ModelSerializer,SerializerMethodField
from .models import ReceiveCallbackUrl
class ReceiveCallbackUrlModelSerializer(ModelSerializer):
From = SerializerMethodField('from')
class Meta:
model = ReceiveCallbackUrl
fields = ['From', 'to', 'message', 'messageid']
view:
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import status
from .serializer import ReceiveCallbackUrlModelSerializer
class ReceiveCallbackUrlAPIView(APIView):
def post(self, request):
serializer = ReceiveCallbackUrlModelSerializer(data=request.data)
if serializer.is_valid():
serializer.save()
return Response(request.POST, status=status.HTTP_200_OK)
return Response(serializer.errors, status=status.HTTP_406_NOT_ACCEPTABLE)

How to update records in a Postgres table with Django rest framework

I have basic django app that returns data from Postgres tables in an AWS RDS instance.
I have a few endpoint which relate to few tables in the RDS.
What I want to do is update records in table. If the record exists it should be updated, if it does not exist then nothing should happen Orit should throw an error.
This is my models.py file -
from django.db import models
class Campaigns(models.Model):
id_campaign = models.CharField(max_length=250, blank=True, null=True)
status = models.CharField(max_length=250, blank=True, null=True)
id_taste_cluster = models.CharField(max_length=250, blank=True, null=True)
I want to update the status field in this table where status = ' '.
This is my serialiser file -
from rest_framework import serializers
from .models import Campaigns
class Campaigns_1_Serializer(serializers.ModelSerializer):
class Meta:
model = Campaigns
fields = ('id_campaign', 'status', 'id_taste_cluster')
This is my views file -
from rest_framework import viewsets
from rest_framework.response import Response
from rest_framework import generics
from .models import Campaigns
from .serializers import Campaigns_1_Serializer
class UpdateView(viewsets.ModelViewSet):
def update(self, request, *args, **kwargs):
data = request.DATA
queryset = Campaigns.objects.filter(status='')
serializer = Campaigns_1_Serializer(queryset, data=data, many=True)
if serializer.is_valid():
serializer.save()
return Response(serializer.data)
I want to give the users the option to update only those campaigns for which the status is ' '(blank).
How can I do that ?
You need to change your update method :
#your imports
from rest_framework import serializers
class YourModelViewset(ModelViewSet):
#your code
def update(self, request, *args, **kwargs):
instance = self.get_object()
# checks if the object staus is empty
If object.status == "" or object.status is None :
raise serializers.ValidationError("your error message")
return super(YourModelViewset, self).update(request, *args, **kwargs)

User specific Serializers in Django Rest Framework

I am creating Serializers in my DRF and so far it's working good the problem is that it is showing data of all the users
serializers.py
from rest_framework import serializers
from .models import Quiz
class TodoSerializer(serializers.ModelSerializer):
class Meta:
model = Quiz
fields = ('foo', 'bar')
How do I make my Serializers User Specific such that it only returns the data of the user who is using the app?
Views.py
class TodoView(viewsets.ModelViewSet):
serializer_class = TodoSerializer
queryset = Quiz.objects.all()
User specific filtering has nothing to do with serializers. Serializers are used to convert complex python objects to/from native python datatypes that can be rendered in JSON/XML etc. It is convenient to do your filtering in your view. Here is an example by using mixins:
# views.py
from .models import Quiz
from .serializers import TodoSerializer
from rest_framework import mixins, viewsets
from rest_framework.response import Response
class TodoListViewSet(viewsets.GenericViewSet, mixins.ListModelMixin):
queryset = models.Quiz.objects.all()
serializer_class = TodoSerializer
def list(self, request, *args, **kwargs):
queryset = self.filter_queryset(self.get_queryset())
# filter your todos here
queryset = queryset.filter(user=request.user)
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)

Django Filter Backend not working in restful api in django

I am trying to use django-filters in have search queries in url using params
view.py
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import status
from django_filters.rest_framework import DjangoFilterBackend
from rest_framework.filters import SearchFilter
from .models import RecruiterRegister
from .serializers import RecruiterRegisterSerializer
# from rest_framework import filters
from rest_framework import generics
class RecruiterRegisterList(APIView):
queryset=RecruiterRegister.objects.all()
filter_backends = (DjangoFilterBackend,SearchFilter ,)
filter_fields = ('email','password')
search_fields = ('email','password')
def get(self, request, format=None):
recruiterRegisters = RecruiterRegister.objects.all()
# self.filter_backends = (DjangoFilterBackend,)
# self.filter_fields = ('password', )
serializer = RecruiterRegisterSerializer(recruiterRegisters, many=True)
return Response(serializer.data)
def post(self, request, format=None):
serializer = RecruiterRegisterSerializer(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)
def delete(self, request, pk, format=None):
recruiterRegisters = self.get_object()
recruiterRegisters.delete()
return Response(status=status.HTTP_204_NO_CONTENT)
but I am not able to get filtered data. All the api data appears.
url sample
http://127.0.0.1:8000/recruiterRegister/?password=random2
edited RecruiterRegisterList class:
class RecruiterRegisterList(generics.ListAPIView):
queryset=RecruiterRegister.objects.all()
serializer_class = RecruiterRegisterSerializer
filter_backends = (DjangoFilterBackend,)
filter_fields=('email','password')
# search_fields = ('email','password')
def list(self, request ):
queryset = self.get_queryset()
serializer = RecruiterRegisterSerializer(queryset, many=True)
return Response(serializer.data)
First question is - why would you ever want to filter or search by password? that is a very unhealthy and unsecure design. Passwords are not stored in their raw formats but hashed so the filters will never hit anyway
Now, even if you really wanted to do that, filtering using filter_backends is implemented in the GenericAPIView and not available in APIView so you may want to use the ListAPIview from rest_framework.generics instead.
Lastly, even if you used the ListAPIView, it still wouldn't work because you're overriding the get method and not calling self.filter_queryset().
Use the ListAPIView and use the already implemented list() method and it will work
I'm adding only the line bellow & working fine:
filter_backends = self.filter_queryset(queryset)
And your code like:
class RecruiterRegisterList(generics.ListAPIView):
queryset=RecruiterRegister.objects.all()
serializer_class = RecruiterRegisterSerializer
filter_backends = (DjangoFilterBackend,)
filter_fields=('email','password')
search_fields = ('email','password')
def list(self, request ):
queryset = self.get_queryset()
filter_backends = self.filter_queryset(queryset)
serializer = RecruiterRegisterSerializer(filter_backends, many=True)
return Response(serializer.data)

django rest framework many to many serialize and apiview

I am creating APIView for book list and add, delete.
Is this serialization the right way?
I want to show a list of books, but I do not know what to put in '?'.
member/models.py
class MyUser(AbstractBaseUser, PermissionsMixin):
username = models.EmailField(unique=True, max_length=256)
nickname = models.CharField(max_length=256)
is_staff = models.BooleanField(default=False)
created_date = models.DateTimeField(auto_now_add=True)
mybook = models.ManyToManyField(Book)
book/models.py
from django.db import models
class Book(models.Model):
title = models.CharField(max_length=256)
author = models.CharField(max_length=200)
def __str__(self):
return self.title
book/seralizers.py
from rest_framework import serializers
from book.models import Book
class MyBookSerializer(serializers.ModelSerializer):
mybook = serializers.PrimaryKeyRelatedField(many=True, read_only=True)
class Meta:
model = Book
fields = (
'title',
'author',
)
apiview.py
class MyBook(APIView):
def get(self, request):
mybook = Book.objects.filter(myuser=?)
serializer = MyBookSerializer(mybook)
return Response(serializer.data, status=status.HTTP_200_OK)
def post(self, request):
pass
def delete(self, request):
pass
If you want create a CRUD for model, depends on a request.user you can simply use ModelViewSet:
from rest_framework import viewsets
class MyBookViewSet(viewsets.ModelViewSet):
serializer_class = MyBookSerializer
def get_queryset(self, request):
return Book.objects.filter(myuser=self.request.user)
That's all for view. You only need to specify router for a viewset.
urls.py:
from rest_framework import routers
router = routers.DefaultRouter()
router.register('books', MyBookViewSet)
urlpatterns = []
urlpatterns += router.urls
Include this usl file in a root urls and you are done.
You also need to specify related_name for m2m field if you want to use myuser name:
mybook = models.ManyToManyField(Book, related_name='myuser')
And you don't need this field in a serializer:
mybook = serializers.PrimaryKeyRelatedField(many=True, read_only=True)
viewsets docs
routers docs

Resources