Reputation: 691
I am building a Django application where there is a Model called Location and another model called Property. Whenever I try to give put request it shows me type error TypeError: Object of type Location is not JSON serializable
My Location Model
class Location(models.Model):
lat = models.DecimalField(max_digits=10,decimal_places=8)
long = models.DecimalField(max_digits=10,decimal_places=8)
address = models.CharField(max_length=256)
class Property(models.Model):
owner = models.OneToOneField(to=User,on_delete=models.CASCADE)
name = models.CharField(max_length=256)
bedrooms = models.SmallPositiveIntigerField()
bathrooms = models.SmallPositiveIntigerField()
living_rooms = models.SmallPositiveIntigerField()
location = models.ForeignKey(to=Location,null=True,on_delete=models.SETNULL)
Serializer
class PropertySerializer(serializers.ModelSerializer):
class Meta:
model = Property
fields = ['id','name','bedrooms','bathrooms','living_rooms','location']
read_only_fields = ['id']
class LocationSerializer(serializers.ModelSerializer):
class Meta:
model = Location
fields = ['id','long','lat','address']
read_only_fields = ['id']
views
class RenterCreate(APIView):
authentication_classes = [TokenAuthentication]
permission_classes = [IsAuthenticated, RenterPermission]
renderer_classes = [JSONRenderer]
def get(self, request):
property = Property.objects.all()
serializer = RenterSerializer(property , many=True)
return Response(serializer.data, status=status.HTTP_200_OK)
def post(self, request):
serializer = PropertySerializer(data=request.data)
if serializer.is_valid():
serializer.save(user=request.user)
return Response(serializer.data, status=status.HTTP_201_CREATED)
return Response(serializer.error_messages, status=status.HTTP_400_BAD_REQUEST)
def put(self, request):
serializer = PropertySerializer(request.user, data=request.data)
if serializer.is_valid():
serializer.save(user=request.user)
return Response(serializer.data)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
After saving a Property when I use PUT request to update the information it shows me
TypeError: Object of type Location is not JSON serializable
I have saved a couple of locations in the database.
First I made a post request with it, it gives me STATUS 201 CREATED
{
'name': 'foo',
'bedrooms':4,
'bathrooms':3,
'living_rooms':5,
'location':4,
}
Then I do a put request on it
{
'name': 'foo bar',
'bedrooms':1,
'bathrooms':2,
'living_rooms':2,
'location':1,
}
It gives me TypeError: Object of type Location is not JSON serializable
Upvotes: 0
Views: 314
Reputation: 691
I found out the problem and solved it in this matter Serializer and Models are same but I have changed the view.
class PropertyView(viewsets.ModelViewSet):
# Adding Authentication classes Token Authentication
# Permission class > Will allow only post request if user is not authenticated
authentication_classes = [TokenAuthentication]
# Permissions only allow renters and authenticated users
permission_classes = [IsAuthenticated, RenterPermission]
# Gives JSON Rendered Class
renderer_classes = [JSONRenderer]
# Serializer Class for this Class View
serializer_class = PropertySerializer
# Query set of all renter objects
queryset = Renter_Property_Pref.objects.all()
@action(methods=['get'], detail=True)
def retrieve(self, request, pk=None):
renter = get_object_or_404(self.queryset, user=request.user)
serializer = self.get_serializer(renter, many=False)
return Response(serializer.data, status=status.HTTP_200_OK)
@action(methods=['post'], detail=True)
def create(self, request):
# giving serializer the data from request data
serializer = self.get_serializer(data=request.data)
# checks if serializer is valid
if serializer.is_valid():
# saves user information and saves it
serializer.save(user=self.request.user)
return Response(serializer.data, status=status.HTTP_201_CREATED)
# Otherwise it will return errors and a bad request
return Response(serializer.error_messages, status=status.HTTP_400_BAD_REQUEST)
@action(methods=['put'], detail=True)
def update(self, request):
# Propery Serializer and instance object
instance = Property.objects.get(owner=request.user)
serializer = self.get_serializer(instance=instance, data=request.data)
# If serializer is valid it will save
if serializer.is_valid():
serializer.save()
return Response(serializer.data)
# Otherwise it will show error
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)**
Upvotes: 0
Reputation: 6296
There are quite a few issues with your code. The GET and POST requests are correctly working on the list endpoint but the PUT request should work on the detail endpoint. This means that the endpoint should enable you to specify the particular Property
object you want to edit, but currently, it is not. Coupled with this, instead of passing the Property
instance you want to edit to the serializer, you're passing the request.user
.
Usually, if you are using the low-level APIView, then you need to make separate views for the list and detail endpoints. If you want to use one view, then you should exploit the higher level viewsets which combine list and detail views. And they are pretty easy to implement as most of the boilerplate code is already implemented for you. For your case, a simple viewset like this can suffice.
from rest_framework import viewsets
class PropertyViewSet(viewsets.ModelViewSet):
authentication_classes = [TokenAuthentication]
permission_classes = [IsAuthenticated, RenterPermission]
renderer_classes = [JSONRenderer]
serilaizer_class = PropertySerializer
queryset = Property.objects.all()
Then register it in the urls.py like this:
from rest_framework.routers import SimpleRouter
router = SimpleRouter()
router.register(r'properties', PropertyViewSet, basename='properties')
urlpatterns = router.get_urls()
It automatically already has the get, post, put and delete implemented and embodies two endpoints: api/properties
called the list endpoint and api/properties/<id>/
- called the detail endpoint.
So to edit the property of say, the property with id 2, you should send the PUT request to api/properties/2/
.
You can also read more about DRF viewsets
Upvotes: 1
Reputation: 1117
In your PUT method(put(self, request)
), you are using request.user as the PropertySerializer's object rather than a property object. You can check the serializer documentation for saving an object.
You can following this wonderful DRF tutorial to set up your APIViews and urls.py for get/put/post methods.
Then you can create, update and get an object without issues.
Upvotes: 0
Reputation: 2873
In your PropertySerializer
you need to either add a PrimaryKeyRelatedField
or LocationSerializer
to the "location" attribute:
class PropertySerializer(serializers.ModelSerializer):
location = PrimaryKeyRelatedField()
class Meta:
model = Property
fields = ['id','name','bedrooms','bathrooms','living_rooms','location']
read_only_fields = ['id']
or:
class PropertySerializer(serializers.ModelSerializer):
location = LocationSerializer()
class Meta:
model = Property
fields = ['id','name','bedrooms','bathrooms','living_rooms','location']
read_only_fields = ['id']
I believe there is also a way to do it in the RenterCreate view, but let me know if either of those work first.
Upvotes: 1