Skip to content

Documentation: ORM-Less View Examples #777

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
Rjak opened this issue Apr 5, 2020 · 3 comments
Closed

Documentation: ORM-Less View Examples #777

Rjak opened this issue Apr 5, 2020 · 3 comments

Comments

@Rjak
Copy link

Rjak commented Apr 5, 2020

I am working on both a personal project and a project for work which retrieves data from external sources, not from an ORM.

My personal project has a class-based view like this:

class PeopleList(APIView):
    """Provides the list of people to choose when performing a person search."""
    def get(self, request, format=None):
        search_term = request.data['search_term']
        input_data = { 'search_term': search_term }
        input_serializer = SearchTermSerializer(data=input_data)
        if not input_serializer.is_valid():
            return Response(input_serializer.errors,
                            status=status.HTTP_400_BAD_REQUEST)

        dao = get_external_dao()
        result = dao.person_search(input_serializer)
        return Response(result.data)

When I enable DJA, I get the following response to this query:

{
    "errors": [
        {
            "detail": "Received document does not contain primary data",
            "status": "400",
            "source": {
                "pointer": "/data"
            },
            "code": "parse_error"
        }
    ]
}

It's not clear to me what this error message refers to. Is there a problem with the request body I am submitting? The search term is specified in a request body (I'm not using filtering here because my understanding is that filters are tied to querysets and since the data is coming from an external API and not an ORM it is not applicable).

The only examples I can find are bound to ORM usage, so I'm finding it tough to even examine the problem.

An example which shows custom logic for handling a string match search against an external, non-ORM data source would help me in this case.

Thanks very much!

@sliverc
Copy link
Member

sliverc commented Apr 9, 2020

Of what type is result? And as this is a get request shouldn't you access request.query_params['search_term']?

I haven't done this before but technically I think it should be possible to use APIView. Such view needs to return data of a serializer though (return Response(serializer.data)) and a restriction because of #155 is that the object this serializer is handling needs to have a pk property.

@Rjak
Copy link
Author

Rjak commented May 5, 2020

@sliverc I'm so sorry I missed your response!

You were correct about the GET. Postman happily sends GET requests with JSON bodies and Django happily parses them, but that's not the standard so I have switched to GET params.

I was able to implement a model-less serializer by extending rest_framework_json_api.serializers.Serializer and I'm now seeing a JSON:API-formatted response, which is great.

I'm now looking into getting pagination and filtering working. I'm guessing since I am in control of the model entirely I'm going to have to roll my own pagination and filtering, which is fine. Just looking at the DJA source to figure out how to do this since I'm having trouble finding examples.

Feel free to close this, thanks very much, and sorry about the delay!

@Rjak Rjak closed this as completed May 5, 2020
@kiawin
Copy link

kiawin commented May 14, 2020

Hi @Rjak, just to share that I've tried to implement a model-less DJA view. The pagination can be enabled by inserting a list of objects into paginate_queryset (instead of a QuerySet object):

some_list = [ ... ]
class SomeView(GenericViewSet):
	resource_name = "something"
	serializer_class = SomeSerializer

	def get_non_model_paginated_response(self, data):
		self.paginator.paginate_queryset(some_list, self.request)
        return self.get_paginated_response(data)

	def list(self, request):
		serializer = SomeSerializer(some_list, many=True)
		return self.get_non_model_paginated_response(serializer.data)

According to DRF, the paginate_queryset instantiate the page object which is to be used by get_paginated_response.

It's not a future-proof solution, as any future change to paginate_queryset to access queryset as a QuerySet object will likely result in an uncaught exception. Alternatively, we can override the method for peace of mind :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants