netbox-community / netbox

The premier source of truth powering network automation. Open source under Apache 2. Try NetBox Cloud free: https://netboxlabs.com/free-netbox-cloud/
http://netboxlabs.com/oss/netbox/
Apache License 2.0
15.91k stars 2.55k forks source link

Allow plugins to extend autotype decorator function #16091

Open amyasnikov opened 4 months ago

amyasnikov commented 4 months ago

NetBox version

v4.0.1

Feature type

Change to existing functionality

Proposed functionality

Problem NetBox 4.0 Plugin migration guide suggests using autotype_decorator to convert filtersets into strawberry filters. However, this decorator does not support a lot of existing filters (e.g. ChoiceFilter):

import django_filters
from netbox.graphql.filter_mixins import autotype_decorator, BaseFilterMixin
from dcim import models, choices
import strawberry_django

class MyFilterSet(django_filters.FilterSet):
     type = django_filters.ChoiceFilter(choices=choices.ConsolePortTypeChoices)
     class Meta:
         model = models.ConsolePort
         fields = ['type']

@strawberry_django.filter(models.ConsolePort, lookups=True)
@autotype_decorator(MyFilterSet)
class MyFilter(BaseFilterMixin):
    pass

# NotImplementedError: GraphQL Filter field unknown: type: <django_filters.filters.ChoiceFilter object at 0x7fa9d06bb370>

This error also ruins all the work made by autotype_decorator for any other filters inside FilterSet. Hence, it would be very painful to handle it at the plugin side.

Possible Solution Just use Dependency Injection to inject map_strawberry_type inside autotype_decorator:

def autotype_decorator(filterset, map_strawberry_type_fn=map_strawberry_type):
   ...
   should_create_function, attr_type = map_strawberry_type_fn(field)
   ...

This would allow plugin developers to supply their own map_strawberry_type_fn for their own filters when using autotype_decorator.

Use case

Plugin developers will be allowed to handle arbitrary filter types by themselves:

def map_strawberry_extra(field):
    create_fn, attr_type = map_strawberry_type(field)
    if attr_type is None and isinstance(field, ChoiceFilter):
        return True, str | None
    return create_fn, attr_type

@strawberry_django.filter(models.ConsolePort, lookups=True)
@autotype_decorator(MyFilterSet, map_strawberry_type_fn=map_strawberry_extra)
class MyFilter(BaseFilterMixin):
    pass

# No error

I can make a PR if you're okay with this change

Database changes

No response

External dependencies

No response

jeffgdotorg commented 4 months ago

Thank you for your interest in helping improve NetBox. Making life easier for plugin developers is important to us too.

My role at this stage is just to triage; others on the team with deeper understanding of the factors in play will need to take a closer look to determine whether your proposal is viable with fully gamed out. I'm setting the issue's status to under review and will raise it with the team.

Thanks for volunteering to work it through to a PR, but we ask that you please wait until you see the status move to accepted and the issue assigned to you before doing so.

amyasnikov commented 4 months ago

@jeffgdotorg Hi, any news on this issue?