Open arthanson opened 1 day ago
Copying this from issue #16024 as that was resolved for the specific case of the ChoiceField, but there is still and underling issue with Strawberry and django-filters interaction.
The basic issue is strawberry filtering uses Q objects, django-filters returns filtersets which makes them incompatible. None of the solutions I see look very good and all would take a lot of work.
Graphene interfaces with Django-filter and uses filtersets. Code is at https://github.com/graphql-python/graphene-django/tree/main/graphene_django/filter. About 8 files of code.
Strawberry is all based off of Q objects. Code is at https://github.com/strawberry-graphql/strawberry-django/blob/main/strawberry_django/filters.py. Strawberry documentation on filters is at: https://strawberry.rocks/docs/django/guide/filters
From what I can see, this is also tied into the GraphQL parsing framework, so if we tried to use Django-filter we would also probably have to make patches to that code as well.
We are also using Strawberry Legacy Filtering which needs to be removed (https://strawberry.rocks/docs/django/guide/filters#legacy-filtering) this would need changes to the auto type decorator (https://github.com/netbox-community/netbox/blob/develop/netbox/netbox/graphql/filter_mixins.py#L131).
I can think of several different potential solutions (Option 4 might potentially be the best option?)
Basically replicate filter handling in Django-graphene - override strawberry_django.process_filters to work with django-filters basically replacing strawberry's filter handling with a new one that is compatible with Django-filters.
Change NetBox filterset functions to return Q objects (or provide sub-functions returning Q objects) which should make them compatible with Strawberry lookup code. (I think this might be the most straight-forward solution)
Functions like (https://github.com/netbox-community/netbox/blob/develop/netbox/dcim/filtersets.py#L1152). So it is not possible to convert a QuerySet to a Q object, Django-filter is pretty much built around QuerySet. Many use Q objects - but some (https://github.com/netbox-community/netbox/blob/develop/netbox/dcim/filtersets.py#L607) are just query set - although exclude could be converted to a negative Q object ~Q(...)
Can override the default filter method (https://strawberry.rocks/docs/django/guide/filters#overriding-the-default-filter-method) to just call the filter set, but then would need to handle the (AND, OR, NOT, ...) parsing ourselves.
[Potential Best Option?] Write custom Strawberry filters for each of the filterset methods. This is what Strawberry is sort-of designed for, but it would require replicating / duplicating all the special NetBox filter handling in a Strawberry compatible way. Similar to 2 but leaves the existing filter code (non GraphQL) untouched.
Note: Could create the Strawberry filters as Q objects as a first pass, then migrate those over to the filters code, thus doing item 2 above, but would allow time to test the filters in the real world.
Support for Django-filter has been requested in Strawberry, but it doesn't look like it will be implemented (https://github.com/strawberry-graphql/strawberry-django/issues/448).
Move back to Graphene / abandoning Strawberry.
strawberry-django code here is where it is calling deprecated filterset (as we have the USE_DEPRECATED_FILTERS flag) (https://github.com/strawberry-graphql/strawberry-django/blob/main/strawberry_django/filters.py#L235) - this only returns the queryset and bypasses the creation of the Q object. q in this case ends up as “q: (AND: )“. So it just doesn’t work.
Docs for the new filtering code (https://strawberry.rocks/docs/django/guide/filters#custom-filter-methods) as you can see this requires returning a Q object (see: https://strawberry.rocks/docs/django/guide/filters#resolver-return) the Q object is what it uses for processing.
So, to use Strawberry as-is would need to remove the USE_DEPRECATED_FILTERS flag, then rewrite our filter_by_filterset to return a Q object (which django-filter doesn’t do).
If you put a breakpoint at the end of filter_by_filterset in netbox/graphql/filter_mixins.py you will see it is getting called from Strawberry’s process_filters function in that _process_deprecated_filter function. Can use a query like:
{
site_list(filters: {asn_id: "1", OR: {asn_id: "4"}}) {
name
asns {
id
}
}
}
Deployment Type
Self-hosted
NetBox Version
v4.1.3
Python Version
3.10
Steps to Reproduce
Using a GraphQL filter with AND, OR, NOT for a field that has custom implementation in the filterset (or only appears in the filterset) for example asn_id on Site. Doesn't work
Expected Behavior
Will get a list of 2 sites.
Observed Behavior
Get an empty list.