Repository: django/django
File: tests/queries/test_qs_combinators.py (Python)

Code before:
        e1 = ExtraInfo.objects.create(value=7, info="e1")
        a1 = Author.objects.create(name="a1", num=1, extra=e1)
        a2 = Author.objects.create(name="a2", num=3, extra=e1)
        Author.objects.create(name="a3", num=2, extra=e1)
        base_qs = Author.objects.select_related("extra").order_by()
        qs1 = base_qs.filter(name="a1")
        qs2 = base_qs.filter(name="a2")
        self.assertSequenceEqual(qs1.union(qs2).order_by("pk"), [a1, a2])

    @skipUnlessDBFeature("supports_slicing_ordering_in_compound")
    def test_union_with_select_related_and_first(self):
        e1 = ExtraInfo.objects.create(value=7, info="e1")
        a1 = Author.objects.create(name="a1", num=1, extra=e1)
        Author.objects.create(name="a2", num=3, extra=e1)
        base_qs = Author.objects.select_related("extra").order_by()
        qs1 = base_qs.filter(name="a1")
        qs2 = base_qs.filter(name="a2")
        self.assertEqual(qs1.union(qs2).order_by("name").first(), a1)

    def test_union_with_first(self):
        e1 = ExtraInfo.objects.create(value=7, info="e1")
        a1 = Author.objects.create(name="a1", num=1, extra=e1)
        base_qs = Author.objects.order_by()
        qs1 = base_qs.filter(name="a1")
        qs2 = base_qs.filter(name="a2")
        self.assertEqual(qs1.union(qs2).order_by("pk").first(), a1)

    def test_union_multiple_models_with_values_list_and_order(self):
        reserved_name = ReservedName.objects.create(name="rn1", order=0)
        qs1 = Celebrity.objects.all()
        qs2 = ReservedName.objects.all()
        self.assertSequenceEqual(
            qs1.union(qs2).order_by("name").values_list("pk", flat=True),
            [reserved_name.pk],
        )

    def test_union_multiple_models_with_values_list_and_order_by_extra_select(self):
        reserved_name = ReservedName.objects.create(name="rn1", order=0)
        qs1 = Celebrity.objects.extra(select={"extra_name": "name"})
        qs2 = ReservedName.objects.extra(select={"extra_name": "name"})
        self.assertSequenceEqual(
            qs1.union(qs2).order_by("extra_name").values_list("pk", flat=True),
            [reserved_name.pk],
        )

    def test_union_multiple_models_with_values_list_and_annotations(self):
        ReservedName.objects.create(name="rn1", order=10)
        Celebrity.objects.create(name="c1")
        qs1 = ReservedName.objects.annotate(row_type=Value("rn")).values_list(
            "name", "order", "row_type"
        )

Review comment (suggestion):
@LilyFirefly the main reason I suggested the deprecation path was because of this test case.

Looking again, perhaps we can look through the other end of the telescope here and make `first()`/`last()` have no change for union()/combinators instead.

The idea would be:
```py
.order_by().first()  # no pk ordering, forced order clear
# teach .union() to forget about whatever forced order clearing came before
qs2.order_by().union(qs1).first()  # still has a pk ordering, since we forgot about the forced order clear before union()
qs2.order_by().union(qs1).order_by().first()  # no pk ordering, ordering was force-cleared after union()
```
WDYT?

@nileshpahari you might want to pause on polishing the deprecation path to allow a little time for this discussion :-)

Code after:
        e1 = ExtraInfo.objects.create(value=7, info="e1")
        a1 = Author.objects.create(name="a1", num=1, extra=e1)
        a2 = Author.objects.create(name="a2", num=3, extra=e1)
        Author.objects.create(name="a3", num=2, extra=e1)
        base_qs = Author.objects.select_related("extra").order_by()
        qs1 = base_qs.filter(name="a1")
        qs2 = base_qs.filter(name="a2")
        self.assertSequenceEqual(qs1.union(qs2).order_by("pk"), [a1, a2])

    @skipUnlessDBFeature("supports_slicing_ordering_in_compound")
    def test_union_with_select_related_and_first(self):
        e1 = ExtraInfo.objects.create(value=7, info="e1")
        a1 = Author.objects.create(name="a1", num=1, extra=e1)
        Author.objects.create(name="a2", num=3, extra=e1)
        base_qs = Author.objects.select_related("extra").order_by()
        qs1 = base_qs.filter(name="a1")
        qs2 = base_qs.filter(name="a2")
        self.assertEqual(qs1.union(qs2).order_by("name").first(), a1)

    def test_union_with_first(self):
        e1 = ExtraInfo.objects.create(value=7, info="e1")
        a1 = Author.objects.create(name="a1", num=1, extra=e1)
        base_qs = Author.objects.order_by()
        qs1 = base_qs.filter(name="a1")
        qs2 = base_qs.filter(name="a2")
        self.assertEqual(qs1.union(qs2).first(), a1)

    @skipUnlessDBFeature("supports_slicing_ordering_in_compound")
    def test_union_applies_default_ordering_afterward(self):
        c = Tag.objects.create(name="C")
        Tag.objects.create(name="B")
        a = Tag.objects.create(name="A")
        qs1 = Tag.objects.filter(name__in=["A", "B"])[:1]
        qs2 = Tag.objects.filter(name__in=["C"])[:1]
        self.assertSequenceEqual(qs1.union(qs2), [a, c])

    def test_union_multiple_models_with_values_list_and_order(self):
        reserved_name = ReservedName.objects.create(name="rn1", order=0)
        qs1 = Celebrity.objects.all()
        qs2 = ReservedName.objects.all()
        self.assertSequenceEqual(
            qs1.union(qs2).order_by("name").values_list("pk", flat=True),
            [reserved_name.pk],
        )

    def test_union_multiple_models_with_values_list_and_order_by_extra_select(self):
        reserved_name = ReservedName.objects.create(name="rn1", order=0)
        qs1 = Celebrity.objects.extra(select={"extra_name": "name"})
        qs2 = ReservedName.objects.extra(select={"extra_name": "name"})
        self.assertSequenceEqual(
            qs1.union(qs2).order_by("extra_name").values_list("pk", flat=True),