|
| 1 | +# **Searching** |
| 2 | + |
| 3 | +**Django Ninja Extra** provides an intuitive searching model using `searching` decoration from the Django-Ninja-Extra searching module. It expects a Queryset from as a route function result. |
| 4 | + |
| 5 | +> This feature was inspired by the [DRF SearchFilter](https://www.django-rest-framework.org/api-guide/filtering/#searchfilter) |
| 6 | +
|
| 7 | +## **Properties** |
| 8 | + |
| 9 | +`def searching(func_or_searching_class: Any = NOT_SET, **searching_params: Any) -> Callable[..., Any]:` |
| 10 | + |
| 11 | +- func_or_searching_class: Defines a route function or an Searching Class. default: `ninja_extra.searching.Searching` |
| 12 | +- searching_params: extra parameters for initialising Searching Class |
| 13 | + |
| 14 | +### Changing Default Searching Class |
| 15 | + |
| 16 | +To change the default searching class, you need to add a `NINJA_EXTRA` variable in `settings.py` with a key `SEARCHING_CLASS` and value defining path to searching class |
| 17 | + |
| 18 | +```python |
| 19 | +# Django project settings.py |
| 20 | +INSTALLED_APPS = [ |
| 21 | + ... |
| 22 | +] |
| 23 | +NINJA_EXTRA={ |
| 24 | + 'SEARCHING_CLASS': 'someapp.somemodule.CustomSearching' |
| 25 | +} |
| 26 | +``` |
| 27 | + |
| 28 | +## **Usage** |
| 29 | + |
| 30 | +- If you do not specify the `search_fields` parameter, will return the result without change. |
| 31 | +- For example, to search users by username or email: |
| 32 | + > http://example.com/api/users?search=someuser |
| 33 | +- You can also perform a related lookup on a ForeignKey or ManyToManyField with the lookup API double-underscore notation: |
| 34 | + > search_fields = ['username', 'email', 'profile__profession'] |
| 35 | +- By default, searches will use case-insensitive partial matches. The search parameter may contain multiple search terms, which should be whitespace and/or comma separated. If multiple search terms are used then objects will be returned in the list only if all the provided terms are matched. The search behavior may be restricted by prepending various characters to the `search_fields`. |
| 36 | + |
| 37 | + * '^' Starts-with search. |
| 38 | + * '=' Exact matches. |
| 39 | + * '@' Full-text search. (Currently only supported Django's [PostgreSQL backend](https://docs.djangoproject.com/en/stable/ref/contrib/postgres/search/).) |
| 40 | + * '$' Regex search. |
| 41 | + |
| 42 | + For example: |
| 43 | + |
| 44 | + > search_fields = ['=username', '=email'] |
| 45 | +
|
| 46 | +```python |
| 47 | +from typing import List |
| 48 | +from ninja_extra.searching import searching, Searching |
| 49 | +from ninja_extra import api_controller, route, NinjaExtraAPI |
| 50 | +from ninja import ModelSchema |
| 51 | +from django.contrib.auth import get_user_model |
| 52 | + |
| 53 | +user_model = get_user_model() |
| 54 | + |
| 55 | + |
| 56 | +class UserSchema(ModelSchema): |
| 57 | + class Config: |
| 58 | + model = user_model |
| 59 | + model_fields = ['username', 'email'] |
| 60 | + |
| 61 | + |
| 62 | +@api_controller('/users') |
| 63 | +class UserController: |
| 64 | + @route.get('', response=List[UserSchema]) |
| 65 | + @searching(Searching, search_fields=['username', 'email']) |
| 66 | + def get_users(self): |
| 67 | + return user_model.objects.all() |
| 68 | + |
| 69 | + @route.get('/iexact-email', response=List[UserSchema]) |
| 70 | + @searching(search_fields=['=email']) |
| 71 | + def get_users_with_search_iexact_email(self): |
| 72 | + return user_model.objects.all() |
| 73 | + |
| 74 | + |
| 75 | +api = NinjaExtraAPI(title='Searching Test') |
| 76 | +api.register_controllers(UserController) |
| 77 | +``` |
| 78 | + |
| 79 | +## Note |
| 80 | + |
| 81 | +> If you use the `paginate` decorator, the `ordering` decorator and the `searching` decorator together, the `paginate` decorator should be above the `ordering` decorator and the `ordering` decorator should be above the `searching` decorator because first the data is filtered, then the data is sorted and then paginated:, for example: |
| 82 | +> |
| 83 | +> ```python |
| 84 | +> @route.get('', response=List[UserSchema]) |
| 85 | +> @paginate |
| 86 | +> @ordering(Ordering, ordering_fields=['username', 'email']) |
| 87 | +> @searching(Searching, search_fields=['username', 'email']) |
| 88 | +> def get_users(self): |
| 89 | +> return user_model.objects.all() |
| 90 | +> ``` |
0 commit comments