OrderingFilter in rest framework 2.4.3

166 views
Skip to first unread message

Wei She

unread,
Mar 5, 2015, 5:39:09 PM3/5/15
to django-res...@googlegroups.com
Hi,

I don't know if anybody knows this problem, or if it is due to my misuse. The problem is:  with the filter 'OrderingFilter', I cannot sort queryset by a column of a referenced model. See the following example:

class Machine(models.Model):
    pool = models.ForeignKey('pool')
    ......

class Pool(models.Model):
    name = models.CharField(max_length=32)
    ...

Machine has a foreign key pointing to Pool, where Pool has a field called 'name'. What we want is to sort machines by the name of its pool. So I pass a parameter 'ordering=pool__name' from the URL (like http://.../machines?ordering=pool__name).
However, the queryset cannot be properly sorted. So I checked the source code. In /.../site-packages/rest_framework/filters.py, I saw two methods:

----------------------------------------------------------------------------------------------------------------------------------------------------------------

156     def filter_queryset(self, request, queryset, view):
157         ordering = self.get_ordering(request)
158
159         if ordering:
160             # Skip any incorrect parameters
161             ordering = self.remove_invalid_fields(queryset, ordering, view)
162
163         if not ordering:
164             # Use 'ordering' attribute by default
165             ordering = self.get_default_ordering(view)
166
167         if ordering:
168             return queryset.order_by(*ordering)
169
170         return queryset

----------------------------------------------------------------------------------------------------------------------------------------------------------------

134     def remove_invalid_fields(self, queryset, ordering, view):
135         valid_fields = getattr(view, 'ordering_fields', self.ordering_fields)
136
137         if valid_fields is None:
138             # Default to allowing filtering on serializer fields
139             serializer_class = getattr(view, 'serializer_class')
140             if serializer_class is None:
141                 msg = ("Cannot use %s on a view which does not have either a "
142                        "'serializer_class' or 'ordering_fields' attribute.")
143                 raise ImproperlyConfigured(msg % self.__class__.__name__)
144             valid_fields = [
145                 field.source or field_name
146                 for field_name, field in serializer_class().fields.items()
147                 if not getattr(field, 'write_only', False)
148             ]
149         elif valid_fields == '__all__':
150             # View explictly allows filtering on any model field
151             valid_fields = [field.name for field in queryset.model._meta.fields]
152             valid_fields += queryset.query.aggregates.keys()
153
154         return [term for term in ordering if term.lstrip('-') in valid_fields]

----------------------------------------------------------------------------------------------------------------------------------------------------------------

As you can see, filter_queryset is based on "order_by" which will accept Django style, e.g. using "order_by('pool__name')". However, if I pass 'pool__name' into this method, it hits method 'remove_invalid_fields' and gets removed.
The problem is at line 151. Here, the model's fields are extracted. Therefore, 'pool_name' gets removed.

Anybody knows how to fix it, except letting me override filter_queryset again?

Thanks,
Wei
Reply all
Reply to author
Forward
0 new messages