рдЙрдкрдпреЛрдЧ рдХрд╛ рдЙрджрд╛рд╣рд░рдг рдПрдХ рдиреЗрд╕реНрдЯреЗрдб рд╕рдВрдмрдВрдзрд┐рдд рд╡рд╕реНрддреБ рджреНрд╡рд╛рд░рд╛ рдЫрдБрдЯрд╛рдИ рд╣реЛрдЧреАред
рдиреЗрд╕реНрдЯреЗрдб рдкреНрд░рддрд┐рдирд┐рдзрд┐рддреНрд╡:
{
'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
рдореИрдВ рдЗрд╕рдХреЗ рд▓рд┐рдП рдкреБрд▓ рдЕрдиреБрд░реЛрдзреЛрдВ рдкрд░ рд╡рд┐рдЪрд╛рд░ рдХрд░реВрдВрдЧрд╛, рд▓реЗрдХрд┐рди рдРрд╕рд╛ рдХреБрдЫ рдирд╣реАрдВ рд╣реИ рдЬреЛ рдореЗрд░реЗ рдкрд╛рд╕ рдЦреБрдж рдХрд░рдиреЗ рдХрд╛ рд╕рдордп рд╣реЛрдЧрд╛ред
рдлрд╝рд┐рд▓реНрдЯрд░рд┐рдВрдЧ рдореЗрдВ рдЧрд▓рдд рдлрд╝реАрд▓реНрдб рдирд╛рдореЛрдВ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд┐рдП рдЬрд╛рдиреЗ рдкрд░ рдЗрд╕реЗ рд▓рд╛рдЧреВ рдХрд░рдиреЗ рд╡рд╛рд▓реЗ рдХрд┐рд╕реА рднреА рд╡реНрдпрдХреНрддрд┐ рдХреЛ рд╕рдордЭрджрд╛рд░ рд╡реНрдпрд╡рд╣рд╛рд░ рд╕реБрдирд┐рд╢реНрдЪрд┐рдд рдХрд░рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реЛрддреА рд╣реИред рдПрдХ рдиреНрдпреВрдирддрдо рдкрд░ рдкрд░рд┐рдгрд╛рдо рдЕрднреА рднреА рдареАрдХ рд▓реМрдЯрдирд╛ рдЪрд╛рд╣рд┐рдПред (рдЖрджрд░реНрд╢ рд░реВрдк рд╕реЗ, рдХрд┐рд╕реА рднреА рдЧрд▓рдд рдлрд╝реАрд▓реНрдб рдирд╛рдореЛрдВ рдХреЛ рдЕрдирджреЗрдЦрд╛ рдХрд┐рдпрд╛ рдЬрд╛рдирд╛ рдЪрд╛рд╣рд┐рдП, рд▓реЗрдХрд┐рди рдЕрдиреНрдп рдлрд╝реАрд▓реНрдб рдХреЛ рдЫреЛрдбрд╝ рджрд┐рдпрд╛ рдЬрд╛рдирд╛ рдЪрд╛рд╣рд┐рдПред)
рд╡рд┐рдЪрд╛рд░ рдХрд░рдиреЗ рдкрд░ рдореИрдВ рдЗрд╕реЗ рдмрдВрдж рдХрд░рдиреЗ рдЬрд╛ рд░рд╣рд╛ рд╣реВрдВред рдЕрдЧрд░ рдХреЛрдИ рдкреБрд▓ рдЕрдиреБрд░реЛрдз рдЬрд╛рд░реА рдХрд░рддрд╛ рд╣реИ рдФрд░ рдЗрд╕рд╕реЗ рд╕рдВрдмрдВрдзрд┐рдд рдкрд░реАрдХреНрд╖рдг рдХрд░рддрд╛ рд╣реИ рддреЛ рдореИрдВ рдкреБрдирд░реНрд╡рд┐рдЪрд╛рд░ рдХрд░ рд╕рдХрддрд╛ рд╣реВрдВ, рд▓реЗрдХрд┐рди рдореВрд▓ рдлрд╝рд┐рд▓реНрдЯрд░рд┐рдВрдЧ рдХрдХреНрд╖рд╛рдУрдВ рдореЗрдВ рд╕реЗ рдкреНрд░рддреНрдпреЗрдХ рдХрд╛ рдЕрдзрд┐рдХ рдкреВрд░реНрдг рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди рд╡рд╛рд╕реНрддрд╡ рдореЗрдВ рдРрд╕рд╛ рдХреБрдЫ рд╣реИ рдЬреЛ рдХрд┐рд╕реА рддреАрд╕рд░реЗ рдкрдХреНрд╖ рдХреЗ рдкреИрдХреЗрдЬ рдореЗрдВ рд╡рд╛рд╕реНрддрд╡ рдореЗрдВ рдЕрдЪреНрдЫреА рддрд░рд╣ рд╕реЗ рдирд┐рдкрдЯ рд╕рдХрддрд╛ рд╣реИ, рдЬрд┐рд╕реЗ рддрдм рдЕрд▓рдЧ рд╕реЗ рдмрдирд╛рдП рд░рдЦрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИ, рдФрд░ рдореБрдЦреНрдп рдбреЙрдХреНрд╕ рд╕реЗ рдЬреБрдбрд╝рд╛ рд╣реБрдЖ рд╣реИред
рдХреЛрдИ рдкреБрд▓ рдЕрдиреБрд░реЛрдз рдирд╣реАрдВ рд╣реИ рдХреНрдпреЛрдВрдХрд┐ рдореЗрд░реЗ рдкрд╛рд╕ рдкрд░реАрдХреНрд╖рдг рдпрд╛ рджрд╕реНрддрд╛рд╡реЗрдЬрд╝ рд▓рд┐рдЦрдиреЗ рдХрд╛ рд╕рдордп рдирд╣реАрдВ рд╣реИ, рд▓реЗрдХрд┐рди рдЕрдЧрд░ рдпрд╣ рдЕрдиреНрдп рд▓реЛрдЧреЛрдВ рдХреЛ рдЗрд╕ рдореБрджреНрджреЗ рдХреЛ рдЦреЛрдЬрдиреЗ рдореЗрдВ рдорджрдж рдХрд░рддрд╛ рд╣реИ, рддреЛ рдореИрдВ рдЗрд╕рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░ рд░рд╣рд╛ рд╣реВрдВ:
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__'
рд╕рдмрд╕реЗ рдЙрдкрдпреЛрдЧреА рдЯрд┐рдкреНрдкрдгреА
рдЯрд┐рдк рдХреЗ рд▓рд┐рдП рдзрдиреНрдпрд╡рд╛рдж: +1:ред рд▓рд┐рдВрдХ рдареАрдХ рдХрд░рдиреЗ рджреЗрддрд╛ рд╣реИред рдпрд╣ рд╕рд╣реА рд╣реИ