2

I'm having some issues getting an index view working. When the database query returns a list of objects, it's all good. But when the query comes empty — because there are no records yet — the response isn't quite what I expect:

if request.method == 'GET':
    powers = Power.objects.get(hero=hero_id);

    if powers:
        serializer = PowerSerializer(powers)
        return Response(serializer.data)

    context = {"message": "This hero has no powers... yet!"}
    return Response(context, status=status.HTTP_200_OK)

The above code works flawlessly when a hero has powers. But when the hero has no powers, I expect to see the custom message but I'm instead getting HTTP 404 Not Found. I tried changing to status=status.HTTP_204_NO_CONTENT but, no difference — the same 404 pops up. Since I've never developed an API before, I'm not quite sure if this is how things should work.

I've combed the documentation and all I've found is how to handle one resource that doesn't exist — using return Response(status=status.HTTP_404_NOT_FOUND). So how do I handle a list of multiple resources that don't exist?

Please advise.

Zero
  • 717
  • 6
  • 21
  • 1
    Possible duplicate of [In Django, how do I objects.get, but return None when nothing is found?](http://stackoverflow.com/questions/3090302/in-django-how-do-i-objects-get-but-return-none-when-nothing-is-found) – rnevius Mar 10 '16 at 00:50
  • @rnevius Even if I return None, how do I get the API to respond with the custom message that I've provided in the context object? – Zero Mar 14 '16 at 18:52
  • @Duos Did my answer help you? If so accept it , please. – ilse2005 Mar 15 '16 at 11:18
  • @ilse2005 It didn't help, but I've upvoted your answer because it gave me a fresh perspective. – Zero Mar 15 '16 at 12:26

1 Answers1

2

You are using objects.get. This will throw a DoesNotExist error if the object does not exist. You have to catch this error:

if request.method == 'GET':
    try:
        powers = Power.objects.get(hero=hero_id);

        serializer = PowerSerializer(powers)
        return Response(serializer.data)
    except Power.DoesNotExist:
        context = {"message": "This hero has no powers... yet!"}
        return Response(context, status=status.HTTP_200_OK)

But if I understand it right a hero can have multiple powers, right? So you probably want to change your query to Power.objects.filter(hero=hero_id) to get all powsers of a hero. Then your code should work.

EDIT:

This is how Duos solved the problem eventually:

You are using objects.get() which is only appropriate when you are querying for exactly one object. It appears you want to return a collection of objects — a hero has many powers — so you should use objects.filter().

Also, if a serializer has multiple objects as its response, it should have many=True, otherwise it'll throw an error.

The context message isn't necessary, if there are no powers, just return the empty list to the client to handle accordingly:

if request.method == 'GET':
    powers = Power.objects.filter(hero=hero_id)
    if powers:
        serializer = PowerSerializer(powers, many=True)
        return Response(serializer.data)
    return Response(powers, status=status.HTTP_200_OK)
ilse2005
  • 11,189
  • 5
  • 51
  • 75
  • Well, the `try` block is something I should've included. Nevertheless, neither your code works. I've tried it but the same error 404 error. And I've tried both `objects.get()` and `objects.filter()`. No luck, still. – Zero Mar 10 '16 at 01:16
  • And I've just realized that this code only works for getting only one object, and in Django is most commonly used in detail views. The context here is an index view, and the `try` block is not applicable, as it will return only one record. Normally, index views use `objects.all()`, `objects.get()`, or `objects.filter()`. – Zero Mar 10 '16 at 01:39
  • Yes. That I was trying to tell you in my answer – ilse2005 Mar 10 '16 at 09:56
  • Okay. I've tried different code permutations and I've concluded that yours is the way to do it. So basically whether it's one object that does not exist, or it's many objects that do not exist, Django throws the same `DoesNotExist` error? – Zero Mar 15 '16 at 17:34
  • @Duos, Your edit won't work. `filter` does not throw an exception if no records are found. It will just return an empty list. – ilse2005 Mar 15 '16 at 18:59
  • My edit is how I got my code to pass. And it's exactly what you suggested in your answer above: _"So you probably want to change your query to Power.objects.filter(hero=hero_id) to get all powsers of a hero. Then your code should work."_ Anyway, after reading your last comment, I tried a new approach that works. You'll have to accept the edit if I'm to accept your answer. – Zero Mar 16 '16 at 00:10