python - Django REST Framework: return 404 (not 400) on POST if related field does not exist? -
i'm developing rest api takes post requests brain-dead software can't patch or else. posts update model objects exist in database.
specifically, i'm posting data objects related field (a slugrelatedfield, poster knows 'name' attribute not 'pk'). however, need return 404 if poster sends data 'name' returns nothing on slugrelatedfield (e.g. related object not exist). i've been through debugger seems drf uses django signals magic way drf it™, return 400 bad request. don't know how modify - only when it's above condition , not true 400-worthy post - 404.
by way, pre_save()
in view not executing during execution of failing test.
here's serializer:
class characterizationserializer(serializers.modelserializer): """ work-in-progress django-rest-framework use. handles (de)serialization of data characterization object , vice versa. see: http://www.django-rest-framework.org/tutorial/1-serialization """ creator = serializers.field(source='owner.user.username') sample = serializers.slugrelatedfield(slug_field='name', required=true, many=false, read_only=false) class meta: model = characterization # leaving 'request' out because it's been decided deprecate it. (...maybe?) fields = ('sample', 'date', 'creator', 'comments', 'star_volume', 'solvent_volume', 'solution_center', 'solution_var', 'solution_minimum', 'solution_min_stddev', 'solution_test_len',)
and here's view pre_save
isn't being run in given test (but run in others):
class characterizationlist(generics.listcreateapiview): queryset = characterization.objects.all() serializer_class = characterizationserializer permission_classes = (anonpostallowed,) # @todo xxx hack braindead poster def pre_save(self, obj): # user isn't sent part of serialized representation, # instead property of incoming request. if not self.request.user.is_authenticated(): obj.owner = get_dummy_proxyuser() # done characterizationlist unauthed users can post. @todo xxx hack else: obj.owner = proxyuser.objects.get(pk=self.request.user.pk) # here, we're fed string sample name, need # actual sample model. # @todo: failing if doesn't exist? should # throw 404, not 400 or 5xx. # except, code doesn't seem run directly when debugging. # 400 thrown; drf must bombing out before pre_save? obj.sample = sample.objects.get(name=self.request.data['sample'])
and measure, here's failing test:
def test_bad_post_single_missing_sample(self): url = reverse(self._post_one_view_name) my_sample_postdict = self.dummy_plqy_postdict.copy() my_sample_postdict["sample"] = "i_dont_exist_lul" response = self.rest_client.post(url, my_sample_postdict) self.asserttrue(response.status_code == 404, "expected 404 status code, got %d (%s). content: %s" % (response.status_code, response.reason_phrase, response.content))
if put breakpoint in @ self.rest_client.post()
call, response has 400 in @ point.
instead of using pre_save
why not override post
in api view:
def post(self, request, *args, **kwargs): ...other stuff try: obj.sample = sample.objects.get(name=self.request.data['sample']) ...or whatever other tests want except: return response(status=status.http_404_not_found) response = super(characterizationlist, self).post(request, *args, **kwargs) return response
make sure import drf's status:
from rest_framework import status
also, note want more specific exceptions catch. django's get
method return either doesnotexist
if nothing matches or multipleobjectsreturned
if more 1 object matches. the relevant documentation:
note there difference between using get(), , using filter() slice of [0]. if there no results match query, get() raise doesnotexist exception. exception attribute of model class query being performed on - in code above, if there no entry object primary key of 1, django raise entry.doesnotexist.
similarly, django complain if more 1 item matches get() query. in case, raise multipleobjectsreturned, again attribute of model class itself.
Comments
Post a Comment