let s make sure that modeladmin getqueryset uses the ordering we define in modeladmin rather that ordering defined in the model s inner meta class the default ordering should be by name as specified in the inner meta class let s use a custom modeladmin that changes the ordering and make sure it actually changes let s use a custom modeladmin that changes the ordering dynamically let s make sure that inlinemodeladmin getqueryset uses the ordering we define in inlinemodeladmin the default ordering should be by name as specified in the inner meta class let s check with ordering set to something different than the default we need to register a custom modeladmin instead of just using modeladmin because the field creator tries to find the modeladmin for the related model should be ordered by name as defined by the model should be ordered by name as defined by the model should be ordered by rank defined by the modeladmin custom queryset has still precedence 21405 class songadminadmin modeladmin exclude one of the two bands from the querysets def formfieldforforeignkeyself dbfield request kwargs if dbfield name band kwargsqueryset band objects filterrankgt2 return super formfieldforforeignkeydbfield request kwargs def formfieldformanytomanyself dbfield request kwargs if dbfield name otherinterpreters kwargsqueryset band objects filterrankgt2 return super formfieldforforeignkeydbfield request kwargs class staticorderingbandadminadmin modeladmin ordering rank site unregistersong site registersong songadmin site registerband staticorderingbandadmin self checkorderingoffieldchoicesself b2 let s make sure that modeladmin get_queryset uses the ordering we define in modeladmin rather that ordering defined in the model s inner meta class the default ordering should be by name as specified in the inner meta class let s use a custom modeladmin that changes the ordering and make sure it actually changes default ordering is name let s use a custom modeladmin that changes the ordering dynamically let s make sure that inlinemodeladmin get_queryset uses the ordering we define in inlinemodeladmin the default ordering should be by name as specified in the inner meta class let s check with ordering set to something different than the default we need to register a custom modeladmin instead of just using modeladmin because the field creator tries to find the modeladmin for the related model should be ordered by name as defined by the model should be ordered by name as defined by the model should be ordered by rank defined by the modeladmin custom queryset has still precedence 21405 exclude one of the two bands from the querysets
from django.contrib import admin
from django.contrib.admin.options import ModelAdmin
from django.contrib.auth.models import User
from django.db.models import F
from django.test import RequestFactory, TestCase

from .models import (
    Band,
    DynOrderingBandAdmin,
    Song,
    SongInlineDefaultOrdering,
    SongInlineNewOrdering,
)


class MockRequest:
    pass


class MockSuperUser:
    def has_perm(self, perm, obj=None):
        return True

    def has_module_perms(self, module):
        return True


request = MockRequest()
request.user = MockSuperUser()

site = admin.AdminSite()


class TestAdminOrdering(TestCase):
    

    request_factory = RequestFactory()

    @classmethod
    def setUpTestData(cls):
        Band.objects.bulk_create(
            [
                Band(name="Aerosmith", bio="", rank=3),
                Band(name="Radiohead", bio="", rank=1),
                Band(name="Van Halen", bio="", rank=2),
            ]
        )

    def test_default_ordering(self):
        
        ma = ModelAdmin(Band, site)
        names = [b.name for b in ma.get_queryset(request)]
        self.assertEqual(["Aerosmith", "Radiohead", "Van Halen"], names)

    def test_specified_ordering(self):
        

        class BandAdmin(ModelAdmin):
            ordering = ("rank",)  

        ma = BandAdmin(Band, site)
        names = [b.name for b in ma.get_queryset(request)]
        self.assertEqual(["Radiohead", "Van Halen", "Aerosmith"], names)

    def test_specified_ordering_by_f_expression(self):
        class BandAdmin(ModelAdmin):
            ordering = (F("rank").desc(nulls_last=True),)

        band_admin = BandAdmin(Band, site)
        names = [b.name for b in band_admin.get_queryset(request)]
        self.assertEqual(["Aerosmith", "Van Halen", "Radiohead"], names)

    def test_dynamic_ordering(self):
        
        super_user = User.objects.create(username="admin", is_superuser=True)
        other_user = User.objects.create(username="other")
        request = self.request_factory.get("/")
        request.user = super_user
        ma = DynOrderingBandAdmin(Band, site)
        names = [b.name for b in ma.get_queryset(request)]
        self.assertEqual(["Radiohead", "Van Halen", "Aerosmith"], names)
        request.user = other_user
        names = [b.name for b in ma.get_queryset(request)]
        self.assertEqual(["Aerosmith", "Radiohead", "Van Halen"], names)


class TestInlineModelAdminOrdering(TestCase):
    

    @classmethod
    def setUpTestData(cls):
        cls.band = Band.objects.create(name="Aerosmith", bio="", rank=3)
        Song.objects.bulk_create(
            [
                Song(band=cls.band, name="Pink", duration=235),
                Song(band=cls.band, name="Dude (Looks Like a Lady)", duration=264),
                Song(band=cls.band, name="Jaded", duration=214),
            ]
        )

    def test_default_ordering(self):
        
        inline = SongInlineDefaultOrdering(self.band, site)
        names = [s.name for s in inline.get_queryset(request)]
        self.assertEqual(["Dude (Looks Like a Lady)", "Jaded", "Pink"], names)

    def test_specified_ordering(self):
        
        inline = SongInlineNewOrdering(self.band, site)
        names = [s.name for s in inline.get_queryset(request)]
        self.assertEqual(["Jaded", "Pink", "Dude (Looks Like a Lady)"], names)


class TestRelatedFieldsAdminOrdering(TestCase):
    @classmethod
    def setUpTestData(cls):
        cls.b1 = Band.objects.create(name="Pink Floyd", bio="", rank=1)
        cls.b2 = Band.objects.create(name="Foo Fighters", bio="", rank=5)

    def setUp(self):
        
        
        
        class SongAdmin(admin.ModelAdmin):
            pass

        site.register(Song, SongAdmin)

    def tearDown(self):
        site.unregister(Song)
        if site.is_registered(Band):
            site.unregister(Band)

    def check_ordering_of_field_choices(self, correct_ordering):
        fk_field = site.get_model_admin(Song).formfield_for_foreignkey(
            Song.band.field, request=None
        )
        m2m_field = site.get_model_admin(Song).formfield_for_manytomany(
            Song.other_interpreters.field, request=None
        )
        self.assertEqual(list(fk_field.queryset), correct_ordering)
        self.assertEqual(list(m2m_field.queryset), correct_ordering)

    def test_no_admin_fallback_to_model_ordering(self):
        
        self.check_ordering_of_field_choices([self.b2, self.b1])

    def test_admin_with_no_ordering_fallback_to_model_ordering(self):
        class NoOrderingBandAdmin(admin.ModelAdmin):
            pass

        site.register(Band, NoOrderingBandAdmin)

        
        self.check_ordering_of_field_choices([self.b2, self.b1])

    def test_admin_ordering_beats_model_ordering(self):
        class StaticOrderingBandAdmin(admin.ModelAdmin):
            ordering = ("rank",)

        site.register(Band, StaticOrderingBandAdmin)

        
        self.check_ordering_of_field_choices([self.b1, self.b2])

    def test_custom_queryset_still_wins(self):
        

        class SongAdmin(admin.ModelAdmin):
            
            def formfield_for_foreignkey(self, db_field, request, **kwargs):
                if db_field.name == "band":
                    kwargs["queryset"] = Band.objects.filter(rank__gt=2)
                return super().formfield_for_foreignkey(db_field, request, **kwargs)

            def formfield_for_manytomany(self, db_field, request, **kwargs):
                if db_field.name == "other_interpreters":
                    kwargs["queryset"] = Band.objects.filter(rank__gt=2)
                return super().formfield_for_foreignkey(db_field, request, **kwargs)

        class StaticOrderingBandAdmin(admin.ModelAdmin):
            ordering = ("rank",)

        site.unregister(Song)
        site.register(Song, SongAdmin)
        site.register(Band, StaticOrderingBandAdmin)

        self.check_ordering_of_field_choices([self.b2])