Django REST Framework: return 404 (not 400) on POST if related field does not exist?

2024/9/25 2:31:44

I'm developing a REST API which takes POST requests from some really brain-dead software which can't PATCH or anything else. The POSTs are to update Model objects which already exist in the database.

Specifically, I'm POSTing data for objects with a related field (a SlugRelatedField, as the POSTer knows the 'name' attribute but NOT the 'pk'). However, I need to return a 404 if the POSTer sends data where the 'name' returns nothing on the SlugRelatedField (e.g. the related object does not exist). I've been through this with a debugger but it seems that DRF uses some Django signals magic to do it The Way DRF Does It™, which is to return a 400 BAD REQUEST. I don't know how to modify this - only when it's the above condition and not a true 400-worthy POST - into a 404.

By the way, pre_save() in my view is NOT executing during execution of the failing test.

Here's the serializer:

class CharacterizationSerializer(serializers.ModelSerializer):"""Work-in-progress for django-rest-framework use.  This handles (de)serializationof data into a Characterization object and 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 to 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 the view where pre_save isn't being run in the given test (but does get run in some others):

class CharacterizationList(generics.ListCreateAPIView):queryset = Characterization.objects.all()serializer_class = CharacterizationSerializerpermission_classes = (AnonPostAllowed,)   # @todo XXX hack for braindead POSTerdef pre_save(self, obj):# user isn't sent as part of the serialized representation,# but is instead a property of the incoming request.if not self.request.user.is_authenticated():obj.owner = get_dummy_proxyuser()   # this is done for CharacterizationList so unauthed users can POST. @todo XXX hackelse:obj.owner = ProxyUser.objects.get(pk=self.request.user.pk)# here, we're fed a string sample name, but we need to look up# the actual sample model.# @TODO: Are we failing properly if it doesn't exist?  Should# throw 404, not 400 or 5xx.# except, this code doesn't seem to be run directly when debugging.# a 400 is thrown; DRF must be bombing out before pre_save?obj.sample = Sample.objects.get(name=self.request.DATA['sample'])

And for good measure, here's the 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 I put a breakpoint in at the self.rest_client.post() call, the response already has a 400 in it at that point.

Answer

You can use a Django Shortcut for that, getting the obj.sample:

from django.shortcuts import get_object_or_404
obj.sample = get_object_or_404(Sample, name=self.request.DATA['sample'])
https://en.xdnf.cn/q/71629.html

Related Q&A

How can i login in instagram with python requests?

Hello i am trying to login instagram with python requests library but when i try, instagram turns me "bad requests". İs anyone know how can i solve this problem?i searched to find a solve f…

How to abstract away command code in custom django commands

Im writing custom django commands under my apps management/commands directory. At the moment I have 6 different files in that directory. Each file has a different command that solves a unique need. How…

Python one-liner (converting perl to pyp)

I was wondering if its possible to make a one-liner with pyp that has the same functionality as this.perl -l -a -F, -p -eif ($. > 1) { $F[6] %= 12; $F[7] %= 12;$_ = join(q{,}, @F[6,7]) }This takes i…

Getting symbols with Lark parsing

Im trying to parse a little pseudo-code Im writing and having some trouble getting values for symbols. It parses successfully, but it wont return a value the same as it would with "regular" …

Why cant I connect to my localhost django dev server?

Im creating a django app and in the process of setting up my local test environment. I can successfully get manage.py runserver working but pointing my browser to any variation of http://127.0.0.1:8000…

How to use L2 pooling in Tensorflow?

I am trying to implement one CNN architecture that uses L2 pooling. The reference paper particularly argues that L2 pooling was better than max pooling, so I would like to try L2 pooling after the acti…

Abstract base class is not enforcing function implementation

from abc import abstractmethod, ABCMetaclass AbstractBase(object):__metaclass__ = ABCMeta@abstractmethoddef must_implement_this_method(self):raise NotImplementedError()class ConcreteClass(AbstractBase)…

Create dataframe from dictionary of list with variable length

I have a dictionary of list which is like - from collections import defaultdict defaultdict(list,{row1: [Affinity],row2: [Ahmc,Garfield,Medical Center],row3: [Alamance,Macbeth],row4: [],row5: [Mayday]}…

How to standardize ONE column in Spark using StandardScaler?

I am trying to standardize (mean = 0, std = 1) one column (age) in my data frame. Below is my code in Spark (Python):from pyspark.ml.feature import StandardScaler from pyspark.ml.feature import VectorA…

Pandas Dataframe - select columns with a specific value in a specific row

I want to select columns with a specific value (say 1) in a specific row (say first row) for Pandas Dataframe