diff --git a/netbox/extras/graphql/types.py b/netbox/extras/graphql/types.py index dbaa0bee2..41a6103d3 100644 --- a/netbox/extras/graphql/types.py +++ b/netbox/extras/graphql/types.py @@ -27,7 +27,7 @@ class CustomFieldType(ObjectType): class Meta: model = models.CustomField - fields = '__all__' + exclude = ('content_types', ) filterset_class = filtersets.CustomFieldFilterSet @@ -83,5 +83,5 @@ class WebhookType(ObjectType): class Meta: model = models.Webhook - fields = '__all__' + exclude = ('content_types', ) filterset_class = filtersets.WebhookFilterSet diff --git a/netbox/netbox/graphql/__init__.py b/netbox/netbox/graphql/__init__.py index 0ad25a541..bd8e3cb88 100644 --- a/netbox/netbox/graphql/__init__.py +++ b/netbox/netbox/graphql/__init__.py @@ -1,9 +1,13 @@ import graphene -from graphene_django.converter import convert_django_field +from dcim.fields import MACAddressField, WWNField +from django.db import models +from graphene import Dynamic +from graphene_django.converter import convert_django_field, get_django_field_description +from graphene_django.fields import DjangoConnectionField +from ipam.fields import IPAddressField, IPNetworkField from taggit.managers import TaggableManager -from dcim.fields import MACAddressField, WWNField -from ipam.fields import IPAddressField, IPNetworkField +from .fields import ObjectListField @convert_django_field.register(TaggableManager) @@ -21,3 +25,45 @@ def convert_field_to_tags_list(field, registry=None): def convert_field_to_string(field, registry=None): # TODO: Update to use get_django_field_description under django_graphene v3.0 return graphene.String(description=field.help_text, required=not field.null) + + +@convert_django_field.register(models.ManyToManyField) +@convert_django_field.register(models.ManyToManyRel) +@convert_django_field.register(models.ManyToOneRel) +def convert_field_to_list_or_connection(field, registry=None): + """ + From graphene_django.converter.py we need to monkey-patch this to return + our ObjectListField with filtering support instead of DjangoListField + """ + model = field.related_model + + def dynamic_type(): + _type = registry.get_type_for_model(model) + if not _type: + return + + if isinstance(field, models.ManyToManyField): + description = get_django_field_description(field) + else: + description = get_django_field_description(field.field) + + # If there is a connection, we should transform the field + # into a DjangoConnectionField + if _type._meta.connection: + # Use a DjangoFilterConnectionField if there are + # defined filter_fields or a filterset_class in the + # DjangoObjectType Meta + if _type._meta.filter_fields or _type._meta.filterset_class: + from .filter.fields import DjangoFilterConnectionField + + return DjangoFilterConnectionField(_type, required=True, description=description) + + return DjangoConnectionField(_type, required=True, description=description) + + return ObjectListField( + _type, + required=True, # A Set is always returned, never None. + description=description, + ) + + return Dynamic(dynamic_type) diff --git a/netbox/netbox/settings.py b/netbox/netbox/settings.py index 5d4dbb809..a693f4754 100644 --- a/netbox/netbox/settings.py +++ b/netbox/netbox/settings.py @@ -18,11 +18,6 @@ from sentry_sdk.integrations.django import DjangoIntegration from netbox.config import PARAMS -# Monkey patch to fix Django 4.0 support for graphene-django (see -# https://github.com/graphql-python/graphene-django/issues/1284) -# TODO: Remove this when graphene-django 2.16 becomes available -django.utils.encoding.force_text = force_str # type: ignore - # # Environment setup