Ex query
User(id: 1234)
{
userIsTeamLeader(teamed: 6)
}
How would I access the user id in the resolve_userIsTeamLeader function? I am aware of contexts but that is not what I am looking for in this case. I want to access a higher level argument. Is this possible?
I've been trying to find a solution to this myself. The only way I've found is through the _info_ parameter in the resolve method. That holds all the arguments, models, and requested fields in the query. However, its a bit messy to go that route because you have to parse through it. Would be great to have a cleaner/easier way to do this.
Is there any documentation for the info object and how to parse through it? or can someone point me to the code where it is formed?
@syrusakbary showed an example of that here: https://github.com/graphql-python/graphene/issues/348#issuecomment-259591901
def get_type(_type):
if isinstance(_type, (GraphQLList, GraphQLNonNull)):
return get_type(_type.of_type)
return _type
def get_fields(info):
fragments = info.fragments
field_asts = info.field_asts[0].selection_set.selections
_type = get_type(info.return_type)
for field_ast in field_asts:
field_name = field_ast.name.value
if isinstance(field_ast, FragmentSpread):
for field in fragments[field_name].selection_set.selections:
yield field.name.value
continue
yield field_name
Also, for the original question, by the time you get to resolve_userIsTeamLeader, I am assuming you have already a resolved user in which case the resolve_userIsTeamLeader has access to the parent user object. Maybe try something like this?
def resolve_userIsTeamLeader(self, args, context, info):
print(self.id)
Apologies for the delay, I am continuing to work this problem and am having issues. When I look at the field_asts for the info object in my user class I can see my teamID argument as part of the selection set which includes userIsTeamLeader, however when I look at the field_asts for the info object in my resolve_userIsTeamLeader function the only field that is present is the userIsTeamLeader with its argument, is there any way to access the user field_asts from within my resolve_userIsTeamLeader function?
I'm sorry. That only works the other way around, when you are trying to access child arguments from the parent. In that case, you should go with what @yfilali demonstrated with _self_. You should have the first part of the argument resolved in self with the User object. So you should be able to access the id field from there.
@jwfehr I looked at this again today. You can access the parent arguments in the _info_ object, but not in the _field_asts_ attribute. Try the _operation_ attribute (_info.operation_). That seems to have all arguments in both contexts.
@angieellis Thanks very much for the help, I will take a look at that.
Hi, I have the same problem and I can't get the self solution to work.
I tried to add a minimal example to the playground at:
https://goo.gl/gd1CgM
Do I really have to parse the whole info object just to get to the filter value?
I found a workaround https://goo.gl/BqMtjV
But I don't really like it.
For anyone else who thinks that the above solutions are too hard, my workaround was to add the arguments to info.context in the higher level resolve method. Not pretty, but very easy.
@Zevgon not sure exactly how to "add arugments to info.context". could you provide an example?
maybe like this?
def resolve_parent(self, info, arg):
info.context.args = dict(arg=arg)
return ChildType()
...
class Child(graphene.ObjectType):
some_field = ...
def resolve_some_field(self, info):
return info.context.args.get('arg')
though I wish something like this would be possible, to make namespacing easier:
def resolve_parent(self, info, arg):
return ChildType(arg=arg)
...
class Child(graphene.ObjectType):
def resolve_some_field(self, info):
return self.args.get('arg')
@pcattori Yes, your first example is exactly what I mean. About your second example, I think that's possible if you access arg directly from self? Pretty sure this works:
def resolve_parent(self, info, arg):
return ChildType(arg=arg)
...
class Child(graphene.ObjectType):
def resolve_some_field(self, info):
return self.arg
Although I still prefer not doing that type of thing in cases where the child inherits from DjangoObjectType because of the possibility of arg clashing with one of the model's property names.
Though using the context solution usually work it has some edge cases when runnning resolvers in parallel.
For example:
{
product1: product(id: "1") { id, name, ...}
product2: product(id: "2") { id, name, ...}
}
if resolve_product sets something in context, say context['current_product'] = self then it might be a problem...
Hi @jwfehr . We're currently going through old issues that appear to have gone stale (ie. not updated in about the last 3 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!
if
resolve_productsets something in context, saycontext['current_product'] = selfthen it might be a problem...
Have you found another, better way, that works with DjangoObjectType?
Thanks @Zevgon this works, however it seems like a hack. Is there any reason why this isn't possible without the workaround.
My use case consists of a Member who has a connection with other Members (If they share a Circle then they are considered Contacts). I would like to annotate the edges of the connection with meta information as to how the two Members are linked (Via which Circles).
It seems odd to me that an Edge doesn't have access to both nodes, but only one. As such I had to do the workaround that @Zevgon has proposed. Also any additional information added to an Edge, is surely gonna have to be based off some relationship between the two nodes?
Is this likely to cause any issues?
class Member(DjangoObjectType):
class Meta:
model = models.Member
filter_fields = []
interfaces = (graphene.Node, )
contacts = graphene.ConnectionField('api.graphql.Contact')
def resolve_contacts(instance, info):
info.context.root = instance
return instance.contacts
class Contact(graphene.Connection):
class Meta:
node = Member
class Edge:
circles = graphene.List(Circle)
def resolve_circles(instance, info):
return info.context.root.circles.intersection(instance.node.circles.all())
Also @ZikDead it appears to work fine with for me with DjangoObjectType
Most helpful comment
@jwfehr I looked at this again today. You can access the parent arguments in the _info_ object, but not in the _field_asts_ attribute. Try the _operation_ attribute (_info.operation_). That seems to have all arguments in both contexts.