I faced with a small issue while trying to add description to a resolver in graphene (to be able to fetch this data in GraphiQL). Mostly the problem is that I want to be able to fetch docstring from resolver directly, rather than specify it as a description parameter of a Field in Query class.
Here is a small snippet with explanation:
from graphene import ObjectType, String, Field
class Person(ObjectType):
full_name = String()
def resolve_full_name(parent, info):
return f"{parent.first_name} {parent.last_name}"
class Query(ObjectType):
me = Field(Person)
def resolve_me(parent, info):
"""
I want to display this docstring description in GraphiQL,
rather than use `description` attribute, eg.
me = Field(Person, description="Blah-blah")
"""
return get_human(name="Luke Skywalker")
Are there any workarounds and ideas on how I can do this?
Related
I'm using Graphene-Django to build a GraphQL API, and I've defined object types as explained in the docs. By way of example,
import graphene
from graphene_django import DjangoObjectType
from .models import Question
class QuestionType(DjangoObjectType):
class Meta:
model = Question
fields = ("id", "question_text")
class Query(graphene.ObjectType):
questions = graphene.List(QuestionType)
question_by_id = graphene.Field(QuestionType, id=graphene.String())
def resolve_questions(root, info, **kwargs):
# Querying a list
return Question.objects.all()
def resolve_question_by_id(root, info, id):
# Querying a single question
return Question.objects.get(pk=id)
This works fine for fetching the content of a Question model in a GraphQL query, but I'd also like to serialize my Question objects to a JSON representation in log files and tests. I can write a separate utility function, but it seems redundant when I already have an existing GraphQL schema that defines which objects fields I'm interested in and how to serialize them.
Basically, I'm looking for a Graphene analogue to using a DRF serializer
serializer = CommentSerializer(comment)
serializer.data
# {'email': 'leila#example.com', 'content': 'foo bar', 'created': '2016-01-27T15:17:10.375877'}
Ideally, I'm looking for something like
from my_app.schema import QuestionType
from my_app.models import Question
question_object = Quest.objects.get(pk=1)
data = QuestionType.to_dict(question_object)
I've looked at the Graphene docs, and poked around the source on Github but it all seems very obfuscated and I can't find an obvious way to do what I want.
Can anyone offer a concise example of using a Graphene ObjectType to serialize a single model instance outside the entire GraphQL query context?
First, Saleor with GraphQL is fantastic. Just love it.
The products we are selling have additional metadata we need to get from Graphql. Out of the box, the Graphql queries work fine, such as:
{
product (id: "UHJvZHVjdDo3Mg==") {
id
name
description
}
}
What I need to do is expose data from my products table with additional columns, such as productInfo1, productInfo2, and productInfo3. This part is easy of course.
However, I am struggling with how to update the Saleor Graphql so I can run a query like the following:
{
product (id: "UHJvZHVjdDo3Mg==") {
id
name
description {
productInfo1
productInfo2
productInfo3
}
}
}
I have been through the Saleor docs, Stack Overflow, and a variety of blogs... I've attempted some logical approaches myself, without any success.
I'm eager to start working on these types of updates for our needs here. Any suggestions or links to "how to" locations would be greatly appreciated!
If you'd like to add subfields to description there is a couple of things you have to do:
Create new description object type which contains the subfields you want, e.g.:
class ProductDescription(graphene.ObjectType):
productInfo1 = graphene.String()
productInfo2 = graphene.String()
productInfo3 = graphene.String()
Set the description field with the new type under Product type:
class Product(CountableDjangoObjectType):
...
description = graphene.Field(ProductDescription)
Add resolver for description under Product type:
def resolve_description(self, info):
return ProductDescription(
productInfo1=self.description,
productInfo2='Some additional info',
productInfo3='Some more additional info',
)
Saleor's GraphQL API is based on the Graphene framework. You can find more about resolvers and object types here: https://docs.graphene-python.org/en/latest/types/objecttypes/#resolvers.
We can use serializer as a field inside another serializer..
Wonder why there's a Field class and Serializer class in DRF?
class CommentSerializer(serializers.Serializer):
user = UserSerializer()
content = serializers.CharField(max_length=200)
created = serializers.DateTimeField()
example serializer is taken from the doc https://www.django-rest-framework.org/api-guide/serializers/
As you can see, UserSerializer is much like a Field .
I'm just curious why they have serializer and field class separately..
Serilaizer is infact a field in DRF. Serializers can be nested and that is why it can be used as a field in other serializers. And yes, if you check the source code, the BaseSerializer is a subclass of Field as the serializer is just a special case of a field.
In my opinion:
In django rest framwork, you can think Serializer like a mask. It cover your origin data and change it to anything you want. Like format your json data , or validate your input data have correct format or not.
In your example,
content = serializers.CharField(max_length=200)
created = serializers.DateTimeField()
Comment have 2 direct field type CharField and DateTimeField.
user = UserSerializer()
Comment have field type is UserSerializer. This is different Serializer, and django know your CommentSerializer will have relationship with UserSerializer. And anything define in UserSerializer will use in here, for format json output or validate. And with define this nested objects, your output json will have more data like
'user': {'email': 'foobar', 'username': 'doe'}
And if you want create Comment with one user, you must pass all validate define in UserSerializer.
Conclude: in this example
Field class use for direct field.
Serializer class for relationship with other class
I've implemented graphql and I'm migrating to relay. I already have a uuid for every table and that is named 'id'. And my application I found this github thread that talks about possibly changing the spec but it feels like a rabbit hole.
Is there a simple way that I can use my own custom id with relay?
If you've already implemented a default relay endpoint then you should have some
TableNameNode classes that have a Meta nested class, and a seperate Query
class.
class ExampleTableNameNode(DjangoObjectType):
class Meta:
model = ExampleTableName
interface = (relay.Node,)
class Query(object):
example_table_name = relay.Node.Field(ExampleTableNameNode)
all_example_table_names = DjangoFilterConnectionField(ExampleTableNameNode)
def resolve_example_table_name(self, info, **kwargs):
pass
def resolve_all_example_table_names(self, info, **kwargs):
pass
The interface = (relay.Node,) is what defines:
How the ids are being generated
How they are used to fetch data
If we create a relay.Node subclass that redefines these two features then we can use our custom ids.
class CustomNode(relay.Node):
class Meta:
name = 'Node'
#staticmethod
def to_global_id(type, id):
#returns a non-encoded ID
return id
#staticmethod
def get_node_from_global_id(info, global_id, only_type=None):
model = getattr(Query,info.field_name).field_type._meta.model
return model.objects.get(id=global_id)
Here we implemented two functions, to_global_id, and get_node_from_global_id.
The line model = ... is a bit of magic to go from the graphql query table name
to the actual model. If that doesn't work you'll just need to make a dictionary
to go from something like example_table_name to the actual ExampleTableName
django model.
Once you do that you'll have to replace the two references to relay.Node with
CustomNode like so.
class ExampleTableNameNode(DjangoObjectType):
class Meta:
model = ExampleTableName
interface = (CustomNode,)
class Query(object):
example_table_name = CustomNode.Field(ExampleTableNameNode)
all_example_table_names = DjangoFilterConnectionField(ExampleTableNameNode)
def resolve_example_table_name(self, info, **kwargs):
pass
def resolve_all_example_table_names(self, info, **kwargs):
pass
The answer is in the graphene docs. I read them when I was implementing
graphene and relay but there is so much to learn at once that it's easy to read
through custom node section and not remember later that you need to do a custom
node solution.
I am using Django REST framework with Mongoengine. When I attempt serialize an optional field on an embedded document, the framework still requires the field and returns the error message that the field cannot be left blank. How do I make fields optional on an EmbeddedDocument? It works fine for standard Document model objects, just not for EmbeddedDocument objects.
My model:
class Event(EmbeddedDocument):
id = ObjectIdField(required=True, default=ObjectId())
status = StringField(required=True, max_length=50)
note = StringField(required=False, max_length=2000)
created = DateTimeField(required=True, default=timezone.now())
My serializer:
class EventSerializer(EmbeddedDocumentSerializer):
class Meta:
model = Event
depth = 2
def validate(self, data):
return data
Note that the field "note" is set to required=False. When I serialize the document, however, I still get an error message that the field can't be left blank. Thank you!
I came across the same problem, I think you can mark the fields as blank=True and it should allow you to place nothing in those fields.