diff --git a/ormar/queryset/queryset.py b/ormar/queryset/queryset.py index 91f8cbc..f17a2f3 100644 --- a/ormar/queryset/queryset.py +++ b/ormar/queryset/queryset.py @@ -933,6 +933,23 @@ class QuerySet(Generic[T]): self.check_single_result_rows_count(processed_rows) return processed_rows[0] # type: ignore + async def first_or_none(self, *args: Any, **kwargs: Any) -> Optional["T"]: + """ + Gets the first row from the db ordered by primary key column ascending. + + If no match is found None will be returned. + + :raises MultipleMatches: if more than 1 row is returned. + :param kwargs: fields names and proper value types + :type kwargs: Any + :return: returned model + :rtype: Model + """ + try: + return await self.first(*args, **kwargs) + except ormar.NoMatch: + return None + async def get_or_none(self, *args: Any, **kwargs: Any) -> Optional["T"]: """ Gets the first row from the db meeting the criteria set by kwargs. @@ -942,8 +959,9 @@ class QuerySet(Generic[T]): Passing a criteria is actually calling filter(*args, **kwargs) method described below. - If not match is found None will be returned. + If no match is found None will be returned. + :raises MultipleMatches: if more than 1 row is returned. :param kwargs: fields names and proper value types :type kwargs: Any :return: returned model diff --git a/tests/test_model_definition/test_models.py b/tests/test_model_definition/test_models.py index df35bff..c25ba96 100644 --- a/tests/test_model_definition/test_models.py +++ b/tests/test_model_definition/test_models.py @@ -451,6 +451,11 @@ async def test_offset(): async def test_model_first(): async with base_ormar_config.database: async with base_ormar_config.database.transaction(force_rollback=True): + with pytest.raises(ormar.NoMatch): + await User.objects.first() + + assert await User.objects.first_or_none() is None + tom = await User.objects.create(name="Tom") jane = await User.objects.create(name="Jane") @@ -460,6 +465,9 @@ async def test_model_first(): with pytest.raises(NoMatch): await User.objects.filter(name="Lucy").first() + assert await User.objects.first_or_none(name="Lucy") is None + assert await User.objects.filter(name="Lucy").first_or_none() is None + assert await User.objects.order_by("name").first() == jane