Django/DRF异常处理

whitzsjs  于 2023-06-25  发布在  Go
关注(0)|答案(2)|浏览(109)

我想检查www.example.com的正确性request.data,每当有一个POST请求127.0.0.1:8000/api/v1/events/目前,我有事件模型

class Event(models.Model): 
    title = models.CharField(max_length=50) 
    description = models.CharField(max_length=250) 
    created_by = models.ForeignKey(User, related_name='created_events', on_delete=models.CASCADE) 
    event_type = models.CharField(choices=EventType.choices, max_length=10) 
    created_time = models.DateTimeField(auto_now_add=True) 
    updated_time = models.DateTimeField(auto_now=True)

每当有PATCH请求127.0.0.1:8000/api/v1/events/{pk}时。那么,updated_timeevent_type不应该在www.example.com中request.data(这意味着它们不应该被更新)。如何确保www.example.com中的所有内容都正确request.data?
可以通过检查

request_keys = request.data.keys() 
actual_keys = self.serializer_class().get_fields().keys() 
result = [x for x in request_keys if x not in actual_keys] 
if result: 
    return Response({'error': 'Invalid data'}, status=400)

但问题是,每当request.method不同时,我确实需要检查不同的字段,比如POST和PATCH,.get_fields()将返回序列化器中的所有字段。然而,对于PATCH I,不应该有updated_timeevent_type字段。
这是我的EventView代码

def create(self, request): 
    serializer = EventSerializer(data=request.data, context={'request': request})
    serializer.is_valid(raise_exception=True)
    error_response = self._validate_request_data(request.data) 
    if error_response is not None: 
        return error_response 
    user, event_id = request.user, request.data['event'] 
    event = get_object_or_404(Event, pk=event_id) 
    ... 
    ... 

def partial_update(self, request):
    error_response = self._validate_request_data(request.data)
    if error_response is not None:
        return error_response
    ...
    ...
   
def _validate_request_data(self, request_data): 
    request_keys = request_data.keys() 
    actual_keys = self.serializer_class().get_fields().keys() 
    result = [x for x in request_keys if x not in actual_keys] 
    if result: 
        return Response({'error': 'Invalid data'}, status=400)
    ...
    ...

但是不知道如何区分不同HTTP_METHODS的.get_fields()

wj8zmpe1

wj8zmpe11#

Django restframework Serializers有只读字段,如果你像下面这样使用ModelSerializer。

class EventSerializer(serializers.ModelSerializer): 
    class Meta: 
        model = Event 
        fields = '__all__' 
        read_only_fields = ['created_by', 'created_time', 'updated_time']

你可以做的另一件事是,你也可以在序列化器中对所有字段或仅对一个特定字段使用验证方法。

class EventSerializer(serializers.ModelSerializer): 
    class Meta: 
        model = Event 
        fields = '__all__' 
        read_only_fields = ['created_by', 'created_time', 'updated_time']
        
    # Drop event_type from the response
    def validate_event_type(self, value): 
        return None

    # or 
    def validate(self, data): 
        data.pop('event_type') 
        return data

要只限制特定请求中的某些字段,您可以编辑上面的validate方法,如下所示。

def validate(self, data):
    # only in PATCH requests
    request = self.context.get('request')
    if request.method == 'PATCH':
        data.pop('event_type') 
    return data

不要把视图搞得一团糟,大多数时候你可以从验证器中做一些事情。
我相信你可以参考文档,这真的是一个很好的参考地方,他们有一个很好的文档。
同时检查restframework文档中的ViewSet。
好好享受

myzjeezk

myzjeezk2#

根据djangorestframework文档
默认情况下,设置了editable=False的模型字段和AutoField字段将设置为只读,并且不需要添加到read_only_fields选项中。
因此,在执行serializer.save()时,无论使用了任何request.method,这些字段都不会受到影响。要更新这些字段,我们必须获取对象示例并显式更新它们,如:

event_obj.some_read_only_field = some_value
event_obj.save()

即使请求数据包含该值,这些字段也不会被更新。
现在的问题是,我们如何在创建对象的同时,在模型中设置event_type等字段。“POST”请求。对于这种类型的字段,设置editable=False将是不合理的,因为它应该能够在创建POST请求期间使用来自request.data的值。
为了避免event_type字段的更新,我们可以实现以下操作:

  • event_type作为read_only字段为UPDATE请求实现一个单独的序列化程序。
  • 从请求数据中弹出event_type密钥,然后将其馈送到串行化器
  • 修改serializer.update方法以避免event_data的更新值
  • 修改模型本身中的save方法,以避免event_type字段的更新。

就我个人而言,编写两个不同的序列化程序更简洁:

class EventCreateSerializer():
  class Meta:
    model = Event
    fields = "__all__"

class EventUpdateSerializer():
  class Meta:
    model = Event
    exclude = ["event_type"]

在APIView中使用它相当容易。我们也可以根据视图集中的操作提供单独的序列化器,如:

class EventViewSet(viewsets.ModelViewSet):
  def get_serializer_class(self):
    if self.action == 'create':
      return EventCreateSerializer
    elif self.action in ['update', 'partial_update']:
      return EventUpdateSerializer
    return super().get_serializer_class()

相关问题