0

my client is sending me a POST with a json-array and is awaiting a response with the complete details of the requested data. I have no problems with single requests and single responses, but to minimize the overhead, I'd like to process an array.

my models.py

class RoFile(models.Model):
    user = models.ForeignKey('auth.User', null=True)
    filename = models.CharField(max_length=120, null=True)
    deleted = models.BooleanField(default=False)
    info = models.CharField(max_length=120, null=True)
    md5check = models.CharField(max_length=120, null=True)

one try of my serializer:

class RoFileSerializer(serializers.ModelSerializer):
    deleted = serializers.ReadOnlyField(required=False)
    user = serializers.ReadOnlyField(required=False)
    info = serializers.ReadOnlyField(required=False)

    class Meta:
        model = RoFile
        fields = (
            'filename', 'md5check', 'deleted', 'user', 'info',
        )

   def create(self, validated_data):
        return RoFile(**validated_data)

on try of my views:

@api_view(['POST'])
def rofile_detaillist(request, format=None):
    data = JSONParser().parse(request)
    serializer = RoFileSerializer(data=data, many=True)
    if serializer.is_valid():
        json_add = []
        for x in serializer.validated_data:
            try:
                rofile = RoFile.objects.filter(md5check=x['md5check'])
            except ObjectDoesNotExist:
                continue

            *invalid code here*

        return Response(jsonarraywithallinfos)
    else:
        return Resonse(status=status.HTTP_400_BAD_REQUEST)

another view try:

class RoFileDetailList(viewsets.ModelViewSet):
    model = RoFile
    serializer_class = RoFileSerializer(many=True)

    def get_queryset(self):
         return Rofile.objects.filter(md5check=self.request.data['md5check'])

a POST example:

{"filename": "filename1.exe", "md5check": "f8541061779b1efc5c30c4783edfb8f8"},
{"filename": "filename2.exe", "md5check": "16cdac5eb0ec829c2e2c199488681f6e"}

what I need as a response back:

{"filename": "filename1.exe", "md5check": "f8541061779b1efc5c30c4783edfb8f8", user: "testuser1", deleted: "True", info: ""},
{"filename": "filename2.exe", "md5check": "16cdac5eb0ec829c2e2c199488681f6e", user: "testuser1", deleted: "False", info: ""}

Sorry for the invalid code part, but I have already tried so much, so I deleted that part (by accident). Thank you!

EDIT:

I don't need to create with POST, I only need to retrieve additional data (the rest of the model). I had to change the create function in the serializer, because I don't want to create the entries, I only want to retrieve the data associated with the md5check from the db.

thanks to @zaphod100.10 my actual serializer:

class RoFileSerializer(serializers.ModelSerializer):
    class Meta:
        model = RoFile
        fields = '__all__'
        read_only_fields = ('deleted',)

    def create(self, validated_data):
        return RoFile(**validated_data)

my view:

class RoFileListDetailApi(generics.ListCreateAPIView):
    serializer_class = RoFileSerializer

    def get_queryset(self):
        return RoFile.objects.filter(md5check=self.request.data['md5check'])

    def create(self, request, *args, **kwargs):
        serializer = self.get_serializer(data=request.data, many=True)
        serializer.is_valid(raise_exception=True)
        self.perform_create(serializer)
        headers = self.get_success_headers(serializer.data)
        return Response(serializer.data, status=status.HTTP_200_OK, headers=headers)

my post:

{"filename": "filename1.exe", "md5check": "f8541061779b1efc5c30c4783edfb8f8"},
{"filename": "filename2.exe", "md5check": "16cdac5eb0ec829c2e2c199488681f6e"}

my actual response is now a list but only with my POST-data and not the real data from the db:

{"filename": "filename1.exe", "md5check": "f8541061779b1efc5c30c4783edfb8f8", deleted: false, info: null, user: null},
{"filename": "filename2.exe", "md5check": "16cdac5eb0ec829c2e2c199488681f6e", deleted: false, info: null, user: null}

should be:

{"filename": "filename1.exe", "md5check": "f8541061779b1efc5c30c4783edfb8f8", deleted: true, info: "some info", user: "usertest1"},
{"filename": "filename2.exe", "md5check": "16cdac5eb0ec829c2e2c199488681f6e", deleted: false, info: "some info2", user: "usertest2"}

1 Answer 1

1

use this:

class RoFileSerializer(serializers.ModelSerializer):

    class Meta:
        model = RoFile
        fields = '__all__'
        read_only_fields = ('deleted', 'user', 'info')

class RoFileListCreateApi(generics.ListCreateAPIView):
    serializer_class = RoFileSerializer

    def get_queryset(self):
         return Rofile.objects.filter(md5check=self.request.data['md5check'])

    def create(self, request, *args, **kwargs):
        serializer = self.get_serializer(data=request.data, many=True)
        serializer.is_valid(raise_exception=True)
        # override perform_create or the serializers create method for custom create logic
        self.perform_create(serializer)
        # assign other fields to the objs and save again
        headers = self.get_success_headers(serializer.data)
        return Response(serializer.data, status=status.HTTP_201_CREATED, headers=headers)

You just have to pass many=True to the serializer for handling lists.

Override perform_create method in the generic view or the serializers create method for applying custom creation logic.

EDIT:

based on new info provided I have changed the create method.

def create(self, request, *args, **kwargs):
    serializer = self.get_serializer(data=request.data, many=True)
    serializer.is_valid(raise_exception=True)
    # don't create anything just insert required data
    for rof_data in serializer.data:
        md5check = rof_data['md5check']
        # code to retrieve data from db based on md5check
        ....
        # code to insert values in rof_data
        rof_data['user'] = user.username
        rof_data['deleted'] = deleted
        rof_data['info'] = info
    headers = self.get_success_headers(serializer.data)
    return Response(serializer.data, status=status.HTTP_201_CREATED, headers=headers)
Sign up to request clarification or add additional context in comments.

2 Comments

thank you, I don't want to create them, because they are already in the db. I only need to make the query to get the additional data. Please see my edit.
@bingobear I updated the answer yesterday. Did it work out?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.