def test_q_with_blank_or3(self): q = Q() | Q(id__gt=5) r = q._resolve( TestQCall.DummyQuerySet(), QueryContext(QueryBuilder()).push(CharFields, CharFields._meta.table()) ) self.assertEqual(r.where_criterion.get_sql(), '"id">5')
async def test_filter_not_with_or(self): await Tournament.create(name="0") await Tournament.create(name="1") await Tournament.create(name="2") tournaments = await Tournament.filter(Q(name="1") | ~Q(name="2")) self.assertEqual(len(tournaments), 2) self.assertSetEqual({t.name for t in tournaments}, {"0", "1"})
def test_q_complex_int3(self): q = Q(Q(id__lt=5, id__gt=50, join_type="OR"), join_type="AND", intnum=80) r = q._resolve( TestQCall.DummyQuerySet(), QueryContext(QueryBuilder()).push(IntFields, IntFields._meta.table()) ) self.assertEqual(r.where_criterion.get_sql(), '"intnum"=80 AND ("id"<5 OR "id">50)')
def test_q_complex_char3(self): q = Q(~Q(char__lt=5, char__gt=50, join_type="OR"), join_type="AND", char_null=80) r = q._resolve( TestQCall.DummyQuerySet(), QueryContext(QueryBuilder()).push(CharFields, CharFields._meta.table()) ) self.assertEqual( r.where_criterion.get_sql(), "\"char_null\"='80' AND NOT (\"char\"<'5' OR \"char\">'50')", )
async def test_filter_by_aggregation_field_with_or_not_reversed(self): tournament = await Tournament.create(name="0") await Tournament.create(name="1") await Tournament.create(name="2") await Event.create(name="1", tournament=tournament) tournaments = await Tournament.annotate( events_count=Count("events") ).filter(~(Q(name="2") | Q(events_count=1))) self.assertEqual(len(tournaments), 1) self.assertSetEqual({t.name for t in tournaments}, {"1"})
async def test_filter_by_aggregation_field_with_and_as_two_nodes(self): tournament = await Tournament.create(name="0") tournament_second = await Tournament.create(name="1") await Event.create(name="1", tournament=tournament) await Event.create(name="2", tournament=tournament_second) tournaments = await Tournament.annotate( events_count=Count("events") ).filter(Q(events_count=1) & Q(name="0")) self.assertEqual(len(tournaments), 1) self.assertEqual(tournaments[0].id, tournament.id)
async def test_filtering(self): tournament = Tournament(name="Tournament") await tournament.save() second_tournament = Tournament(name="Tournament 2") await second_tournament.save() event_first = Event(name="1", tournament=tournament) await event_first.save() event_second = Event(name="2", tournament=second_tournament) await event_second.save() event_third = Event(name="3", tournament=tournament) await event_third.save() event_forth = Event(name="4", tournament=second_tournament) await event_forth.save() team_first = Team(name="First") await team_first.save() team_second = Team(name="Second") await team_second.save() await team_first.events.add(event_first) await event_second.participants.add(team_second) found_events = (await Event.filter( Q(id__in=[event_first.id, event_second.id]) | Q(name="3")).filter(participants__not=team_second.id ).order_by("name", "tournament_id").distinct()) self.assertEqual(len(found_events), 2) self.assertEqual(found_events[0].id, event_first.id) self.assertEqual(found_events[1].id, event_third.id) await Team.filter(events__tournament_id=tournament.id ).order_by("-events__name") await Tournament.filter(events__name__in=["1", "3"]).distinct() teams = await Team.filter(name__icontains="CON") self.assertEqual(len(teams), 1) self.assertEqual(teams[0].name, "Second") teams = await Team.filter(name__iexact="SeCoNd") self.assertEqual(len(teams), 1) self.assertEqual(teams[0].name, "Second") tournaments = await Tournament.filter( events__participants__name__startswith="Fir") self.assertEqual(len(tournaments), 1) self.assertEqual(tournaments[0], tournament)
def test_q_compound_and(self): q1 = Q(moo="cow") q2 = Q(moo="bull") q = q1 & q2 self.assertEqual(q1.children, ()) self.assertEqual(q1.filters, {"moo": "cow"}) self.assertEqual(q1.join_type, Q.AND) self.assertEqual(q2.children, ()) self.assertEqual(q2.filters, {"moo": "bull"}) self.assertEqual(q2.join_type, Q.AND) self.assertEqual(q.children, (q1, q2)) self.assertEqual(q.filters, {}) self.assertEqual(q.join_type, Q.AND)
async def test_filter_not(self): await Tournament.create(name="0") await Tournament.create(name="1") tournaments = await Tournament.filter(~Q(name="1")) self.assertEqual(len(tournaments), 1) self.assertEqual(tournaments[0].name, "0")
def test_q_multiple_or2(self): q = Q(join_type="OR", id=8, intnum=80) r = q._resolve( TestQCall.DummyQuerySet(), QueryContext(QueryBuilder()).push(IntFields, IntFields._meta.table()) ) self.assertEqual(r.where_criterion.get_sql(), '"id"=8 OR "intnum"=80')
def test_q_basic_or(self): q = Q(join_type="OR", id=8) r = q._resolve( TestQCall.DummyQuerySet(), QueryContext(QueryBuilder()).push(IntFields, IntFields._meta.table()) ) self.assertEqual(r.where_criterion.get_sql(), '"id"=8')
async def test_q_object_related_query(self): tournament_first = await Tournament.create(name="0") tournament_second = await Tournament.create(name="1") event = await Event.create(name="1", tournament=tournament_second) await Event.create(name="1", tournament=tournament_first) fetched_event = await Event.filter(tournament=tournament_second ).first() self.assertEqual(fetched_event.id, event.id) fetched_event = await Event.filter(Q(tournament=tournament_second) ).first() self.assertEqual(fetched_event.id, event.id) fetched_event = await Event.filter(Q(tournament=tournament_second.id) ).first() self.assertEqual(fetched_event.id, event.id)
def test_q_multiple_and(self): q = Q(join_type="AND", id__gt=8, id__lt=10) r = q._resolve( TestQCall.DummyQuerySet(), QueryContext(QueryBuilder()).push(IntFields, IntFields._meta.table()) ) self.assertEqual(r.where_criterion.get_sql(), '"id">8 AND "id"<10')
async def run(): Tortoise.init(db_url="sqlite://:memory:", modules={"models": ["__main__"]}) await Tortoise.open_connections() await Tortoise.generate_schemas() tournament = Tournament(name="Tournament") await tournament.save() second_tournament = Tournament(name="Tournament 2") await second_tournament.save() event_first = Event(name="1", tournament=tournament) await event_first.save() event_second = await Event.create(name="2", tournament=second_tournament) await Event.create(name="3", tournament=tournament) await Event.create(name="4", tournament=second_tournament) await Event.filter(tournament=tournament) team_first = Team(name="First") await team_first.save() team_second = Team(name="Second") await team_second.save() await team_first.events.add(event_first) await event_second.participants.add(team_second) print( await Event.filter(Q(id__in=[event_first.id, event_second.id]) | Q(name="3")) .filter(participants__not=team_second.id) .order_by("tournament__id") .distinct() ) print(await Team.filter(events__tournament_id=tournament.id).order_by("-events__name")) print( await Tournament.filter(events__name__in=["1", "3"]) .order_by("-events__participants__name") .distinct() ) print(await Team.filter(name__icontains="CON")) print(await Tournament.filter(events__participants__name__startswith="Fir")) print(await Tournament.filter(id__icontains=1).count())
def _filter_or_exclude(self, *args, negate: bool, **kwargs): queryset = self._clone() for arg in args: if not isinstance(arg, Q): raise TypeError("expected Q objects as args") if negate: queryset.q_objects.append(~arg) else: queryset.q_objects.append(arg) for key, value in kwargs.items(): if negate: queryset.q_objects.append(~Q(**{key: value})) else: queryset.q_objects.append(Q(**{key: value})) return queryset
async def test_q_object_backward_related_query(self): await Tournament.create(name="0") tournament = await Tournament.create(name="Tournament") event = await Event.create(name="1", tournament=tournament) fetched_tournament = await Tournament.filter(events=event.id).first() self.assertEqual(fetched_tournament.id, tournament.id) fetched_tournament = await Tournament.filter(Q(events=event.id) ).first() self.assertEqual(fetched_tournament.id, tournament.id)
async def test_filter_by_aggregation_field_with_or_as_one_node(self): tournament = await Tournament.create(name="0") await Tournament.create(name="1") await Tournament.create(name="2") await Event.create(name="1", tournament=tournament) tournaments = await Tournament.annotate(events_count=Count("events") ).filter( Q(events_count=1, name="2", join_type=Q.OR)) self.assertEqual(len(tournaments), 2) self.assertSetEqual({t.name for t in tournaments}, {"0", "2"})
def __resolve_filters(self, context: QueryContext) -> None: Q(*self.q_objects).resolve_into(self, context)
def test_q_partial_or(self): q = Q(join_type="OR", moo="cow") self.assertEqual(q.children, ()) self.assertEqual(q.filters, {"moo": "cow"}) self.assertEqual(q.join_type, Q.OR)
def test_q_bad_join_type(self): with self.assertRaisesRegex(OperationalError, "join_type must be AND or OR"): Q(join_type=3)
def test_q_notq(self): with self.assertRaisesRegex(OperationalError, "All ordered arguments must be Q nodes"): Q(Q(), 1)
def test_q_compound_and_notq(self): with self.assertRaisesRegex(OperationalError, "AND operation requires a Q node"): Q() & 2 # pylint: disable=W0106
def test_q_basic(self): q = Q(moo="cow") self.assertEqual(q.children, ()) self.assertEqual(q.filters, {"moo": "cow"}) self.assertEqual(q.join_type, Q.AND)