When a DjangoConnectionField traverses a many-to-many field it would be nice to have the option to expose the fields of any through-table on the edges of the relationship.
[As much a note for myself as a feature request]
Never thought about that but makes sense :+1:
We'd also love to see this, an example of using m2m relationships would also be fantastic.
@matclayton FWIW I'm currently treating the through table as simply another node. It makes the GraphQL somewhat nested, but it works for now.
We would also like to see this feature :)
Hi @adamcharnock . We're currently going through old issues that appear to have gone stale (ie. not updated in about the last 6 months) to try and clean up the issue tracker. If this is still important to you please comment and we'll re-open this.
Thanks!
Reopening the issue as it might be useful to have
This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.
Is it possible to keep this on the radar? It would be a very nice feature (And its how I assume it would work)
So I've found a way of implementing this using annotations
class Member(DjangoObjectType):
class Meta:
model = models.Member
channels = graphene.ConnectionField('api.graphql.MemberToChannelConnection')
def resolve_channels(instance, info):
return instance.channels.annotate(broadcaster=F('memberships__broadcaster'))
class Channel(DjangoObjectType):
class Meta:
model = models.Channel
members = graphene.ConnectionField('api.graphql.ChannelToMemberConnection')
def resolve_members(instance, info):
return instance.members.annotate(broadcaster=F('channel_memberships__broadcaster'))
class ChannelMembershipEdge:
broadcaster = graphene.NonNull(graphene.Boolean)
def resolve_broadcaster(instance, info):
return instance.node.broadcaster
class ChannelToMemberConnection(graphene.Connection):
class Meta:
node = Member
class Edge(ChannelMembershipEdge):
pass
class MemberToChannelConnection(graphene.Connection):
class Meta:
node = Channel
class Edge(ChannelMembershipEdge):
pass
I have also created a custom connection field to add annotations
from functools import partial
class AnnotateConnectionField(graphene.ConnectionField):
def __init__(self, type, annotate_fields, *args, **kwargs):
super().__init__(type, *args, **kwargs)
self.annotate_fields = annotate_fields
def get_resolver(self, parent_resolver):
resolver = super(graphene.ConnectionField, self).get_resolver(parent_resolver)
patched_resolver = lambda *args, **kwargs: resolver(*args, **kwargs).annotate(**self.annotate_fields)
return partial(self.connection_resolver, patched_resolver, self.type)
So the above becomes
class Member(DjangoObjectType):
class Meta:
model = models.Member
channels = AnnotateConnectionField('api.graphql.MemberToChannelConnection', dict(broadcaster=F('memberships__broadcaster')))
class Channel(DjangoObjectType):
class Meta:
model = models.Channel
members = AnnotateConnectionField('api.graphql.ChannelToMemberConnection', dict(broadcaster=F('channel_memberships__broadcaster')))
class ChannelMembershipEdge:
broadcaster = graphene.NonNull(graphene.Boolean)
def resolve_broadcaster(instance, info):
return instance.node.broadcaster
class ChannelToMemberConnection(graphene.Connection):
class Meta:
node = Member
class Edge(ChannelMembershipEdge):
pass
class MemberToChannelConnection(graphene.Connection):
class Meta:
node = Channel
class Edge(ChannelMembershipEdge):
pass
I also attempted to have the two Connection classes autogenerated within the connection field. So you basically pass in the the node value and it would generate the class for you. However because graphene.Connection.Meta.node does not support lazy loading the class, I got into an issue with circular dependencies that I was unable to resolve. Im sure theres a lot more magic that could be done too. One potential issue with this approach is that I doubt it will work if the Through tables "metadata" is a FK to another object, as Im not sure annotation would support that.
Anyway this is a sufficient enough solution for myself for now
@McPo What would it take for graphene to automatically add the through model fields?
Any updates on this?
Still looking forward to automatic through edges. :)
Most helpful comment
Reopening the issue as it might be useful to have