I am getting order_by fields in the form of a alphabetical order. I want to order_by by multiple values of field with django orm. List is like below:

orderbyList = ['Day','Afternoon','Night']

I am writing a query is like:

modelclassinstance.objects.all().order_by(shift_name=*orderbyList)

  1. shift_name is name of the column and 'Day','Afternoon','Night' are values in it

  2. my ultimate output should be like

    All day records first and then afternoon second and then night, not in alphabetical order.

2 answers

  • answered 2021-04-21 11:43 Abdul Aziz Barkat

    You can annotate a value for each of the values in orderbyList using Conditional Expressions [Django docs] according to which the queryset will be ordered:

    from django.db.models import Case, Value, When
    
    
    orderbyList = ['Day','Afternoon','Night']
    
    order_case = Case(
        *[When(shift_name=value, then=Value(index)) for index, value in enumerate(orderbyList)],
        default=Value(len(orderbyList))
    )
    
    queryset = modelclassinstance.objects.annotate(order_case=order_case).order_by('order_case')
    

    Note: Although this solution will work you should instead look into having shift_name be in a separate model which would have some field to indicate it's ordering and order on that field. Your current model should simply have a foreign key to this model for shift_name. This would be better in terms of efficiency.

  • answered 2021-04-21 11:48 Tim Nyborg

    You'll need to use conditional expressions (Case/When syntax): https://docs.djangoproject.com/en/3.2/ref/models/conditional-expressions/

    So something like:

    from django.db.models import Value, Case, When, IntegerField
    
    modelclassinstance.objects.annotate(
        custom_order=Case(
            When(shift_name='Day', then=Value(1)),
            When(shift_name='Afternoon', then=Value(2)),
            When(shift_name='Night', then=Value(3)),
            output_field=IntegerField()
        )
    ).order_by('custom_order')