graphql-python / graphene-mongo Goto Github PK
View Code? Open in Web Editor NEWGraphene MongoEngine integration
Home Page: http://graphene-mongo.readthedocs.io/en/latest/
License: MIT License
Graphene MongoEngine integration
Home Page: http://graphene-mongo.readthedocs.io/en/latest/
License: MIT License
Hi,
Please add support for GenericEmbeddedDocumentField, and GenericLazy..... fields
Regrads
Python Version: Python 3.7
Error: TypeError: '<' not supported between instances of 'ID' and 'ConfigurationSpec'
Essentially, I have an embedded document modeled as such:
class ConfigurationSpec(EmeddedDocument):
first_field = StringField(db_field="First Field")
second_field = StringField(db_field="Second Field")
...
And then, I pull in the embedded document into a larger model. This larger model is built of embedded documents. The standalone embedded documents seem to work fine. When I use the field embedded document list field it gives me a couple of problems.
The larger document is modeled as:
class LargeSpecModel(Document):
meta = {'collection': 'specifications'}
list_of_configs = EmbeddedDocumentListField(ConfigurationSpec)
This breaks ๐.
Hey guys, just came accross the need for a PolygonField representation.
I tried hacking my way into it by looking at #58 and it seemed very straightforward.
Could give it a shot and send PR if that's OK
Hello everybody,
we are using the SequenceField to create Invoice Numbers. Sadly there is no integration. I get the following error:
Exception: Don't know how to convert the MongoEngine field <mongoengine.fields.SequenceField object at 0x10df7a908> (<class 'mongoengine.fields.SequenceField'>)
Is it possible to add the support? Thank you in advance :)
Hi, currently the field converter throws an exception on MongoEngine's GenericReferenceField
:
Exception: Don't know how to convert the MongoEngine field <mongoengine.fields.GenericReferenceField object at 0x7f24dc4d03c8> (<class 'mongoengine.fields.GenericReferenceField'>)
It would be great to have support for this field type.
There's a dramatic reduction in query performance when using GraphQL with graphene-mongo, as opposed to a regular REST API doing something like list(collection.objects.all())
and sending the entire document set. From 300ms to over 6 seconds to retrieve one field from 100 elements.
I believe that using the DataLoader pattern is the expected solution to the N+1 problem, but actually attempting to use it will cause a runtime error
graphql.error.located_error.GraphQLLocatedError: Data loader batch_load_fn function raised an Exception: AttributeError("type object 'Person' has no attribute 'objects'",)
It would be nice to add some examples about integrating graphene_mongo with starlette to build awesome API libraries.
Is there a support for the PolygonField? I only could find the MultiPolygon.
Thanks so much :)
Using the following script as a test case
If Parent
is registered before Child
, when extracting types from Parent.Meta.model
no type corresponding to ReferenceField("ChildModel")
will be found in the registry, leading to the children
attribute to be unqueryable.
If Child
is registered before Parent
, however, this issue does not arise.
The point of lazy field loading is to avoid these load-order shenanigans - I think if type conversion can be delayed that might work.
I'll poke around on my end, see if I can't find out how to get this thing to work.
from graphene_mongo import MongoengineConnectionField
from mongoengine import connect, Document
from mongoengine.fields import (StringField, ListField, ReferenceField)
from graphene_mongo import MongoengineObjectType
from graphene.relay import Node
import graphene
import json
connect("TestCollection")
class ParentModel(Document):
meta = {"collection": "Parents"}
name = StringField()
children = ListField(ReferenceField("ChildModel"))
class ChildModel(Document):
meta = {"collection": "Children"}
name = StringField()
parent = ReferenceField("ParentModel")
ChildModel.objects.all().delete()
ParentModel.objects.all().delete()
# Create a child
child = ChildModel(name="My parent is parent_a!")
child.save()
# Create two parents
parent_a = ParentModel(name="ThisParentWillHaveAChild", children=[child])
parent_b = ParentModel(name="ThisParentHasNoChildren", children=[])
parent_a.save()
parent_b.save()
child.parent = parent_a
child.save()
class Parent(MongoengineObjectType):
class Meta:
model = ParentModel
interfaces = (Node, )
class Child(MongoengineObjectType):
class Meta:
model = ChildModel
interfaces = (Node, )
class Query(graphene.ObjectType):
node = Node.Field()
parents = MongoengineConnectionField(Parent)
children = graphene.List(Child)
schema = graphene.Schema(query=Query, types=[Parent, Child])
x = schema.execute("""
query {
parents {
edges {
node {
name,
children {
edges {
node {
name,
parent { name }
}
}
}
}
}
}
}
""")
print("ERR:", x.errors)
print("DATA: {}".format(json.dumps(x.data)))
Hello Folks.
I tried graphene with SQLite and works like a charm, but now I am trying to use mongo DB using this project graphql-python/graphene-mongo
.
What I did was install the following packages
pip install "graphene-django>=2.0"
pip install graphene-mongo
pip install djongo
And include the following configuration in my settings.py
DATABASES = {
'default': {
'ENGINE': 'djongo',
'ENFORCE_SCHEMA': False,
'NAME': 'mymongodb',
'HOST': 'localhost',
'PORT': 3501,
}
}
Django connects perfectly because I can run migration and new collection was created in my new Mongo (empty) database using the following command.
python manage.py migrate
In addition, I could create a super user, with the instruction.
python manage.py createsuperuser
The admin user works like a charm.
I copy the model and schema from the example https://github.com/graphql-python/graphene-mongo/tree/master/examples/flask_mongoengine
and is accesible via documenation in Graphiql.
But when I tried to run the following query.
{
allEmployees {
edges {
node {
id,
name,
department {
id,
name
},
roles {
edges {
node {
id,
name
}
}
},
leader {
id,
name
}
tasks {
edges {
node {
name,
deadline
}
}
}
}
}
}
}
I got the error
{
"errors": [
{
"message": "You have not defined a default connection",
"locations": [
{
"line": 2,
"column": 3
}
],
"path": [
"allEmployees"
]
}
],
"data": {
"allEmployees": null
}
}
I have created a working example with graphene-mongo and graphene-federation (https://github.com/erebus1/graphene-federation).
We are currently working with GraphQL + Mongoengine. We split up into Microservices, so Federation was the thing to do. After fiddling around for a day, I was able to create a working example with Mongoengine. I want to share it, just in case somebody needs it too.
The example is made up of two Services. Each Service has its own DB. We want to be able to connect these to DBs, but have access via 1 GraphQL Endpoint to be able to connect multiple Frontend Applications. I choose the following file-structure:
gateway
|-gateway.js
graphene_federation
services
|-models
|-ReviewModel.py
|-UserModel.py
|-service1
|-app.py
|-config.py
|-schema.py
|-server.py
|-service2
|-app.py
|-config.py
|-schema.py
|-server.py
We have two DB-Models, a User
and a Review
. Each of the models is sitting in its own Database. They are only connected via Mongoengine.
from mongoengine import Document
from mongoengine.fields import StringField, ReferenceField
from .UserModel import UserModel
class ReviewModel(Document):
name = StringField()
user = ReferenceField(UserModel)
meta = {'db_alias': 'review-db'}
from mongoengine import Document
from mongoengine.fields import StringField, IntField
class UserModel(Document):
username = StringField()
age = IntField()
meta = {'db_alias': 'user-db'}
I wasn't very creative on the service. I just called them service1
and service2
. Service1 is handling the users and Service2 the reviews.
Both have the same structure:
serviceX
|
|-app.py
|-config.py
|-schema.py
|-server.py
The server.py file is the same in both services, except for the port to avoid conflicts. I am using a UploadView. We are using File uploads, so this a custom option.
from app import app
from graphene_file_upload.flask import FileUploadGraphQLView
from mongoengine import connect
from schema import schema
# we need to connect to both databases
connect('service1',
host=app.config['MONGO_HOST'],
alias='user-db',
username=app.config['MONGO_USER'],
password=app.config['MONGO_PWD'],
authentication_source="admin")
connect('service2',
host=app.config['MONGO_HOST'],
alias='review-db',
username=app.config['MONGO_USER'],
password=app.config['MONGO_PWD'],
authentication_source="admin")
app.add_url_rule('/graphql', view_func=FileUploadGraphQLView.as_view('graphql', schema=schema, graphiql=app.debug))
if __name__ == '__main__':
app.run(port=5000)
The app.py is even simpler.
from flask import Flask
app = Flask(__name__)
app.debug = True
app.config.from_object('config.DevConfig')
Nothing special here. Fill in your own details.
class BaseConfig:
TESTING = False
DEBUG = False
MONGO_USER = '******'
MONGO_PWD = '*****'
MONGO_HOST = '*******'
class DevConfig(BaseConfig):
DEBUG = True
The schema file is the big difference in the two services. Let's start by the User.
import graphene
from graphene_mongo import MongoengineObjectType
from graphene_federation import build_schema, key
from models.UserModel import UserModel
# The primary key
@key('id')
class User(MongoengineObjectType):
# we resolve a db reference by the id
def __resolve_reference(self, info, **kwargs):
# common mongoengine query
return UserModel.objects.get(id=self.id)
# Use Model as Type (common graphene_mongoengine)
class Meta:
model = UserModel
# define a query
class Query(graphene.ObjectType):
users = graphene.Field(User)
def resolve_users(self, info, **kwargs):
return UserModel.objects.all()
# define a mutation
class CreateUser(graphene.Mutation):
user = graphene.Field(User)
class Arguments:
username = graphene.String()
age = graphene.Int()
def mutate(self, info, username, age):
user = UserModel(username=username, age=age)
user.save()
return CreateUser(user)
class Mutation(graphene.ObjectType):
create_user = CreateUser.Field()
# build schema USE THE FEDERATION PACKAGE
schema = build_schema(Query, types=[User], mutation=Mutation)
As you can see, nothing special happens here. We just need to set the id
as our key and add a resolver for the key.
Service2 will now be able to resolve a type from another schema by using the external
function.
import graphene
from graphene_mongo import MongoengineObjectType
from graphene_federation import build_schema, key, external, extend
from models.ReviewModel import ReviewModel
# use extend and the key to tell service2 that this a type from another service
@extend('id')
class User(graphene.ObjectType):
# define key, use graphene.ID because this is the type used by graphene_mongo
# set it to external
id = external(graphene.ID())
# set id as key
@key('id')
class Review(MongoengineObjectType):
# Add user as type
user = graphene.Field(User)
# optional: we dont need to resolve the reference
def __resolve_reference(self, info, **kwargs):
return ReviewModel.objects.get(id=self.id)
# Use Model as Type (common graphene_mongoengine)
class Meta:
model = ReviewModel
# define a query
class Query(graphene.ObjectType):
reviews = graphene.Field(Review)
def resolve_reviews(self, info, **kwargs):
return ReviewModel.objects.all().first()
# define a mutation
class CreateReview(graphene.Mutation):
review = graphene.Field(Review)
class Arguments:
name = graphene.String()
user_id = graphene.String()
def mutate(self, info, name, user_id):
review = ReviewModel(name=name, user=user_id)
review.save()
return CreateReview(review)
class Mutation(graphene.ObjectType):
create_review = CreateReview.Field()
# build schema USE THE FEDERATION PACKAGE
schema = build_schema(Query, mutation=Mutation)
To combine our 2 Services into one gateway, we use the Apollo Gateway.
We just need to create the following file:
const { ApolloServer } = require('apollo-server');
const { ApolloGateway } = require("@apollo/gateway");
const gateway = new ApolloGateway({
serviceList: [
{ name: 'service1', url: 'http://127.0.0.1:5000/graphql' },
{ name: 'service2', url: 'http://127.0.0.1:5001/graphql' },
// more services
],
});
const server = new ApolloServer({
gateway,
// Currently, subscriptions are enabled by default with Apollo Server, however,
// subscriptions are not compatible with the gateway. We hope to resolve this
// limitation in future versions of Apollo Server. Please reach out to us on
// https://spectrum.chat/apollo/apollo-server if this is critical to your adoption!
subscriptions: false,
});
server.listen().then(({ url }) => {
console.log(`๐ Server ready at ${url}`);
});
Next we need to install the depencies:
npm install @apollo/gateway apollo-server graphql
The last thing is to just run the two flask applications and start the gateway via
node gateway.js
I hope all the instructions are clear enough. Have a great day!!!
orders = GenericEmbeddedDocumentField(choices=[(AOrders, BOrders)]) Throws conversion error
Filtering works for a base document to a query. But when filtering by a property for a nested document, the query returns all results regardless of the argument value.
Example.
Schema.py
class Subgraph(MongoengineObjectType):
class Meta:
model = SubgraphModel
interfaces = (RelayNode,)
class Graph(MongoengineObjectType):
class Meta:
model = GraphModel
interfaces = (RelayNode,)
class Query(graphene.ObjectType):
node = RelayNode.Field()
graph = RelayNode.Field(Graph)
graphs = MongoengineConnectionField(Graph)
Model.py
class Subgraph(Document):
meta = {'collection': 'subgraph'}
key = StringField(required=True)
class Graph(Document):
meta = {'collection': 'graph'}
key = StringField(required=True)
subgraphs = ListField(ReferenceField(Subgraph), required=True)
Query that fails:
{
graphs(key:"graph1") {
edges {
node {
id
subgraphs(key:"none") {
edges {
node {
id
key
}
}
}
}
}
}
}
The first argument to graphs filters properly. But the second argument does not filter at all, because all results are returned.
Result:
{
"data": {
"graphs": {
"edges": [
{
"node": {
"id": "R3JhcGg6NWI3NWU1YWYxMGYyMGMxZDliYmZmYzBj",
"key": "graph1",
"subgraphs": {
"edges": [
{
"node": {
"id": "U3ViZ3JhcGg6NWI3NWU1YWYxMGYyMGMxZDliYmZmYzAw",
"key": "subgraph1"
}
},
{
"node": {
"id": "U3ViZ3JhcGg6NWI3NWU1YWYxMGYyMGMxZDliYmZmYzAx",
"key": "subgraph2"
}
},
{
"node": {
"id": "U3ViZ3JhcGg6NWI3NWU1YWYxMGYyMGMxZDliYmZmYzAy",
"key": "subgraph3"
}
}
]
}
}
}
]
}
}
}
Here is the produced schema
schema {
query: Query
}
type Graph implements Node {
id: ID!
key: String!
subgraphs(before: String, after: String, first: Int, last: Int, id: ID, key: String): SubgraphConnection
}
type GraphConnection {
pageInfo: PageInfo!
edges: [GraphEdge]!
}
type GraphEdge {
node: Graph
cursor: String!
}
interface Node {
id: ID!
}
type PageInfo {
hasNextPage: Boolean!
hasPreviousPage: Boolean!
startCursor: String
endCursor: String
}
type Query {
node(id: ID!): Node
graph(id: ID!): Graph
graphs(before: String, after: String, first: Int, last: Int, id: ID, key: String): GraphConnection
}
type Subgraph implements Node {
id: ID!
key: String!
}
type SubgraphConnection {
pageInfo: PageInfo!
edges: [SubgraphEdge]!
}
type SubgraphEdge {
node: Subgraph
cursor: String!
}
Error:
Download error on https://pypi.python.org/simple/pytest-runner/: EOF occurred in violation of protocol (_ssl.c:590) -- Some packages may not be found!
Couldn't find index page for 'pytest-runner' (maybe misspelled?)
I resolved the problem by:
Right now, extending MongoengineObjectType
by subclassing is not possible in any useful way as __init_subclass_with_meta__
is immediately called on encountering a descendant class definition. This makes several assumptions, e.g. Meta.model
being defined on the subclass. Extension classes might want to deduce the model via their subclasses and generally wouldn't know about it at the point of class body execution.
The proposed solution is some mechanism to defer initialization until manually requested, if some flag (e.g. manual_init
) is passed in Meta
.
My current workaround is using multiple inheritance which allows customization. A superficial example - let's say we wish to use quux
instead of model
for the Meta
key defining the model:
class Enhancer:
@classmethod
def __init_subclass_with_meta__(cls, quux, **kwargs):
kwargs["model"] = quux
super().__init_subclass_with_meta__(**kwargs)
class AssetSchema(Enhancer, MongoengineObjectType):
class Meta:
interfaces = (relay.Node,)
quux = Asset
Hi,
How can I achieve Hashing/ Encrypting a password field?
How about having a HashField or MD5Field?
Regards
I am receiving an error node = kv[1].get_type()._type._meta
AttributeError: 'NoneType' object has no attribute '_type'
when I am using "EmbeddedDocument(LatLang)"
class LatLng(EmbeddedDocument):
lat = FloatField()
lng = FloatField()
class User(Document):
email = StringField(required=True)
first_name = StringField(max_length=50)
last_name = StringField(max_length=50)
location = EmbeddedDocumentField(LatLng)
I am new to graphql and grahene
I am attempting to hydrate a MongoengineObjectType from my resolve method
I have a few pre-defined filter rules that need to run before I can return the data, but I cant seem to return the model itself
`class UserNode(MongoengineObjectType):
class Meta:
model = User
class Query(graphene.ObjectType):
user = graphene.Field(UserNode, id=graphene.String())
def resolve_user(self, info, id):
auth_user = info.context.get('user')
user = User.objects.get(userId=id, foo_Id=auth_user.foo_Id)
return user`
Dear,
Is it possible to move the following find to a GraphQL query?
Example Mongodb: (Specifically { date_ar: {
ยดยดยด
db.collection.find( { date_ar: {
$regex: /23:55$ / } } ).limit(30).sort( { $natural: -1 } ).pretty()
{
"_id" : ObjectId("5cb9388e87200745fba9d727"),
"dm3rf" : "4240.02",
"dm3pr" : "4945.75",
"rdm3p" : "40.67",
"unit" : "m3",
"dm3" : "3813.85",
"truckm" : "477",
"date_ar" : "2019-04-18 23:55",
"rdm3" : "1993.03",
"dm3rf_p" : "86.53",
"dm3_p" : "77.83",
"date_utc" : "2019-04-19 02:55:10.030226"
}
{
"_id" : ObjectId("5cb7e7118720071491f42149"),
"dm3pr" : "5623.5",
"date_ar" : "2019-04-17 23:55",
"dm3" : "4265.61",
"dm3_p" : "87.05",
"rdm3" : "3986.05",
"date_utc" : "2019-04-18 02:55:13.017360",
"truckm" : "533",
"dm3rf" : "4353.11",
"dm3rf_p" : "88.84",
"unit" : "m3",
"rdm3p" : "81.35"
}
ยดยดยด
Example GraphQL - (I can only select a specific day and time)
ยดยดยด
allDaym3(dateAr: "2019-04-16 23:55") {
edges {
node {
dm3
dm3rf
rdm3
dm3pr
dateAr
}
}
}
ยดยดยด
ยดยดยด
{
"data": {
"allDaym3": {
"edges": [
{
"node": {
"dm3": "4196.06",
"dm3rf": "4192.95",
"rdm3": "3986.05",
"dm3pr": "5695.5",
"dateAr": "2019-04-16 23:55"
}
}
]
},
ยดยดยด
models
class Article(Document):
meta = {'collection': 'test_article'}
headline = StringField(required=True)
pub_date = DateTimeField(default=datetime.now)
class Player(Document):
first_name = StringField(required=True)
last_name = StringField(required=True)
opponent = ReferenceField('Player')
articles = ListField(ReferenceField('Article'))
fixture
article1 = Article(headline='Hello', editor=editor1)
article1.save()
article2 = Article(headline='World', editor=editor2)
article2.save()
player1 = Player(first_name='Michael', last_name='Jordan')
player1.save()
query
class Query(graphene.ObjectType):
all_players = MongoengineConnectionField(PlayerNode)
query = '''
query PlayersQuery {
allPlayers {
edges {
node {
firstName,
allArticles {
edges {
node {
headline
}
}
}
}
}
}
}
'''
Now it returns all articles from db under Michael Jordan
player node :(
Thanks for a great library.
After starting examples/flask_mongoengine :
I expected I would be able to query by id?
I'm unable to query by id, but can query by name
{
allEmployees(id:"RW1wbG95ZWU6NWE5ZjE4NzA2MGJmZmVhZDcyYmI3Zjgw") {
pageInfo {
hasNextPage
}
edges {
node {
id, name
department {
id, name
}
}
}
}
}
{
"errors": [
{
"message": "u'RW1wbG95ZWU6NWE5ZjE4NzA2MGJmZmVhZDcyYmI3Zjgw' is not a valid ObjectId, it must be a 12-byte input or a 24-character hex string",
"locations": [
{
"column": 3,
"line": 13
}
]
}
],
"data": {
"allEmployees": null
}
}
{
allEmployees( name: "Peter") {
pageInfo {
hasNextPage
}
edges {
node {
id, name
department {
id, name
}
}
}
}
}
{
"data": {
"allEmployees": {
"pageInfo": {
"hasNextPage": false
},
"edges": [
{
"node": {
"id": "RW1wbG95ZWU6NWE5ZjE4NzA2MGJmZmVhZDcyYmI3Zjgw",
"name": "Peter",
"department": {
"id": "RGVwYXJ0bWVudDo1YTlmMTg3MDYwYmZmZWFkNzJiYjdmN2M=",
"name": "Engineering"
}
}
}
]
}
}
}
Are there any plans to add support for simple create / update / delete mutations? It seems like you could view the fields associated with a Mongoengine Document and automatically build the arguments to a graphene mutation, instead of needing to manually write one for each object. Thoughts on this?
In the flask mongoengine example, in app.py, a 'default_query' is declared.
I had assumed that there was some magic in the background that would cause this default query to be populated by default when the graphiql view is requested from the browser.
However, this doesn't happen in my implementation attempt -- the query pane is just empty. The rest of the graphiql interface works just fine. Searching code in both graphene-mongo and flask-graphql doesn't seem to turn up any references to 'default_query'.
Is my expectation above correct, i.e. is this a way to populate the graphiql interface with a default query?
If the expectation is correct, then maybe it's not working for me because I'm declaring default_query within a flask app factory method? How would I set the default query in this case?
I'm confused by this code:
graphene-mongo/graphene_mongo/fields.py
Lines 74 to 77 in fbdd3e2
It seems to me that this test is basically just seeing if the field is a graphene structure (https://github.com/graphql-python/graphene/blob/43aec720a851a7a8e9d3e3a06b96b9a61232a5e7/graphene/types/structures.py), or, really, a NonNull.
Is there a reason filter is restricted to non-null fields? Mongo can query against nulls and missing keys / values.
model using PointField raises an error
Exception: Don't know how to convert the MongoEngine field <mongoengine.fields.PointField object at 0x04365090> (<class 'mongoengine.fields.PointField'>)
After updating graphene-mongo from 0.18 to 0.2.0, I could not get "ListField(StringField())" types in query parameter. So I revert back to 0.18.
For example:
query{
allPosts(here I can have all fields of posts collection except 'selectedtags' and 'postpics')
}
in post_model.py I have following
class Posts(Document): meta = {'collection': 'posts'} categoryid = ReferenceField(Categories) cityid = ReferenceField(City) pdate = DateTimeField() content = DictField(required = True) selectedtags = ListField(StringField()) postpics = ListField(StringField()) featured = BooleanField()
I'd like to filter nested documents
models:
class Internal(EmbeddedDocument):
potential = fields.IntField(min_value=1, max_value=3)
class Lead(Document):
meta = {'collection': 'lead'}
id = fields.ObjectIdField(required=True, primary_key=True, default=ObjectId)
internal = fields.EmbeddedDocumentField(Internal)
query:
{
leads {
edges {
node {
id
internal(potential: 1) {
potential
}
}
}
}
}
but response is:
{
"errors": [
{
"message": "Unknown argument \"filter\" on field \"internal\" of type \"LeadNode\".",
"locations": [
{
"line": 6,
"column": 18
}
]
}
]
}
I'm trying to achieve filtering by resolvers:
class Query(graphene.ObjectType):
node = Node.Field()
leads = MongoengineConnectionField(LeadNode)
leads_by_internal = graphene.Field(
LeadNode,
internal__potential=graphene.Int(),
internal__warmth=graphene.Int(),
internal__next_step=graphene.Int(),
)
def resolve_leads_by_internal(_, __, **kwargs):
qs = Lead.objects.filter(**kwargs)
return qs
But I don't know, what type resolver should return
Any help guys, pls?
I had a model:
class MyModel(EmbeddedDocument):
myField = BooleanField(null=True)
and was getting an error about "Cannot return null for non-nullable". It seemed that it didn't matter if I set null=True, null=False. Digging into this, I found:
graphene-mongo/graphene_mongo/converter.py
Lines 39 to 41 in fbdd3e2
Why is this?
Hello and thx for your lib,
I'd like to self-reference a model, but I'm not sure how to do it as I'm quite new to Python, what I do is:
class Player(Document):
created_on = DateTimeField(default=datetime.now, db_field='d')
name = StringField(required=True, db_field='n')
Player.friends = ListField(ReferenceField(Player))
But I get an AttributeError: 'NoneType' object has no attribute '_type'
in python3.6/site-packages/graphene_mongo/converter.py
Am I doing it wrong or is it not possible?
Hi, I'm trying to update a nested document including an EmbeddedDocumentListField / EmbeddedDocument with graphene-mongo. Creating a new user via create mutation works perfectly fine, but when I try to update a nested document, it fails with the error
Invalid embedded document instance provided to an EmbeddedDocumentField: ['label']
Here is my code:
models.py:
from mongoengine import Document, EmbeddedDocumentListField, EmbeddedDocument
from mongoengine.fields import StringField
class UserLabel(EmbeddedDocument):
code = StringField()
value = StringField()
class User(Document):
meta = {'collection': 'user'}
first_name = StringField(required=True)
last_name = StringField(required=True)
label = EmbeddedDocumentListField(UserLabel)
app.py:
from flask import Flask
from flask_graphql import GraphQLView
import graphene
from graphene_mongo import MongoengineObjectType
from mongoengine import connect
from models import User as UserModel, UserLabel as UserLabelModel
app = Flask(__name__)
class UserLabel(MongoengineObjectType):
class Meta:
model = UserLabelModel
class User(MongoengineObjectType):
class Meta:
model = UserModel
class UserLabelInput(graphene.InputObjectType):
code = graphene.String()
value = graphene.String()
class UserInput(graphene.InputObjectType):
id = graphene.String()
first_name = graphene.String()
last_name = graphene.String()
label = graphene.List(UserLabelInput, required=False)
class Query(graphene.ObjectType):
users = graphene.List(User)
def resolve_users(self, info):
return list(UserModel.objects.all())
class createUser(graphene.Mutation):
user = graphene.Field(User)
class Arguments:
user_data = UserInput()
def mutate(root, info, user_data):
user = UserModel(
first_name=user_data.first_name,
last_name=user_data.last_name,
label=user_data.label
)
user.save()
return createUser(user=user)
class updateUser(graphene.Mutation):
user = graphene.Field(User)
class Arguments:
user_data = UserInput()
def mutate(self, info, user_data):
user = UserModel.objects.get(id=user_data.id)
if user_data.first_name:
user.first_name = user_data.first_name
if user_data.last_name:
user.last_name = user_data.last_name
if user_data.label:
user.label = user_data.label
user.save()
return updateUser(user=user)
class Mutation(graphene.ObjectType):
create_user = createUser.Field()
update_user = updateUser.Field()
schema = graphene.Schema(query=Query, mutation=Mutation)
app.add_url_rule('/graphql', view_func=GraphQLView.as_view('graphql', schema=schema, graphiql=True))
if __name__ == '__main__':
app.run(debug=True, port=1234)
Trying to run this update mutation via graphiql :
mutation {
updateUser(userData: {
id: "5d6f8bbbe3ec841d93229322",
firstName: "Peter",
lastName: "Simpson",
label: [
{
code:"DE",
value: "Peter Simpson"
}
]
}) {
user {
id
firstName
lastName
label {
code
value
}
}
}
}
I get the error:
{
"errors": [
{
"message": "ValidationError (User:5d6f8bbbe3ec841d93229322) (Invalid embedded document instance provided to an EmbeddedDocumentField: ['label'])",
"locations": [
{
"line": 2,
"column": 3
}
],
"path": [
"updateUser"
]
}
],
"data": {
"updateUser": null
}
}
Updating without the nested field works perfectly fine.
How can I resolve this ?
If I create add a new field and the field is null, it leads to an error in
Cannot return null for non-nullable field Type.field.
In my model, I didn't set required to true for that field. After inspecting I found this in converter.py
String(description=field.db_field, required=not field.null)
which sets all field to required.
I'm trying to get a stack of Sanic
, mongodb
and graphql
to work. All async..
I can do mongo async using https://github.com/heynemann/motorengine, but then I have no way of using graphene-mongo
as it wants a valid Mongoengine Model
.
I can't find any issues on this in this repo, so I might be getting this wrong, but is there plans for supporting async? Or anyway I can hack it in using the current graphene-mongo
?
Support for filtering edges on based on cursors. Currently the libarary returns an error when you ask it something like this:
{
questions(first: 2, after: "YXJyYXljb25uZWN0aW9uOjE=") {
edges {
node {
id
}
cursor
}
}
}
It will return this kind of error
{
"errors": [
{
"message": "Cannot resolve field \"after\"",
"locations": [
{
"line": 2,
"column": 3
}
]
}
],
"data": {
"questions": null
}
}
Hi,
I have the following models:
class ProfessorMetadata(EmbeddedDocument):
id = StringField()
first_name = StringField()
last_name = StringField()
departments = ListField(StringField())
class ProfessorVector(Document):
meta = {'collection': 'professorVectors'}
vec = ListField(FloatField())
metadata = EmbeddedDocumentField(ProfessorMetadata)
And setup a schema like so
class Query(graphene.ObjectType):
professor_vector = graphene.Field(ProfessorVector, id=graphene.String())
def resolve_professor_vector(self, info, id):
print(id)
return ProfessorVectorModel.objects(metadata__id=id).first()
schema = graphene.Schema(query=Query, types=[ProfessorVector])
And a sample of the object in the database:
{
"_id" : ObjectId("5b0c4c9628086740a872dd4d"),
"id" : "5e06aa20-6805-4eef-a144-5615dedbe32b",
"vec" : [
-1.9864423274993896,
-0.6392910480499268
],
"metadata" : {
"id" : "5e06aa20-6805-4eef-a144-5615dedbe32b",
"first_name" : "Nigel S",
"last_name" : "Paneth",
"departments" : [
"Epidemiology and Biostatistics"
]
}
}
However with this setup, I am not able to run the following query in graphiql:
query {
professorVector(id: "5e06aa20-6805-4eef-a144-5615dedbe32b") {
id
vec
metadata {
first_name
}
}
}
I get the following error:
{
"errors": [
{
"message": "Cannot query field \"metadata\" on type \"ProfessorVector\".",
"locations": [
{
"line": 5,
"column": 5
}
]
}
]
}
What's the issue with EmbeddedDocumentField
? Does graphene-mongo
support this kind of embedded document? Any help would be appreciated.
Thanks.
Have the DateTimeField field in MongoEngine automatically resolve to a graphene scalar.
Do you have a way to filter queries? I understand that the graphene-django project relied on django-filter for query filtering. Is there something similar already implemented in this project?
I am trying to perform the following query:
query {
allUsers(name: "foo"){
edges{
node{
id,
name
}
}
}
}
Using the slicing pagination for getting the first n items works, but asking for the last n doesn't. Doing this query for example works:
{
questions(first: 2) {
edges {
node{
id
}
cursor
}
}
}
You get a result like this
{
"data": {
"questions": {
"edges": [
{
"node": {
"id": "UXVlc3Rpb246NWFiNmM1OTY0YmFhM2MwMDA0YzIzMjBl"
},
"cursor": "YXJyYXljb25uZWN0aW9uOjA="
},
{
"node": {
"id": "UXVlc3Rpb246NWFiNmM1OTg0YmFhM2MwMDA0YzIzMjBm"
},
"cursor": "YXJyYXljb25uZWN0aW9uOjE="
}
]
}
}
}
But doing this query breaks:
{
questions(last: 2) {
edges {
node {
id
}
cursor
}
}
}
and give you something like this
{
"errors": [
{
"message": "stop index must be greater than startindex for slice slice(None, -2, None)",
"locations": [
{
"line": 2,
"column": 3
}
]
}
],
"data": {
"questions": null
}
}
I know I'm missing something. Given a model with multiple document types in a collection:
class AModel(Document):
meta = {'allow_inheritance': True}
a_field = StringField()
class ASubModel(AModel):
a_sub_field = StringField()
I can construct a schema and query:
class A(MongoengineObjectType):
class Meta:
model = AModel
interfaces = (Node,)
class ASub(A):
class Meta:
model = ASubModel
interfaces = (Node,)
class Query(graphene.ObjectType):
node = Node.Field()
all_a = MongoengineConnectionField(A)
If I run the allA
query, I get back all the documents as expected, but I can't access ASub
's fields because the returned type is A
, not ASub
, even though the class is identified as A.ASub
. E.g.,:
{
"data": {
"allA": {
"edges": [
{
"node": {
"id": "VGFyZ2V0OjVjZTVmOTMwMjRmN2NhMGJmMjZlNzZmMQ==",
"Cls": "A.ASub",
"__typename": "A"
}
}
]
}
}
Attempting to resolve ASub.a_sub_field
results in an error.
Inline fragment doesn't work either:
{
"errors": [
{
"message": "Fragment cannot be spread here as objects of type A can never be of type ASub",
"locations": [
{
"line": 8,
"column": 9
}
]
}
]
}
I'm clearly doing something wrong, but I don't know what.
First of all, thank you for writing this library. I've been wanting to try GraphQL out with my current project but didn't want to have to create an entire new backend application from scratch. I can reuse my existing models thanks to this library, way cool ๐ ๐ฅ
Now for my issue...
I have a parent/child relationship defined like this:
from mongoengine import Document
class Parent(Document):
bar = StringField()
class Child(Parent):
baz = StringField()
When I defined my schema and attempt to query against the Child
model, it says Unknown argument "bar" on field "child" of type "Query"
My query:
{
child(bar:"a valid value") {
edges {
node {
bar
baz
}
}
}
}
from graphene_mongo import MongoengineConnectionField, MongoengineObjectType
from app.models import Child as ChildModel
class Child(MongoengineObjectType):
class Meta:
model = ChildModel
interfaces = (Node,)
class Query(graphene.ObjectType):
node = Node.Field()
child = MongoengineConnectionField(Child)
schema = graphene.Schema(query=Query, types=[Child])
I may just be misusing the library, or perhaps this is a feature that isn't implemented yet. If the feature hasn't been implemented yet I am up for taking a stab at it. Is there a way for my schema to infer the parent's attributes based on how I define them like the above example? Thank you again!
Working with a simple GenericReferenceField works fine. But as mentioned in #70 support for a List of GenericReferenceFields would be great. Thank you in advance!
I have a model defined like so:
from mongoengine import Document, StringField, ReferenceField
class Bar(Document):
pass
class Foo(Document):
parent = ReferenceField('Bar')
name = StringField(default='')
If I set up my schema like this:
from graphene_mongo import MongoengineConnectionField, MongoengineObjectType
from .models import (Foo as FooModel, Bar as BarModel)
class Bar(MongoengineObjectType):
class Meta:
model = BarModel
interfaces = (Node,)
class Foo(MongoengineObjectType):
class Meta:
model = FooModel
interfaces = (Node,)
class Query(graphene.ObjectType):
node = Node.Field()
foos = MongoengineConnectionField(Foo)
bars = MongoengineConnectionField(Bar)
schema = graphene.Schema(query=Query, types=[Foo, Bar])
Should I be able to query for Foo
with parent
equal to the id of a Bar
? Example query:
{
foos(parent: "some_valid_id_in_string_form") {
edges {
node {
name
}
}
}
}
Hi,
It would be good if graphene mongo had support for filters. For example
query { allPersons(filter: { age_gt: 18 }) { firstName lastName } }
Is there any other way to achieve this or fire a query like thin in graphene-mongo?
I've used a MongoengineObjectType
class to define the schema from model.
There's a way to use a reference model to define a InputObjectType
or AbstractType
class? Something like that:
class UserFields(graphene.AbstractType):
class Meta:
model = model.User
class User(graphene.ObjectType, UserFields):
pass
class UserInput(graphene.InputObjectType, UserFields):
pass
Please add support for filefield
How to implement something like cursor.limit(number)
( ref: https://docs.mongodb.com/manual/reference/method/cursor.limit/ )
OR How can I restrict the number of results? The main purpose is to create pagination.
My collection has 5million documents, and thus I require pagination set up via graphql.
Hi,
I am wondering why there is an edges and nodes attributes in the result set? It seems to break the concept of being able to have a consistent object model, query language and result set.
Hi,
how can I use cursor based pagination (page=page, per_page=...) with your library ? I can't modify the mongo request using something like this:
def resolve_users(self, info):
return list(UserModel.objects.find({...}).sort(...).limit(limit))
because then I get 'QuerySet' object has no attribute 'find'
Please provide information regarding this functionality or implement this feature.
Hello,
I am currently working on a project where I use the Apollo Federation Gateway and graphene-federation to connect multiple Microservices. For each external Type I need to add the following resolver to the type.
def __resolve_reference(self, info, **kwargs):
return MY_MODEL.objects.get(id=self.id)
Couldn't we just add something like the following to the MongoEngineObjectType
?
@classmethod
def __resolve_reference(cls, info):
return cls._meta.model.objects.get(id=self.id)
The only problem is that we need to resolve the reference by the Types key which isn't alwasy the id (just in my case). It could be any property of the model.
Thanks!
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.