Как изменить request.data в django REST framework
Я использую Django REST Framework
request.data = '{"id": "10", "user": "tom"}'
Я хочу добавить дополнительный атрибут типа "age": "30"
прежде чем отправлять его дальше
request.data = new_data
response = super().post(request, *args, **kwargs)
У меня есть два вопроса
- Почему request.data поступает как строка, а не dict
- Как я могу обновить request.data
Ответы
Ответ 1
Это похоже на строку 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')
Ответ 2
Хороший друг привел меня в школу гораздо более простым способом, чем я иллюстрирую выше
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']
Ответ 3
Если ваша конечная точка реализована с помощью DRF ViewSet
решение может состоять в том, чтобы реализовать класс to_internal_value
последовательного 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 sketchy though
instance["user"] = "tom"
return instance
Ответ 4
Согласно вашему комментарию:
", потому что перед публикацией мне нужно chnage имена полей aqs, требуемые API"
Вместо этого вы должны использовать аргумент source
Field
.
Это сделает сообщения об ошибках более последовательными, иначе ваш пользователь столкнется с ошибками с именами полей, которые они не предоставили.
Ответ 5
Я рассматривал это по-другому. Я переопределяю метод CreateAPIView create, как показано ниже.
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 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
Ответ 6
Обычно request
в представлениях rest_framework.request.Request
является экземпляром rest_framework.request.Request
. После этого исходный код (djangorestframework==3.8.2
):
@property
def data(self):
if not _hasattr(self, '_full_data'):
self._load_data_and_files()
return self._full_data
Ты можешь сделать:
request._full_data = your_data