Python 如何在django REST框架中修改request.data
我正在使用Django REST框架Python 如何在django REST框架中修改request.data,python,json,django,django-rest-framework,Python,Json,Django,Django Rest Framework,我正在使用Django REST框架 request.data = '{"id": "10", "user": "tom"}' 我想添加额外的属性,比如“age”:“30”,然后再将其发送给其他类似的用户 request.data = new_data response = super().post(request, *args, **kwargs) 我有两个问题 为什么request.data是字符串而不是dict 如何更新request.data 它看起来像一个json字
request.data = '{"id": "10", "user": "tom"}'
我想添加额外的属性,比如“age”:“30”
,然后再将其发送给其他类似的用户
request.data = new_data
response = super().post(request, *args, **kwargs)
我有两个问题
它看起来像一个json字符串。要将其转换为dict,应执行以下操作:
import json
data = json.loads(request.data)
然后可以添加额外属性:
data['age'] = 30
然后你必须提出一个新的要求,因为看起来你不能仅仅改变旧的要求。这假设您正在向/notes/发布:
from rest_framework.test import APIRequestFactory
factory = APIRequestFactory()
request = factory.post('/notes/', data, format='json')
根据你的评论: “因为在发布之前,我需要更改API要求的字段名aqs” 您应该使用
字段
这将使错误消息更加一致,否则您的用户将面临他们没有提供的字段名的错误。如果您的端点是用DRF
ViewSet
实现的,解决方案可以是实现对应的TIG序列化程序类的to_internal_value
方法并修改其中的数据
class MyModelViewSet(viewsets.ModelViewSet):
authentication_classes = ...
...
serializer_class = MyModelSerializer
class MyModelSerializer(serializers.ModelSerializer):
class Meta:
model = MyModel
fields = ('id', 'user', ...)
def to_internal_value(self, data):
instance = super(MyModelSerializer, self).to_internal_value(data)
if "lastModified" in data:
# instance["id"] = 10 # That's sketchy though
instance["user"] = "tom"
return instance
我以不同的方式处理这个问题。我重写CreateAPIView创建方法,如下所示
class IPAnnotatedObject(CreateAPIView):
model = IPAnnotatedObject
queryset = IPAnnotatedObject.objects.all()
serializer_class = IPAnnotatedObject
def create(self, request, *args, **kwargs):
request.data['ip_addr'] = self.get_ip()
serializer = self.get_serializer(data=request.data)
serializer.is_valid(raise_exception=True)
## perform_create calls serializer.save() which calls the serializer's create() method
self.perform_create(serializer)
headers = self.get_success_headers(serializer.data)
return Response(serializer.data, status=status.HTTP_201_CREATED, headers=headers)
def get_ip(self):
x_forwarded_for = self.request.META.get('HTTP_X_FORWARDED_FOR',None)
if x_forwarded_for:
ip = x_forwarded_for.split(',')[0]
else:
ip = self.request.META.get('REMOTE_ADDR',None)
return ip
相应的序列化程序类如下所示
class IPAnnotatedObjectSerializer(serializers.ModelSerializer):
email = serializers.EmailField(validators=[UniqueValidator(queryset=IPAnnotatedObject.objects.all())])
password = serializers.CharField(write_only=True)
ip_addr = serializers.IPAddressField(write_only=True)
class Meta:
model = IPAnnotatedObject
fields = ['email','password','created_ip']
def create(self, validated_data):
email, password, created_ip = validated_data['email'], validated_data['password'],validated_data['created_ip']
try:
ipAnnoObject = IPAnnotatedObject.objects.create(email=email,password=make_password(password),ip_addr=ip_addr)
except Exception as e:
# you can think of better error handler
pass
return ipAnnoOjbect
一位好朋友带我去学校的方法比我上面所说的要简单得多
class CreateSomething(CreateAPIView):
model = Something
queryset = Something.objects.all()
serializer_class = SomethingSerializer
perform_create(self,serializer):
def perform_create(self,serializer):
ip = self.get_ip()
## magic here: add kwargs for extra fields to write to db
serializer.save(ip_addr=ip)
def get_ip(self):
x_forwarded_for = self.request.META.get('HTTP_X_FORWARDED_FOR',None)
if x_forwarded_for:
ip = x_forwarded_for.split(',')[0]
else:
ip = self.request.META.get('REMOTE_ADDR',None)
return ip
class SomethingSerializer(serializers.ModelSerializer):
email = serializers.EmailField(validators=[UniqueValidator(queryset=Something.objects.all())])
fieldA = serializers.CharField()
fieldB = serializers.CharField()
class Meta:
model = Customer2
fields = ['email','fieldA','fieldB','ip_addr']
read_only_fields = ['ip_addr']
通常,drf视图中的
request
是rest\u framework.request.request
实例。下面是它的源代码(djangorestframework==3.8.2
):
@属性
def数据(自身):
如果不是_hasattr(self,_full_data)):
self.\u加载\u数据和\u文件()
返回自我。\u完整\u数据
你可以做:
request.\u full\u data=您的\u数据
如果API是APIView
,则应使用更新功能扩展请求数据对象,而不会丢失从客户端发送的数据
request.data.update({"id": "10", "user": "tom"})
request.data
应该是不可变的,而不是字符串。如果需要修改,请执行以下操作:
如果存在(request.data,QueryDict):#可选
request.data.\u mutable=True
请求.数据['age']=“30”
您可能会检查它是否是
QueryDict
的实例的唯一原因是,如果我使用request.data=json\u data
它说无法在requestYikes上设置属性,那么使用常规的dict
进行单元测试就更容易了。。。虽然这是可行的,但DRF应该有一个更干净的方法来实现这一点。请提供更多的上下文,例如如何添加额外属性以及为什么要更新request.data。请注意,更新request.data通常是个好主意。@Linovia我想添加额外的属性request.data['age']=30
。现在我不能在request.data是string而不是dict时这样做。现在如果使用data=json.loads(request.data)
然后request.data=json\u data
那么我得到一个错误,无法在request上设置属性添加“request.data['age']=30”就是您试图做的方式,这不是你想要/需要这样做的原因。@Linovia因为在发布之前,我需要更改API所需的字段名aqs,所以我需要更改请求数据。很遗憾,没有更直观的方法来执行此操作。可能是更好的mixin或某些预定义函数。顺便说一句,如果覆盖ModelViewSet
的create
和update
方法,也可以进行一些操作。