14π
I created an AliasedOrderingFilter that should fit this need rather well. It extends the ordering_fields attribute to allow tuples for fields as well as strings. For example you could set the views ordering_fields to:
ordering_fields = (('alias1', 'field1'),('alias2', 'field2'), 'field3')
Using this class in a request with ordering=alias1,-alias2,field3
will result in:
qs.order_by('field1', '-field2', 'field3)
The class:
class AliasedOrderingFilter(OrderingFilter):
''' this allows us to "alias" fields on our model to ensure consistency at the API level
We do so by allowing the ordering_fields attribute to accept a list of tuples.
You can mix and match, i.e.:
ordering_fields = (('alias1', 'field1'), 'field2', ('alias2', 'field2')) '''
def remove_invalid_fields(self, queryset, fields, view):
valid_fields = getattr(view, 'ordering_fields', self.ordering_fields)
if valid_fields is None or valid_fields == '__all__':
return super(AliasedOrderingFilter, self).remove_invalid_fields(queryset, fields, view)
aliased_fields = {}
for field in valid_fields:
if isinstance(field, basestring):
aliased_fields[field] = field
else:
aliased_fields[field[0]] = field[1]
ordering = []
for raw_field in fields:
invert = raw_field[0] == '-'
field = raw_field.lstrip('-')
if field in aliased_fields:
if invert:
ordering.append('-{}'.format(aliased_fields[field]))
else:
ordering.append(aliased_fields[field])
return ordering
17π
pip install django-filter
In your view:
from rest_framework import viewsets, filters
from django_filters.filters import OrderingFilter
from .models import MyList
from .serializers import MyListSerializer
class MyFilter(django_filters.FilterSet):
surname = django_filters.CharFilter(name="model_field_name_2")
order_by_field = 'ordering'
ordering = OrderingFilter(
# fields(('model field name', 'parameter name'),)
fields=(
('model_field_name_1', 'name'),
('model_field_name_2', 'surname'),
('model_field_name_3', 'email'),
)
)
class Meta:
model = MyList
fields = ['model_field_name_2',]
class MyListViewSet(viewsets.ModelViewSet):
serializer_class = MyListSerializer
filter_backends = (filters.DjangoFilterBackend,)
filter_class = MyFilter
def get_queryset(self):
return MyList.objects.all()
And you could do something like this:
/my-list?ordering=name,surname,email
/my-list?ordering=-email&surname=taylor
django-filter docs:
https://django-filter.readthedocs.io/en/latest/ref/filters.html#orderingfilter
drf docs:
http://www.django-rest-framework.org/api-guide/filtering/#djangofilterbackend
0π
Yes you can do that by using the ordering_fields
attribute in your view like:
class YourViewSet(viewsets.ModelViewSet):
serializer_class = yourSerializer
filter_backends = (filters.OrderingFilter,)
ordering_fields = ('field1', 'field2')
In ordering_fields
you mention all the fields by which you want to allow ordering.
Here field1
and field2
need not be present in the serializer fields
attribute and therefore they wonβt be in your API response.
Update:
Your request url should be like:
http://example.com/api/users?ordering=field1
ordering
is the query parameter. You need to set ordering
with the field name with which you want to order your queryset.
you can learn more here
- Add context to every Django Admin page
- Django, loop over all form errors
- Python urlparse.parse_qs unicode url