Django-rest-framework: рдСрд░реНрдбрд░рд┐рдВрдЧрдлрд╝рд┐рд▓реНрдЯрд░ рдореЗрдВ рдиреЗрд╕реНрдЯреЗрдб рд╕рдВрдмрдВрдзрд┐рдд рдлрд╝реАрд▓реНрдб рджреНрд╡рд╛рд░рд╛ рдСрд░реНрдбрд░ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рд╕рдорд░реНрдерди

рдХреЛ рдирд┐рд░реНрдорд┐рдд 25 рдЬреБрд▓ре░ 2013  ┬╖  28рдЯрд┐рдкреНрдкрдгрд┐рдпрд╛рдБ  ┬╖  рд╕реНрд░реЛрдд: encode/django-rest-framework

рдЙрдкрдпреЛрдЧ рдХрд╛ рдЙрджрд╛рд╣рд░рдг рдПрдХ рдиреЗрд╕реНрдЯреЗрдб рд╕рдВрдмрдВрдзрд┐рдд рд╡рд╕реНрддреБ рджреНрд╡рд╛рд░рд╛ рдЫрдБрдЯрд╛рдИ рд╣реЛрдЧреАред

рдиреЗрд╕реНрдЯреЗрдб рдкреНрд░рддрд┐рдирд┐рдзрд┐рддреНрд╡:

{
    'username': 'george',
    'email': '[email protected]'
    'stats': {
        'facebook_friends': 560,
        'twitter_followers': 4043,
        ...
    },
},
{
    'username': 'michael',
    'email': '[email protected]'
    'stats': {
        'facebook_friends': 256,
        'twitter_followers': 120,
        ...
    },
},
...

рдПрдХ рд╡рд┐рдХрд▓реНрдк рд╕рдВрдмрдВрдзрд┐рдд рдореЙрдбрд▓реЛрдВ рдХреЗ рд▓рд┐рдП django orm рдбрдмрд▓ рдЕрдВрдбрд░рд╕реНрдХреЛрд░ рдиреЛрдЯреЗрд╢рди __ рдХрд╛ рд╕рдорд░реНрдерди рдХрд░рдирд╛ рд╣реИред

рднреВрддрдкреВрд░реНрд╡ред ?ordering=stats__facebook_friends facebook_friends рджреНрд╡рд╛рд░рд╛ рдХреНрд░рдордмрджреНрдз рдХрд┐рдпрд╛ рдЬрд╛рдПрдЧрд╛ред

рд╡рд░реНрддрдорд╛рди рдореЗрдВ рдСрд░реНрдбрд░рд┐рдВрдЧ рдХреЗрд╡рд▓ рдХреНрд╡реЗрд░реАрд╕реЗрдЯ рдореЗрдВ рдирд┐рд░реНрджрд┐рд╖реНрдЯ рд╡рд┐рд╢реЗрд╖ рдореЙрдбрд▓ рдХреЗ рдХреНрд╖реЗрддреНрд░реЛрдВ рдХреЗ рд▓рд┐рдП рдХрд╛рдо рдХрд░рддрд╛ рд╣реИред

https://github.com/tomchristie/django-rest-framework/blob/master/rest_framework/filters.py#L125

рд╕рдмрд╕реЗ рдЙрдкрдпреЛрдЧреА рдЯрд┐рдкреНрдкрдгреА

рдЯрд┐рдк рдХреЗ рд▓рд┐рдП рдзрдиреНрдпрд╡рд╛рдж: +1:ред рд▓рд┐рдВрдХ рдареАрдХ рдХрд░рдиреЗ рджреЗрддрд╛ рд╣реИред рдпрд╣ рд╕рд╣реА рд╣реИ

from django.core.exceptions import FieldDoesNotExist
from django.db.models.fields.related import ForeignObjectRel
from rest_framework.filters import OrderingFilter


class RelatedOrderingFilter(OrderingFilter):
    """
    Extends OrderingFilter to support ordering by fields in related models
    using the Django ORM __ notation
    """
    def is_valid_field(self, model, field):
        """
        Return true if the field exists within the model (or in the related
        model specified using the Django ORM __ notation)
        """
        components = field.split('__', 1)
        try:
            field, parent_model, direct, m2m = \
                model._meta.get_field_by_name(components[0])

            # reverse relation
            if isinstance(field, ForeignObjectRel):
                return self.is_valid_field(field.model, components[1])

            # foreign key
            if field.rel and len(components) == 2:
                return self.is_valid_field(field.rel.to, components[1])
            return True
        except FieldDoesNotExist:
            return False

    def remove_invalid_fields(self, queryset, ordering, view):
        return [term for term in ordering
                if self.is_valid_field(queryset.model, term.lstrip('-'))]

рд╕рднреА 28 рдЯрд┐рдкреНрдкрдгрд┐рдпрд╛рдБ

рдореИрдВ рдЗрд╕рдХреЗ рд▓рд┐рдП рдкреБрд▓ рдЕрдиреБрд░реЛрдзреЛрдВ рдкрд░ рд╡рд┐рдЪрд╛рд░ рдХрд░реВрдВрдЧрд╛, рд▓реЗрдХрд┐рди рдРрд╕рд╛ рдХреБрдЫ рдирд╣реАрдВ рд╣реИ рдЬреЛ рдореЗрд░реЗ рдкрд╛рд╕ рдЦреБрдж рдХрд░рдиреЗ рдХрд╛ рд╕рдордп рд╣реЛрдЧрд╛ред

рдлрд╝рд┐рд▓реНрдЯрд░рд┐рдВрдЧ рдореЗрдВ рдЧрд▓рдд рдлрд╝реАрд▓реНрдб рдирд╛рдореЛрдВ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд┐рдП рдЬрд╛рдиреЗ рдкрд░ рдЗрд╕реЗ рд▓рд╛рдЧреВ рдХрд░рдиреЗ рд╡рд╛рд▓реЗ рдХрд┐рд╕реА рднреА рд╡реНрдпрдХреНрддрд┐ рдХреЛ рд╕рдордЭрджрд╛рд░ рд╡реНрдпрд╡рд╣рд╛рд░ рд╕реБрдирд┐рд╢реНрдЪрд┐рдд рдХрд░рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реЛрддреА рд╣реИред рдПрдХ рдиреНрдпреВрдирддрдо рдкрд░ рдкрд░рд┐рдгрд╛рдо рдЕрднреА рднреА рдареАрдХ рд▓реМрдЯрдирд╛ рдЪрд╛рд╣рд┐рдПред (рдЖрджрд░реНрд╢ рд░реВрдк рд╕реЗ, рдХрд┐рд╕реА рднреА рдЧрд▓рдд рдлрд╝реАрд▓реНрдб рдирд╛рдореЛрдВ рдХреЛ рдЕрдирджреЗрдЦрд╛ рдХрд┐рдпрд╛ рдЬрд╛рдирд╛ рдЪрд╛рд╣рд┐рдП, рд▓реЗрдХрд┐рди рдЕрдиреНрдп рдлрд╝реАрд▓реНрдб рдХреЛ рдЫреЛрдбрд╝ рджрд┐рдпрд╛ рдЬрд╛рдирд╛ рдЪрд╛рд╣рд┐рдПред)

рд╡рд┐рдЪрд╛рд░ рдХрд░рдиреЗ рдкрд░ рдореИрдВ рдЗрд╕реЗ рдмрдВрдж рдХрд░рдиреЗ рдЬрд╛ рд░рд╣рд╛ рд╣реВрдВред рдЕрдЧрд░ рдХреЛрдИ рдкреБрд▓ рдЕрдиреБрд░реЛрдз рдЬрд╛рд░реА рдХрд░рддрд╛ рд╣реИ рдФрд░ рдЗрд╕рд╕реЗ рд╕рдВрдмрдВрдзрд┐рдд рдкрд░реАрдХреНрд╖рдг рдХрд░рддрд╛ рд╣реИ рддреЛ рдореИрдВ рдкреБрдирд░реНрд╡рд┐рдЪрд╛рд░ рдХрд░ рд╕рдХрддрд╛ рд╣реВрдВ, рд▓реЗрдХрд┐рди рдореВрд▓ рдлрд╝рд┐рд▓реНрдЯрд░рд┐рдВрдЧ рдХрдХреНрд╖рд╛рдУрдВ рдореЗрдВ рд╕реЗ рдкреНрд░рддреНрдпреЗрдХ рдХрд╛ рдЕрдзрд┐рдХ рдкреВрд░реНрдг рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди рд╡рд╛рд╕реНрддрд╡ рдореЗрдВ рдРрд╕рд╛ рдХреБрдЫ рд╣реИ рдЬреЛ рдХрд┐рд╕реА рддреАрд╕рд░реЗ рдкрдХреНрд╖ рдХреЗ рдкреИрдХреЗрдЬ рдореЗрдВ рд╡рд╛рд╕реНрддрд╡ рдореЗрдВ рдЕрдЪреНрдЫреА рддрд░рд╣ рд╕реЗ рдирд┐рдкрдЯ рд╕рдХрддрд╛ рд╣реИ, рдЬрд┐рд╕реЗ рддрдм рдЕрд▓рдЧ рд╕реЗ рдмрдирд╛рдП рд░рдЦрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИ, рдФрд░ рдореБрдЦреНрдп рдбреЙрдХреНрд╕ рд╕реЗ рдЬреБрдбрд╝рд╛ рд╣реБрдЖ рд╣реИред

рдХреЛрдИ рдкреБрд▓ рдЕрдиреБрд░реЛрдз рдирд╣реАрдВ рд╣реИ рдХреНрдпреЛрдВрдХрд┐ рдореЗрд░реЗ рдкрд╛рд╕ рдкрд░реАрдХреНрд╖рдг рдпрд╛ рджрд╕реНрддрд╛рд╡реЗрдЬрд╝ рд▓рд┐рдЦрдиреЗ рдХрд╛ рд╕рдордп рдирд╣реАрдВ рд╣реИ, рд▓реЗрдХрд┐рди рдЕрдЧрд░ рдпрд╣ рдЕрдиреНрдп рд▓реЛрдЧреЛрдВ рдХреЛ рдЗрд╕ рдореБрджреНрджреЗ рдХреЛ рдЦреЛрдЬрдиреЗ рдореЗрдВ рдорджрдж рдХрд░рддрд╛ рд╣реИ, рддреЛ рдореИрдВ рдЗрд╕рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░ рд░рд╣рд╛ рд╣реВрдВ:

from django.db.models.fields import FieldDoesNotExist 
from rest_framework.filters import OrderingFilter

class RelatedOrderingFilter(OrderingFilter):
    """ 
    Extends OrderingFilter to support ordering by fields in related models
    using the Django ORM __ notation
    """
    def is_valid_field(self, model, field):
        """
        Return true if the field exists within the model (or in the related 
        model specified using the Django ORM __ notation)
        """
        components = field.split('__', 1)
        try:
            field, parent_model, direct, m2m = model._meta.get_field_by_name(components[0])
            if field.rel and len(components) == 2:
                return self.is_valid_field(field.rel.to, components[1])
            return True
        except FieldDoesNotExist:
            return False

    def remove_invalid_fields(self, queryset, ordering):
        return [term for term in ordering if self.is_valid_field(queryset.model, term.lstrip('-'))]

@rhunwicks рдЖрдкрдХрд╛ рд╕рдВрд╕реНрдХрд░рдг рд░рд┐рд╡рд░реНрд╕ рд░рд┐рд▓реЗрд╢рди рд╕реЙрд░реНрдЯрд┐рдВрдЧ рдХреА рдЕрдиреБрдорддрд┐ рдирд╣реАрдВ рджреЗрддрд╛ рд╣реИ, рдХреЗрд╡рд▓ рдкреНрд░рддреНрдпрдХреНрд╖ fk рдХрд╛ рдпрд╣рд╛рдВ рдкреИрдЪ рдХрд┐рдпрд╛ рдЧрдпрд╛ рд╕рдВрд╕реНрдХрд░рдг рд╣реИ

class RelatedOrderingFilter(OrderingFilter):
    """
    Extends OrderingFilter to support ordering by fields in related models
    using the Django ORM __ notation
    """
    def is_valid_field(self, model, field):
        """
        Return true if the field exists within the model (or in the related
        model specified using the Django ORM __ notation)
        """
        components = field.split('__', 1)
        try:
            field, parent_model, direct, m2m = \
                model._meta.get_field_by_name(components[0])

            # reverse relation
            if isinstance(field, RelatedObject):
                return self.is_valid_field(field.model, components[1])

            # foreign key
            if field.rel and len(components) == 2:
                return self.is_valid_field(field.rel.to, components[1])
            return True
        except FieldDoesNotExist:
            return False

    def remove_invalid_fields(self, queryset, ordering, view):
        return [term for term in ordering
                if self.is_valid_field(queryset.model, term.lstrip('-'))]

pySilver рдХреЗ рд╕реНрдирд┐рдкреЗрдЯ рдиреЗ рдореЗрд░реЗ рд▓рд┐рдП рдЕрдЪреНрдЫрд╛ рдХрд╛рдо рдХрд┐рдпрд╛, рдХреНрдпрд╛ рд╣рдо рдЗрд╕реЗ рдХрд┐рд╕реА рднреА рдореМрдХреЗ рдкрд░ DRF рдореЗрдВ рд▓рд╛ рд╕рдХрддреЗ рд╣реИрдВ?

рдЖрдк RelatedObject рдХрд╣рд╛рдБ рд╕реЗ рдЖрдпрд╛рдд рдХрд░рддреЗ рд╣реИрдВ? рдореЗрд░реЗ рд▓рд┐рдП рдЙрдкрд▓рдмреНрдз рдирд╣реАрдВ рдкреНрд░рддреАрдд рд╣реЛрддрд╛ рд╣реИ

Python 3.4.3
Django==1.8.5
djangorestframework==3.2.3

@eldamir django.db.models.

ImportError: No module named 'django.db.models.related'

рдЖрд╣, рдРрд╕рд╛ рд▓рдЧрддрд╛ рд╣реИ рдХрд┐ рдЗрд╕реЗ 1.8 рд╕реЗ рд╣рдЯрд╛ рджрд┐рдпрд╛ рдЧрдпрд╛ рд╣реИ, рджреЗрдЦреЗрдВ https://code.djangoproject.com/ticket/21414

рдЯрд┐рдк рдХреЗ рд▓рд┐рдП рдзрдиреНрдпрд╡рд╛рдж: +1:ред рд▓рд┐рдВрдХ рдареАрдХ рдХрд░рдиреЗ рджреЗрддрд╛ рд╣реИред рдпрд╣ рд╕рд╣реА рд╣реИ

from django.core.exceptions import FieldDoesNotExist
from django.db.models.fields.related import ForeignObjectRel
from rest_framework.filters import OrderingFilter


class RelatedOrderingFilter(OrderingFilter):
    """
    Extends OrderingFilter to support ordering by fields in related models
    using the Django ORM __ notation
    """
    def is_valid_field(self, model, field):
        """
        Return true if the field exists within the model (or in the related
        model specified using the Django ORM __ notation)
        """
        components = field.split('__', 1)
        try:
            field, parent_model, direct, m2m = \
                model._meta.get_field_by_name(components[0])

            # reverse relation
            if isinstance(field, ForeignObjectRel):
                return self.is_valid_field(field.model, components[1])

            # foreign key
            if field.rel and len(components) == 2:
                return self.is_valid_field(field.rel.to, components[1])
            return True
        except FieldDoesNotExist:
            return False

    def remove_invalid_fields(self, queryset, ordering, view):
        return [term for term in ordering
                if self.is_valid_field(queryset.model, term.lstrip('-'))]

Django рдмрд╛рдХреА рдврд╛рдВрдЪреЗ рдХреЗ рдЕрдВрддрд┐рдо рд╕рдВрд╕реНрдХрд░рдг рдХреЗ рд╕рд╛рде рд╕рдорд╕реНрдпрд╛ рдирд╣реАрдВ рдереА :)

рдЕрдкрдирд╛ ordering_fields рд╕рд╣реА рдврдВрдЧ рд╕реЗ рдирд┐рд░реНрджрд┐рд╖реНрдЯ рдХрд░рдирд╛ рди рднреВрд▓реЗрдВ

рдмрд╕ рдПрдХ рдиреЛрдЯ - Django> 1.10 рдореЗрдВ рдХреБрдЫ рддрд░реАрдХреЗ рдмрджрд▓ рдЧрдП рд╣реИрдВ

рд╡рд┐рд╢реЗрд╖ рд░реВрдк рд╕реЗ рдЖрдкрдХреЛ рдирд┐рдореНрдирд▓рд┐рдЦрд┐рдд рдХреЛ рдмрджрд▓рдирд╛ рд╣реЛрдЧрд╛:

field, parent_model, direct, m2m = model._meta.get_field_by_name(components[0])
рдкреНрд░рддрд┐
field = model._meta.get_field(components[0])

рдФрд░ remove_invalid_fields рд▓рд┐рдП рд╣рд╕реНрддрд╛рдХреНрд╖рд░ рдмрджрд▓ рдЧрдпрд╛ рд╣реИ:

def remove_invalid_fields(self, queryset, ordering, view, request):

рдЬрд┐рд╕рдХреЗ рдкрд░рд┐рдгрд╛рдорд╕реНрд╡рд░реВрдк Django> 1.10 рдХреЗ рд▓рд┐рдП рдЕрдВрддрд┐рдо рдХрд╛рд░реНрдпрд╢реАрд▓ рд╕рдВрд╕реНрдХрд░рдг:

class RelatedOrderingFilter(OrderingFilter):
    """
    Extends OrderingFilter to support ordering by fields in related models
    using the Django ORM __ notation
    """
    def is_valid_field(self, model, field):
        """
        Return true if the field exists within the model (or in the related
        model specified using the Django ORM __ notation)
        """
        components = field.split('__', 1)
        try:

            field = model._meta.get_field(components[0])

            # reverse relation
            if isinstance(field, ForeignObjectRel):
                return self.is_valid_field(field.model, components[1])

            # foreign key
            if field.rel and len(components) == 2:
                return self.is_valid_field(field.rel.to, components[1])
            return True
        except FieldDoesNotExist:
            return False

    def remove_invalid_fields(self, queryset, fields, view, request):
        return [term for term in fields if self.is_valid_field(queryset.model, term.lstrip('-'))]

рдЙрдкрд░реЛрдХреНрдд рдХреЛрдб рдореЗрдВ OneToOneField рдХреЗ рд╕рд╛рде рд╕рдорд╕реНрдпрд╛ рд╣реЛрдЧреА, рдЗрд╕рдХреЗ рд▓рд┐рдП рдПрдХ рдлрд┐рдХреНрд╕ рдЬреЛрдбрд╝рдирд╛:

from django.core.exceptions import FieldDoesNotExist
from django.db.models.fields.reverse_related import ForeignObjectRel, OneToOneRel

from rest_framework.filters import OrderingFilter


class RelatedOrderingFilter(OrderingFilter):
    """
    Extends OrderingFilter to support ordering by fields in related models.
    """    

    def is_valid_field(self, model, field):
        """
        Return true if the field exists within the model (or in the related
        model specified using the Django ORM __ notation)
        """
        components = field.split('__', 1)
        try:

            field = model._meta.get_field(components[0])

            if isinstance(field, OneToOneRel):
                return self.is_valid_field(field.related_model, components[1])

            # reverse relation
            if isinstance(field, ForeignObjectRel):
                return self.is_valid_field(field.model, components[1])

            # foreign key
            if field.rel and len(components) == 2:
                return self.is_valid_field(field.rel.to, components[1])
            return True
        except FieldDoesNotExist:
            return False

    def remove_invalid_fields(self, queryset, fields, view):
        return [term for term in fields
                if self.is_valid_field(queryset.model, term.lstrip('-'))]        

field.rel рдФрд░ field.rel.to Django>= 1.10 рдкрд░ рдПрдХ рдмрд╣рд┐рд╖реНрдХрд░рдг рдЪреЗрддрд╛рд╡рдиреА рдмрдврд╝рд╛рдПрдВрдЧреЗред рд╡реЗ рдЕрдм рдХреНрд░рдорд╢рдГ рд╣реИрдВ:

  • рдлрд╝реАрд▓реНрдб.рд░рд┐рдореЛрдЯ_рдлрд╝реАрд▓реНрдб
  • рдХреНрд╖реЗрддреНрд░.рдореЙрдбрд▓

@tomchristie рдЗрд╕ рдкреИрдЪ рдкрд░ рд╡рд┐рдЪрд╛рд░ рдХрд░ рд░рд╣рд╛ рд╣реИ (рдФрд░ рд▓рдЧрд╛рддрд╛рд░ рдЕрдкрдбреЗрдЯ рдХрд┐рдпрд╛ рдЬрд╛ рд░рд╣рд╛ рд╣реИ) рдЗрд╕ рдореБрджреНрджреЗ рдореЗрдВ 4 рд╕рд╛рд▓ рдХреЗ рд▓рд┐рдП (рд╣рдо рдкрд┐рдЫрд▓реЗ рд╕рд╛рд▓ рд╕реЗ рдЙрддреНрдкрд╛рджрди рдореЗрдВ рдЗрд╕рдХрд╛ рдЗрд╕реНрддреЗрдорд╛рд▓ рдХрд░ рд░рд╣реЗ рд╣реИрдВ), рдХреНрдпрд╛ рдпрд╣ рдкреАрдЖрд░ рдХреЗ рд▓рд┐рдП рдЙрдкрдпреБрдХреНрдд рд╣реЛ рд╕рдХрддрд╛ рд╣реИ рдФрд░ рдбреАрдЖрд░рдПрдл рдореЗрдВ рд╡рд┐рд▓рдп рд╣реЛ рд╕рдХрддрд╛ рд╣реИ (рд╣рд╛рдВ, рдмреИрдХ рдЕрдк рджреНрд╡рд╛рд░рд╛ рд╕рдорд░реНрдерд┐рдд) Unittests рдХрд╛ рдПрдХ рдЙрдЪрд┐рдд рд╕реЗрдЯ)?

рдмрд╕ рдореЗрд░рд╛ .2 рд╕реЗрдВрдЯ

рдпрд╣ рдкреИрдЪ рдореЗрд░реЗ рд▓рд┐рдП рдХрд╛рдо рдХрд░рддрд╛ рд╣реИ, рдХреНрдпрд╛ рд╣рдо рдЗрд╕реЗ рд░рд┐рд▓реАрдЬрд╝ рд╕рдВрд╕реНрдХрд░рдгреЛрдВ рдореЗрдВ рдорд░реНрдЬ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ?

рдЬреИрд╕рд╛ рдХрд┐ рдкрд╣рд▓реЗ рдХрд╣рд╛ рдЧрдпрд╛ рд╣реИ, рдпрд╛ рддреЛ рдЗрд╕реЗ рдПрдХ рддреГрддреАрдп рдкрдХреНрд╖ (рдкрд╕рдВрджреАрджрд╛) рдмрдирд╛рдПрдВ рдпрд╛ рдЗрд╕реЗ рдкрд░реАрдХреНрд╖рдг рдФрд░ рджрд╕реНрддрд╛рд╡реЗрдЬрд╝реАрдХрд░рдг рдХреЗ рд╕рд╛рде рдЙрдЪрд┐рдд рдкреАрдЖрд░ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИред

@filiperinaldi рдореБрдЭреЗ рд▓рдЧрддрд╛ рд╣реИ рдХрд┐ Django >= 1.10 field.rel.to field.related_model рдмрди рдЬрд╛рддрд╛ рд╣реИред рдпрд╣рд╛рдБ рдкреИрдЪ рдХрд╛ рдирд╡реАрдирддрдо рд╕рдВрд╕реНрдХрд░рдг рд╣реИ рдЬреЛ рд╣рдорд╛рд░реЗ рдпреВрдирд┐рдЯрдЯреЗрд╕реНрдЯ рдХреЛ рдкрд╛рд╕ рдХрд░рддрд╛ рд╣реИред

nb рд╣рдо Django 1.11 рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░ рд░рд╣реЗ рд╣реИрдВ рдЗрд╕рд▓рд┐рдП ymmw

class RelatedOrderingFilter(filters.OrderingFilter):
    """

    See: https://github.com/tomchristie/django-rest-framework/issues/1005

    Extends OrderingFilter to support ordering by fields in related models
    using the Django ORM __ notation
    """
    def is_valid_field(self, model, field):
        """
        Return true if the field exists within the model (or in the related
        model specified using the Django ORM __ notation)
        """
        components = field.split('__', 1)
        try:
            field = model._meta.get_field(components[0])

            if isinstance(field, OneToOneRel):
                return self.is_valid_field(field.related_model, components[1])

            # reverse relation
            if isinstance(field, ForeignObjectRel):
                return self.is_valid_field(field.model, components[1])

            # foreign key
            if field.remote_field and len(components) == 2:
                return self.is_valid_field(field.related_model, components[1])
            return True
        except FieldDoesNotExist:
            return False

    def remove_invalid_fields(self, queryset, fields, ordering, view):
        return [term for term in fields
                if self.is_valid_field(queryset.model, term.lstrip('-'))]

рдареАрдХ рд╣реИ рд▓реЛрдЧ, рдЗрд╕ рдЕрдВрдХ рдХреЗ рдЪреМрдереЗ рдЬрдиреНрдорджрд┐рди рдХреЗ рд▓рд┐рдП, рдореИрдВрдиреЗ рдЗрд╕реЗ рдЖрдЬрдорд╛рдиреЗ рдХрд╛ рдлреИрд╕рд▓рд╛ рдХрд┐рдпрд╛ рдФрд░ рдЗрд╕ рдЙрдкрдпреЛрдЧреА рдЖрджреЗрд╢ рдХрд╛ рд╕рдорд░реНрдерди рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдбреАрдЖрд░рдПрдл рдХреЗ рд╕рд╛рде рд╕реНрдерд╛рдкрд┐рдд рдХрд┐рдП рдЬрд╛рдиреЗ рд╡рд╛рд▓реЗ рдмрд╛рд╣рд░реА рдкреИрдХреЗрдЬ рдХреЛ рдПрдХ рд╕рд╛рде рд╣реИрдХ рдХрд░рдиреЗ рдХрд╛ рдлреИрд╕рд▓рд╛ рдХрд┐рдпрд╛:

https://github.com/apiraino/djangorestframework_custom_filters_ordering

рдореИрдВ рдХрд╛рдо рдЦрддреНрдо рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдЕрдЧрд▓реЗ рджрд┐рдиреЛрдВ рдореЗрдВ рдЗрд╕ рдкрд░ рдХрд╛рдо рдХрд░реВрдВрдЧрд╛ (рдЕрд░реНрдерд╛рддреН рдореБрдЭреЗ рдХреЛрдб рдХреЛ рдареАрдХ рд╕реЗ рдкреИрдХреЗрдЬ рдФрд░ рдлреИрдХреНрдЯрд░ рдХрд░рдиреЗ, рдкрд░реАрдХреНрд╖рдг рдХреЛ рдкрд░рд┐рд╖реНрдХреГрдд рдХрд░рдиреЗ рдФрд░ рд╕рдХреНрд░рд┐рдп рд░реВрдк рд╕реЗ рд╕рдорд░реНрдерд┐рдд Django рд╕рдВрд╕реНрдХрд░рдгреЛрдВ рдХреЗ рд▓рд┐рдП рд╕рдорд░реНрдерди рд╕реБрдирд┐рд╢реНрдЪрд┐рдд рдХрд░рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИ)ред

рдпреЛрдЧрджрд╛рди рдХрд╛ рд╕реНрд╡рд╛рдЧрдд рд╣реИ, рдмрд┐рд▓реНрдХреБрд▓!

рдЪрд┐рдпрд░реНрд╕

рд░реЗрдлрд░реА #5533ред

рдореИрдВ рдмрд╣реБрдд рдЕрд╕рдордВрдЬрд╕ рдореЗрдВ рд╣реВрдБред рдпрд╣ рдбрд┐рдлрд╝реЙрд▓реНрдЯ рд░реВрдк рд╕реЗ рдХрд╛рдо рдХрд░рддрд╛ рдкреНрд░рддреАрдд рд╣реЛрддрд╛ рд╣реИ?

рдореИрдВ рдЗрд╕ рдореБрджреНрджреЗ рдкрд░ рдЖрдпрд╛, рд╕рднреА рдЯрд┐рдкреНрдкрдгрд┐рдпреЛрдВ рдХреЛ рдкрдврд╝рд╛, рдФрд░ @apiraino рджреНрд╡рд╛рд░рд╛ рд╕рдорд╛рдзрд╛рди рдХреЛ рд▓рд╛рдЧреВ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдЖрдЧреЗ

рд╣рд╛рд▓рд╛рдВрдХрд┐, рдЕрдм рдореИрдВ рдПрдкреАрдЖрдИ рдкрд░рд┐рдгрд╛рдореЛрдВ рдХреЛ рдСрд░реНрдбрд░ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдбрдмрд▓ рдиреЗрд╕реНрдЯреЗрдб рд░рд┐рд╢реНрддреЗ рдХреЗ рд▓рд┐рдП ?ordering=job__customer__company рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░ рд░рд╣рд╛ рд╣реВрдВ рдФрд░ рдпрд╣ рдареАрдХ рдХрд╛рдо рдХрд░ рд░рд╣рд╛ рд╣реИред

@halfnibble - рдореЗрд░рд╛ рдорд╛рдирдирд╛ тАЛтАЛтАЛтАЛрд╣реИ рдХрд┐ рдпрд╣ # 5533 рдореЗрдВ рддрдп рдХрд┐рдпрд╛ рдЧрдпрд╛ рдерд╛ред

рд╕реАрд╕реА @carltongibson

@ рд╣рд╛рдлрдирд┐рдмрд▓ ,

    "install_requires": [
        "django==2.0.3",
        "coreapi==2.3.3",
        "django-filter==1.1.0",
        "djangorestframework-filters==0.10.2.post0",
        "djangorestframework-queryfields==1.0.0",
        "djangorestframework==3.8.2",
        "django-bulk-update==2.2.0",
        "django-cors-headers==2.4.0",
        "django-rest-auth[with_social]==0.9.2",
        "drf-yasg==1.6.0",
        "django-taggit==0.22.2",
        "google-api-python-client==1.6.2",
        "markdown==2.6.11",
        "pygments==2.2.0",
        "xlrd==1.1.0",
        "xlsxwriter==0.9.8",
        "factory-boy==2.10.0",
        "psycopg2-binary==2.7.4",
        "django-admin-tools==0.8.1"
    ]

рдХреНрд╖рдорд╛ рдХрд░реЗрдВ, рдЕрдм рдореИрдВ рд╕рдордЭ рдЧрдпрд╛ред рдбрд┐рдлрд╝реЙрд▓реНрдЯ рд░реВрдк рд╕реЗ рдпрд╣ рдХреЗрд╡рд▓ рддрднреА рдХрд╛рдо рдХрд░реЗрдЧрд╛ рдЬрдм рд╕рдВрдмрдВрдзрд┐рдд рдСрд░реНрдбрд░рд┐рдВрдЧ рдкреИрд░рд╛рдореАрдЯрд░ ordering_fields ред рд▓реЗрдХрд┐рди рдЕрдзрд┐рдХ рд╕рд╛рдорд╛рдиреНрдп рд╕рдорд╛рдзрд╛рди рдХреЗ рд▓рд┐рдП рдЕрднреА рднреА рдкреИрдЪ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИред

рдирдорд╕реНрддреЗ, рдореИрдВ рдбреАрдЖрд░рдПрдл рдХреЗ рд▓рд┐рдП рдЕрдкреЗрдХреНрд╖рд╛рдХреГрдд рдирдпрд╛ рд╣реВрдВ рдФрд░ рдЕрдкрдиреЗ рдбреЗрдЯрд╛рдмреЗрд╕ рдХреА рд╕рдВрд░рдЪрдирд╛ рдХреЛ рдЙрдЬрд╛рдЧрд░ рдХрд┐рдП рдмрд┐рдирд╛ рдЕрдкрдиреЗ рдСрд░реНрдбрд░ рдлрд╝реАрд▓реНрдб рдореЗрдВ рдСрд░реНрдбрд░ рдЬреЛрдбрд╝рдиреЗ рдХрд╛ рддрд░реАрдХрд╛ рдвреВрдВрдв рд░рд╣рд╛ рдерд╛ред рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП, рдпрджрд┐ рдореИрдВ z рдХреА рддрд▓рд╛рд╢ рдХрд░рдирд╛ рдЪрд╛рд╣рддрд╛ рд╣реВрдВ, рддреЛ рдореБрдЭреЗ x__y__z рд▓рд┐рдЦрдирд╛ рд╣реЛрдЧрд╛, рдФрд░ рдкреИрд░рд╛рдореАрдЯрд░ рдХреЗ рд░реВрдк рдореЗрдВ рдЗрд╕реЗ рдПрдВрдбрдкреЙрдЗрдВрдЯ рдореЗрдВ рдкрд╛рд╕ рдХрд░рдирд╛ рд╕рдВрд░рдЪрдирд╛ рдХреЛ рдЙрдЬрд╛рдЧрд░ рдХрд░рддрд╛ рд╣реИред рдХреНрдпрд╛ рдпрд╣ рд╡рд╣реА рд╣реИ рдЬреЛ рдореИрдВ рдвреВрдВрдв рд░рд╣рд╛ рд╣реВрдВ рдЕрдЧрд░ рдореИрдВ рдХреЗрд╡рд▓ z рдХрд╣рдирд╛ рдЪрд╛рд╣рддрд╛ рд╣реВрдВ рдФрд░ рдпрд╣ рджреЗрдЦрдиреЗ рдХреЗ рд▓рд┐рдП рдлрд╝рдВрдХреНрд╢рди рдЬрд╛рдВрдЪрддрд╛ рд╣реИ рдХрд┐ рдпрд╣ рдУрдЖрд░рдПрдо рдореЗрдВ рд╕рдВрдмрдВрдзрд┐рдд рдлрд╝реАрд▓реНрдб рд╣реИ рдпрд╛ рдирд╣реАрдВ?

рдЖрдк OrderingFilter.get_ordering рдУрд╡рд░рд░рд╛рдЗрдб рдХрд░рдиреЗ рдХрд╛ рдкреНрд░рдпрд╛рд╕ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВред рдХреБрдЫ рдЗрд╕ рддрд░рд╣...

class CustomOrderingFilter(OrderingFilter):
    def get_ordering(self, request, queryset, view):
        ordering = super().get_ordering(request, queryset, view)
        field_map = {
            'z': 'x__y__z',
        }
        return [field_map.get(o, o) for o in ordering]

@rpkilby рдмрд╣реБрдд рдмрд╣реБрдд рдзрдиреНрдпрд╡рд╛рдж! рдпрд╣реА рд╡рд╣ рд╣реИ рдЬрд┐рд╕рдХреА рддрд▓рд╛рд╢ рдореЗрдВ рдореИрдВ рд╣реВрдВред рдореИрдВ рдорджрдж рдХреА рд╕рд░рд╛рд╣рдирд╛ рдХрд░рддрд╛ рд╣реВрдВред

рдпрд╣рд╛рдВ рдПрдХ рд╕рдорд╛рдзрд╛рди рд╣реИ рдЬрд┐рд╕реЗ рдореИрдВрдиреЗ рдПрдХ рд╕рд╛рде рд░рдЦрд╛ рд╣реИ:

class RelatedOrderingFilter(filters.OrderingFilter):
    _max_related_depth = 3

    <strong i="6">@staticmethod</strong>
    def _get_verbose_name(field: models.Field, non_verbose_name: str) -> str:
        return field.verbose_name if hasattr(field, 'verbose_name') else non_verbose_name.replace('_', ' ')

    def _retrieve_all_related_fields(
            self,
            fields: Tuple[models.Field],
            model: models.Model,
            depth: int = 0
    ) -> List[tuple]:
        valid_fields = []
        if depth > self._max_related_depth:
            return valid_fields
        for field in fields:
            if field.related_model and field.related_model != model:
                rel_fields = self._retrieve_all_related_fields(
                    field.related_model._meta.get_fields(),
                    field.related_model,
                    depth + 1
                )
                for rel_field in rel_fields:
                    valid_fields.append((
                        f'{field.name}__{rel_field[0]}',
                        self._get_verbose_name(field, rel_field[1])
                    ))
            else:
                valid_fields.append((
                    field.name,
                    self._get_verbose_name(field, field.name),
                ))
        return valid_fields

    def get_valid_fields(self, queryset: models.QuerySet, view, context: dict = None) -> List[tuple]:
        valid_fields = getattr(view, 'ordering_fields', self.ordering_fields)
        if not valid_fields == '__all_related__':
            if not context:
                context = {}
            valid_fields = super().get_valid_fields(queryset, view, context)
        else:
            valid_fields = [
                *self._retrieve_all_related_fields(queryset.model._meta.get_fields(), queryset.model),
                *[(key, key.title().split('__')) for key in queryset.query.annotations]
            ]
        return valid_fields
````

Then I add this to wherever I want to be able to order by all related fields:
```python
filter_backends = (RelatedOrderingFilter,)
ordering_fields = '__all_related__'
рдХреНрдпрд╛ рдпрд╣ рдкреГрд╖реНрда рдЙрдкрдпреЛрдЧреА рдерд╛?
0 / 5 - 0 рд░реЗрдЯрд┐рдВрдЧреНрд╕

рд╕рдВрдмрдВрдзрд┐рдд рдореБрджреНрджреЛрдВ

manjitkumar picture manjitkumar  ┬╖  3рдЯрд┐рдкреНрдкрдгрд┐рдпрд╛рдБ

sebdiem picture sebdiem  ┬╖  3рдЯрд┐рдкреНрдкрдгрд┐рдпрд╛рдБ

orf picture orf  ┬╖  3рдЯрд┐рдкреНрдкрдгрд┐рдпрд╛рдБ

hemanthsp picture hemanthsp  ┬╖  3рдЯрд┐рдкреНрдкрдгрд┐рдпрд╛рдБ

thnee picture thnee  ┬╖  3рдЯрд┐рдкреНрдкрдгрд┐рдпрд╛рдБ