【问题标题】:Type error while Put Request Django Rest FrameworkPut Request Django Rest Framework 时输入错误
【发布时间】:2020-06-25 15:44:58
【问题描述】:

我正在构建一个 Django 应用程序,其中有一个名为 Location 的模型和另一个名为 Property 的模型。每当我尝试发出 put 请求时,它都会显示输入错误TypeError: Object of type Location is not JSON serializable

我的位置模型

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)

序列化器

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']

观看次数

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)

当我使用 PUT 请求更新它向我显示的信息时保存属性后 TypeError: Object of type Location is not JSON serializable 我在数据库中保存了几个位置。 首先我用它发了一个帖子请求,它给了我STATUS 201 CREATED

{
'name': 'foo',
'bedrooms':4,
'bathrooms':3,
'living_rooms':5,
'location':4,
}

然后我对它做一个 put 请求

{
'name': 'foo bar',
'bedrooms':1,
'bathrooms':2,
'living_rooms':2,
'location':1,
}

它给了我TypeError: Object of type Location is not JSON serializable

【问题讨论】:

  • 我相信您的属性序列化程序需要添加 PrimaryKeyRelatedField 属性 - 例如 location = PrimaryKeyRelatedField() 或 location = LocationSerializer()
  • 那么您如何决定您在 PUT 请求中编辑的属性?您提供的是 request.user 而不是要编辑的属性实例

标签: python django django-rest-framework django-serializer serialization


【解决方案1】:

您的代码存在很多问题。 GET 和 POST 请求在列表端点上正常工作,但 PUT 请求应该在详细端点上工作。这意味着端点应该使您能够指定要编辑的特定 Property 对象,但目前不是。再加上这一点,您不是将要编辑的Property 实例传递给序列化程序,而是传递request.user

通常,如果您使用的是低级 APIView,那么您需要为列表和详细信息端点制作单独的视图。如果您想使用一个视图,那么您应该利用结合了列表和详细视图的更高级别的视图集。而且它们很容易实现,因为大多数样板代码已经为您实现了。对于您的情况,像这样的简单视图集就足够了。

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()

然后像这样在 urls.py 中注册它:

from rest_framework.routers import SimpleRouter

router = SimpleRouter()
router.register(r'properties', PropertyViewSet, basename='properties')
urlpatterns = router.get_urls()

它已经自动实现了 get、post、put 和 delete,并包含两个端点:api/properties 称为列表端点,api/properties/<id>/ - 称为详细端点。

所以要编辑id为2的属性,你应该将PUT请求发送到api/properties/2/

您还可以阅读有关DRF viewsets的更多信息

【讨论】:

  • 那是我第一次写这个应用程序的时候,后来我按照你说的做了。但是,它仍然给了我同样的问题。然后我能够解决它。我忘了给序列化器一个实例,这就是它导致问题的原因
  • @KhanAsfiRezaPranto 那么好。如果它有助于解决问题,请不要忘记接受答案
【解决方案2】:

在您的PropertySerializer 中,您需要将PrimaryKeyRelatedFieldLocationSerializer 添加到“位置”属性:

class PropertySerializer(serializers.ModelSerializer):
     location = PrimaryKeyRelatedField()
     class Meta:
          model = Property
          fields = ['id','name','bedrooms','bathrooms','living_rooms','location']
          read_only_fields = ['id']

或:

class PropertySerializer(serializers.ModelSerializer):
     location = LocationSerializer()
     class Meta:
          model = Property
          fields = ['id','name','bedrooms','bathrooms','living_rooms','location']
          read_only_fields = ['id']

我相信在 RenterCreate 视图中也有一种方法可以做到这一点,但如果其中任何一个先起作用,请告诉我。

【讨论】:

  • 我的位置模型是一个独立模型,它与多个模型有关系,Like。财产 - 位置,代理 - 位置,所有者 - 位置。我创建了这样的位置模型以节省空间。
【解决方案3】:

在您的 PUT 方法 (put(self, request)) 中,您使用 request.user 作为 PropertySerializer 的对象,而不是属性对象。您可以查看the serializer documentation for saving an object

您可以关注this wonderful DRF tutorial 来设置您的 APIViews 和 urls.py 用于 get/put/post 方法。

然后您可以毫无问题地创建、更新和获取对象。

【讨论】:

    【解决方案4】:

    我在这件事上发现了问题并解决了 序列化器和模型是相同的,但我改变了视图。

    
    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)**
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2018-11-25
      • 2013-07-05
      • 2016-09-09
      • 2017-07-15
      • 1970-01-01
      • 2019-11-22
      • 2015-02-13
      相关资源
      最近更新 更多