strawberry-django
                                
                                 strawberry-django copied to clipboard
                                
                                    strawberry-django copied to clipboard
                            
                            
                            
                        Custom ordering methods?
Feature Request Type
- [ ] Core functionality
- [X] Alteration (enhancement/optimization) of existing feature(s)
- [X] New behavior
Description
I'm wondering if you'd consider supporting custom methods on ordering.order classes, in the same way you do for filters.filter classes. Something like:
@ordering.order(SomeModel)
class SomeModelOrder:
    related_thing: auto
    def order_related_thing(self, queryset):
        return queryset.order_by('related_thing__name')
This would be really useful when you want to order by some related model, but don't necessarily want to expose that relation and expect the client to know about it. In the example above, we're exposing related_thing__name as related_thing without leaking the db architecture details. It's also really handy if you need to annotate the queryset before ordering on it, e.g. for things like computed time deltas (days_in_progress and such).
I'm currently doing the following to implement this, but it only works in custom resolvers and not when the order class is passed to either the type or the field definition:
class ModelOrder:
    def apply(self, queryset: QuerySet) -> QuerySet:
        for field in fields(self):
            if getattr(self, field.name, strawberry.UNSET) == strawberry.UNSET:
                continue
            order_method = getattr(self, f"order_{field.name}", None)
            if order_method:
                queryset = order_method(queryset)
                # we expect the custom method to do the ordering, so we want to prevent strawberry's ordering handler
                # from doing anything with it since the field name may not be valid on this model
                setattr(self, field.name, strawberry.UNSET)
        return ordering.apply(self, queryset=queryset)
@ordering.order(models.Report)
class ReportOrder(ModelOrder):
    product_type: auto
    def order_product_type(self, queryset):
        return queryset.order_by("requisition__product_type")
def reports_resolver(order: ReportOrder) -> list[Report]:
    return order.apply(models.Report.objects.all())
Upvote & Fund
- We're using Polar.sh so you can upvote and help fund this issue.
- We receive the funding once the issue is completed & confirmed by you.
- Thank you in advance for helping prioritize & fund our backlog.
Yes. I actually am planning on redoing the ordering functionality because the current one has a lot of issues. For example, there's no way for you to ask for 2 or more ordering in a given sequence, since the sequence used will be the ones defined by the attributes.
Together with that I also want to make it possible to have custom orderings, just like filters.
@bellini666
Thank you for considering nulls_last ordering also!
wo = Work_Order.objects.order_by(F('dateWORequired').asc(nulls_last=True))
https://github.com/strawberry-graphql/strawberry-django/pull/478