web-dev-qa-db-ja.com

Django RESTフレームワーク

私はDjango REST Frameworkを使用しています

request.data = '{"id": "10", "user": "tom"}'

さらに「いいね」に送信する前に、"age": "30"などの属性を追加したい

    request.data = new_data
    response = super().post(request, *args, **kwargs)

2つの問題があります

  1. なぜrequest.dataがdictではなくstringとして送られるのですか
  2. Request.dataを更新する方法
22
John Kaff

一般に、DRFビューのrequestrest_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
3
validname

良い友達が上に示したよりもずっと簡単なアプローチで私を学校に連れて行ってくれた

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
Stephan Doliov

Json文字列のように見えます。それを辞書に変換するには、次のようにします。

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
Stephen Briney

APIがAPIViewの場合は、更新関数を使用して、クライアント側から送信されたデータを失うことなく要求データオブジェクトを拡張する必要があります。

request.data.update({"id": "10", "user": "tom"})
2
Ibrahim Tayseer

あなたのコメントによると:

「投稿する前に、APIで必要なフィールド名AQを変更する必要があるため」

代わりにFieldの-​​ source引数 を使用する必要があります。

これにより、エラーメッセージの一貫性が向上します。そうしないと、ユーザーが提供していないフィールド名でエラーが発生します。

0
Linovia

私はこれを別の方法で扱いました。 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'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
0
Stephan Doliov

エンドポイントがDRF ViewSetで実装されている場合、解決策は、対応するシリアライザクラスの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
0
Csaba Toth