Skip to content

Connection-level resolvers get access to model objects, not node-wrapper objects #1551

@boomdizz

Description

@boomdizz

Note: for support questions, please use stackoverflow. This repository's issues are reserved for feature requests and bug reports.

  • What is the current behavior?
    When defining a connection-level field/attribute, in it's resolver we get access to the model objects and not the node wrappers (DjangoObjectType) around that model. This is fine in most cases, but if we have defined a custom field/attribute at the node level, and need to do some aggregation at the Connection level, we cannot do that aggregation as the model objects available to the Connection class do not have that custom attribute.

Assume a model class with an email addresses field that can contain a comma-delimited list of email addresses (among other fields):

class User(models.Model):
  email_addrs = models.TextField(max_length=512, null=True,
         help_text="Comma-delimited string of email addresses")
  ...<other-fields>...

The DjangoObjectType wrapper around this model class has an additional custom attribute with a resolver:

class UserNode(DjangoObjectType):
    class Meta:
        model = User
        filter_fields = ('email_addrs', )
        interfaces = (Node, )
        connection_class = UserConnection
    
    count_email_addresses = graphene.Int()

    @static_method
    resolve_count_email_addresses(parent, info):
       # code to resolve the count of email addresses

This works fine. The relay query returns the 'count_email_addresses' field correctly for each node. Notice the UserConnection custom Connection class in the node definition. It is used to report the total number of email addresses across all the User objects returned (which may vary based on various filter criteria). The UserConnection class looks like:

class UserConnection(Connection):
    class Meta:
        abstract = True

    aggregate_count_email_addrs = graphene.Int()

The problem is in the resolver for the 'aggregate_count_email_addrs', since the field 'count_email_addresses' is in UserNode and not the model 'User' - I don't have access to this field to perform an aggregation across all Users. At the Connection level, I should have access to the UserNode object and it's field count_email_addresses, and not the underlying model 'User' object.

The email count is a contrived example to keep the description here simple. A more complex (and real situation) may be the count of something that may be accessible thrrough a foreign key, e.g. Tuition paid, which may come from an 'Accounts' table. In such a case, we may want to aggregate the amount of tuition paid by a group of Users based on some filtering criteria (e.g., 'sophomores').....

  • If the current behavior is a bug, please provide the steps to reproduce and if possible a minimal demo of the problem via
    a github repo, https://repl.it or similar (you can use this template as a starting point: https://repl.it/@jkimbo/Graphene-Django-Example).
    log the fields in the Connection resolver. You will find that the count_email_addresses field does not exist on the User objects passed in.

  • What is the expected behavior?
    Connection resolvers should get the Node (DjangoObjectType) objects and not the underlying model objects

  • What is the motivation / use case for changing the behavior?
    Aggregation at the Connection level.

  • Please tell us about your environment:

    • Version:
      graphene==3.1.1
      graphene-django==3.0.0
      graphql-core==3.2.3
      graphql-relay==3.2.0
      Django==4.2.4
      django-filter==22.1
    • Platform:
  • Other information (e.g. detailed explanation, stacktraces, related issues, suggestions how to fix, links for us to have context, eg. stackoverflow)

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions