title: Bulk requests in Django Rest Framework: What to pass as the serializer's "instance" argument?
body: <p>I am using a <code>ListSerializer</code> to process multiple objects at once. It accepts a JSON array of objects, i.e. <code>request.data</code> is a <code>list</code> of <code>dict</code>s on the Python side.</p>
  
  <p>In my <code>ListCreateAPIView</code>, I was considering to override <code>get_object()</code> in order to fetch the objects that are modified in a <code>PATCH</code> or <code>PUT</code> request. I planned to do this by looping over the objects given in the <code>request.data</code> list and fetching them from the database.</p>
  
  <p>(Note that for single-object requests, the generic workflow uses an URL-based lookup field to fetch the instance. However, you cannot identify multiple objects in the URL.)</p>
  
  <p>Unfortunately, this approach does not properly handle the case of invalid <code>request.data</code> input, e.g. when it is not a list. <strong>This is the root of the problem.</strong></p>
  
  <p>So, how to handle this? Here are a few ideas:</p>
  
  <ol>
  <li><p>Do an extra validation step in the <code>get_object()</code> view method.</p></li>
  <li><p>Don't populate <code>instance</code> in the serializer until calling <code>serializer.save()</code>, and modify the <code>save()</code> method such that existing instances are fetched and passed on to <code>update()</code>:</p></li>
  </ol>
  
  <pre class="lang-py prettyprint-override"><code>### in the serializer's save() method
  instance = get_instances_somehow(validated_data)  # not based on request.data
  if self.instance is not None:
      # in the generic workflow, this passes the pre-populated self.instance
      self.instance = self.update(instance, validated_data)
  else:
      self.instance = self.create(validated_data)
  
  return self.instance
  </code></pre>
  
  <ol start="3">
  <li>Initialize the serializer without passing an instance, then validate to make sure the payload is a list, then fetch the instance, like this:</li>
  </ol>
  
  <pre class="lang-py prettyprint-override"><code>### in the view's update() method
  serializer = self.get_serializer(None, data=request.data, many=True)
  serializer.is_valid(raise_exception=True)
  serializer.instance = self.get_object()  # this line differs from generic workflow
  self.perform_update(serializer)
  </code></pre>
  
  <p>Considerations:</p>
  
  <ol>
  <li><p>This approach seems ugly, as the <code>is_valid()</code> method of a serializer initialized with <code>many=True</code> already does this check. Further, validation is not the view's task. Unfortunately thought, <code>is_valid()</code> is called only after the view's <code>get_object()</code> method in the generic workflow, so <code>get_object()</code> has no access to validated data.</p></li>
  <li><p>This moves the instance fetching from the view's <code>get_object()</code> method to the serializer. As this also breaks the DRF conceptual structure, it is not a desirable solution as well.</p></li>
  <li><p>This seems most promising.</p></li>
  </ol>
  
  <p>However, there's another issue with approaches 2.) and 3.): The return value of the serializer's <code>data</code> property depends on whether <code>self.instance</code> is <code>None</code> or not. In other words, by setting the serializer's <code>instance</code> attribute later, users of the <code>data</code> property may get different data than otherwise. (If <code>self.instance</code> exists, then <code>data</code> corresponds to it, otherwise it corresponds to <code>validated_data</code>.)</p>
  
  <p>What is the best way to approach this?</p>
  
  <hr>
  
  <p><strong>Bonus question:</strong> Sometimes, validation depends on whether an instance is being modified or created. This can happen, for example, if the instance has a write-once field whose value is provided upon creation and cannot be changed later. Assuming that the field is not the primary key, the field consequently should only be considered "required" if no instance exists. This seems like a good reason to hand over the instances to the serializer as early as possible. However, what do you do if doing so requires accessing <code>request.data</code>, which one shall not do directly without calling <code>is_valid()</code> first?</p>