          return field[1:], dirn[1]
      return field, dirn[0]
  
  
  def add_to_dict(data, key, value):
      """
      Add "value" to the set of values for "key", whether or not "key" already
      exists.
      """
      if key in data:
          data[key].add(value)
      else:
          data[key] = {value}
  
  
  def is_reverse_o2o(field):
      """
      Check if the given field is reverse-o2o. The field is expected to be some
      sort of relation field or related object.
      """
      return field.is_relation and field.one_to_one and not field.concrete
  
  
  class JoinPromoter:
      """
      A class to abstract away join promotion problems for complex filter
      conditions.
      """
 
</s> remove             # We need to load all fields for each model, except those that
            # appear in "seen" (for all models that appear in "seen"). The only
            # slight complexity here is handling fields that exist on parent
            # models.
            workset = {}
            for model, values in seen.items():
                for field in model._meta.local_fields:
                    if field not in values:
                        m = field.model._meta.concrete_model
                        add_to_dict(workset, m, field)
            for model, values in must_include.items():
                # If we haven't included a model in workset, we don't add the
                # corresponding must_include fields for that model, since an
                # empty set means "include all fields". That's why there's no
                # "else" branch here.
                if model in workset:
                    workset[model].update(values)
            for model, fields in workset.items():
                target[model] = {f.attname for f in fields}
        else:
            for model, values in must_include.items():
                if model in seen:
                    seen[model].update(values)
                else:
                    # As we've passed through this model, but not explicitly
                    # included any fields, we have to make sure it's mentioned
                    # so that only the "must include" fields are pulled in.
                    seen[model] = values
            # Now ensure that every model in the inheritance chain is mentioned
            # in the parent list. Again, it must be mentioned to ensure that
            # only "must include" fields are pulled in.
            for model in orig_opts.get_parent_list():
                seen.setdefault(model, set())
            for model, fields in seen.items():
                target[model] = {f.attname for f in fields}
 </s> add             return self._get_defer_select_mask(opts, mask)
        return self._get_only_select_mask(opts, mask) </s> remove     def test_iter_exceptions(self):
        qs = ExtraInfo.objects.only("author")
        msg = "'ManyToOneRel' object has no attribute 'attname'"
        with self.assertRaisesMessage(AttributeError, msg):
            list(qs)

 </s> add  </s> remove 
class DeferAnnotateSelectRelatedTest(TestCase):
 </s> add 
          return field[1:], dirn[1]
      return field, dirn[0]
  
  



















  class JoinPromoter:
      """
      A class to abstract away join promotion problems for complex filter
      conditions.
      """
keep keep keep keep replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace keep keep keep keep keep
 Fixed #21204 -- Tracked field deferrals by field instead of models.

This ensures field deferral works properly when a model is involved
more than once in the same query with a distinct deferral mask. 
django/db/models/sql/query.py