Closed Cerebus closed 3 years ago
Using the examples above, mongoengine returns the subclass when fetching on the parent class, which is IMHO correct behavior:
>>> AModel.objects.all()
[<ASubModel: ASubModel object>]
However, MongoengineConnectionField
descends from graphene.Field
, which adopts the named class as the only possible type. As a result, when the query is run returned results are being cast to MongoengineConnectionField._type
, which is the parent class in this example. The casting works because of inheritance, but it's unexpected behavior when you're using a mongo backend.
I don't think the other graphene backends won't have this issue.
IMHO this is a bug. Document subclassing is a key mongo feature, so graphene_mongo should support it. I think the right way is to override graphene's behavior here and set __typename
to the returned object's class, with an assertion that the returned object is a subclass of MongoengineConnectionField._type
.
I think this would allow inline fragments to access fields on each subclass in a way compatible with mongo.
@Cerebus Regarding your Query class
class Query(graphene.ObjectType):
node = Node.Field()
all_a = MongoengineConnectionField(A)
should be
class Query(graphene.ObjectType):
node = Node.Field()
all_a = MongoengineConnectionField(ASub)
^ Make sense?
Yes, but...if I add a new Document subclass,
class ASub_new(A):
pass
Then I have a different problem.
I could use a union, but even that makes me unhappy since I still have to modify the Query class every time I extend the data model. Further, it seems like it takes me away from Relay's interface, which I'd rather not do.
@Cerebus : after doing some research, I found this as the workaround(?) by adding field and it's resolve method, and yes, there is another effort (adding fields) though ... :(, but I think it's hard to know what fields child-model added automatically.
Please let me know if any thought, thanks.
import graphene
import mongoengine
from datetime import datetime
from graphene_mongo import (
MongoengineObjectType,
MongoengineConnectionField
)
mongoengine.connect(
"graphene-mongo-test", host="mongomock://localhost", alias="default"
)
class AModel(mongoengine.Document):
meta = {'allow_inheritance': True}
a_field = mongoengine.StringField()
class ASubModel(AModel):
a_sub_field = mongoengine.StringField()
class A(MongoengineObjectType):
a_sub_field = graphene.String()
class Meta:
model = AModel
interfaces = (graphene.Node,)
class ASub(A):
class Meta:
model = ASubModel
interfaces = (graphene.Node,)
AModel.drop_collection()
a_model = AModel(a_field='a_model_1')
a_model.save()
a_sub_model = ASubModel(a_field='a_field_abc', a_sub_field='hello')
a_sub_model.save()
class Query(graphene.ObjectType):
all_a = MongoengineConnectionField(A)
query = """
query Query {
allA {
edges {
node {
aField,
aSubField,
}
}
}
}
"""
schema = graphene.Schema(query=Query)
result = schema.execute(query)
print(result.data)
close due to stale, feel free to re-open it.
I know I'm missing something. Given a model with multiple document types in a collection:
I can construct a schema and query:
If I run the
allA
query, I get back all the documents as expected, but I can't accessASub
's fields because the returned type isA
, notASub
, even though the class is identified asA.ASub
. E.g.,:Attempting to resolve
ASub.a_sub_field
results in an error. Inline fragment doesn't work either:I'm clearly doing something wrong, but I don't know what.