How to pass complex types as arguments in graphene Python - graphene-python

I'm trying to create a query that accepts a complex argument object like so:
class Pair(graphene.ObjectType):
x = graphene.Int()
y = graphene.Int()
class Pairs(graphene.ObjectType):
pairs = graphene.List(graphene.NonNull(graphene.Field(Pair, required=True)), required=True)
class Query(graphene.ObjectType):
endpoint = graphene.Field(ResultType, pairs=graphene.Argument(Pairs, required=True))
I'm invoking it as follows in testing:
client = graphene.test.Client(graphene.Schema(query=Query))
executed = client.execute(
"""query($pairs: Pairs!) {
endpoint(pairs: $pairs) {
[result type goes here]
}
}"""
Any thoughts on what may be wrong with this approach?

I was able to do with the code below
class SomeFilter(graphene.InputObjectType):
name = graphene.String()
class Query(graphene.ObjectType):
all_somes = graphene.List(Some, options=SomeFilter())
def resolve_all_somes(self, info, options=None):
if options:
if name := options.get('name'):

Related

How to get models schema (type_defs) in form of string?

Example Code
I have the following model.
class Post(Base):
__tablename__ = "post"
id = Column(Integer, primary_key=True, index=True)
title = Column(String)
author = Column(String)
content = Column(String)
time_created = Column(DateTime(timezone=True), server_default=func.now())
with this schema
class PostSchema(SQLAlchemyObjectType):
class Meta:
model = Post
Problem
How to to get the graphql schema definition in form of string like this
"""
type Post{
id: ID
title: string!
author: String!
content: String!
time_created: Int!
}
"""
I tried this, but there is not type_defs option.
graphene.Field(PostModel).type_defs
One option you can use is to introspect your schema not just the object type. Suppose you have a graphene schema called schema,
from graphene_sqlalchemy import SQLAlchemyObjectType
class schema(SQLAlchemyObjectType):
class Meta:
model = MyModel
you can do something like:
schema_dict = schema.introspect()
This will return a dict version of your schema and the types that you want can be found here:
types = schema_dict["__schema"]["types"]
Unfortunately, this returns a list of all object types so you might need to process it to narrow down what you want with something like:
list(filter(lambda types: types['name'] == 'PostSchema', types))
alternative way
def make_schemas(model):
d = """
"""
for i, key in model.__table__.columns.items():
x = str(key.type.python_type)
x = x.replace("<class '", '')
x = x.replace("'>", '')
x = x.title()
if x in ['Str', 'Datetime.Datetime']:
x = 'String'
if x == 'Bool':
x = 'Boolean'
d += f"""
{i}: {x}
"""
y = f"""
type {model.__tablename__.title()} {{
{d}
}}
"""
return y

A simple query but Graphene-Django is returning null values

I am trying to make a simple query with graphene-django but i can not get the DB, it gives me null.
I think the code is ok, what is going wrong, I am working for hours on it.
Do you have any idea, what it is?
Thanks in advance
import graphene
from graphene_django.types import DjangoObjectType, ObjectType
from myProject.models import Times
class TimesType(DjangoObjectType):
class Meta:
model=Times
fields="__all__"
class Query(ObjectType):
today_times = graphene.Field(TimesType, id=graphene.ID())
all_times = graphene.List(TimesType)
def resolve_todaytimes(self, info, id=None):
return Times.objects.get(pk=id)
def resolve_alltimes(root, info, **kwargs):
return Times.objects.all()
schema = graphene.Schema(query=Query, mutation=Mutation)
query {todayTimes(id:"1029"){id}}
{
"data": {
"todayTimes": null
}
}
The resolver method should be named in resolve_<FieldName> format
class Query(ObjectType):
today_times = graphene.Field(TimesType, id=graphene.ID())
all_times = graphene.List(TimesType)
def resolve_today_times(self, info, id=None): # not `resolve_todaytimes`
return Times.objects.get(pk=id)
def resolve_all_times(root, info, **kwargs): # not `resolve_alltimes`
return Times.objects.all()
Alternatively, you can use the resolver parameter to set the callable resolver as,
def resolve_todaytimes(self, info, id=None):
return Times.objects.get(pk=id)
def resolve_alltimes(root, info, **kwargs):
return Times.objects.all()
class Query(ObjectType):
today_times = graphene.Field(
TimesType,
id=graphene.ID(),
resolver=resolve_todaytimes
)
all_times = graphene.List(
TimesType,
resolver=resolve_alltimes
)

Mutations - batch creation of objects

I want to use graphene to create many people in one go.
The document only mention the way to create one person like this:
class CreatePerson(graphene.Mutation):
class Input:
name = graphene.String()
age = graphene.Int()
ok = graphene.Boolean()
person = graphene.Field(lambda: Person)
#staticmethod
def mutate(root, args, context, info):
person = Person(name=args.get('name'), age=args.get('age'), mobile=args.get('mobile'))
ok = True
return CreatePerson(person=person, ok=ok)
are there any ways to get it done?
Instead of using a mutation that creates a list of objects, you can also call a mutation that creates one objects multiple times in one GraphQL request. This is accomplished using GraphQL Aliases:
mutation {
c001: createPerson(
name: "Donald Duck"
age: 42
) {
id
}
c002: createPerson(
name: "Daisy Duck"
age: 43
) {
id
}
c003: createPerson(
name: "Mickey Mouse"
age: 44
) {
id
}
}
I can figure out a solution base on the answer of Jan Hančič
There is a type called graphene.InputObjectType to use in this case
The solution can be
class PersonInput(InputObjectType):
name = graphene.String()
age = graphene.Int()
class CreatePeople(graphene.Mutation):
class Input:
people = graphene.List(PersonInput)
people = graphene.List(lambda: Person)
#staticmethod
def mutate(root, args, context, info):
people = [Person.objects.create(name=person.name, age=person.age) for person in args.get('people')]
return CreatePeople(people=people)
Make your mutation input a list and return a list of created people. Something like this:
class CreatePerson(graphene.Mutation):
class Input:
name = graphene.List(graphene.String)
ok = graphene.Boolean()
people = graphene.List(Person)
#staticmethod
def mutate(root, args, context, info):
people = [Person(name=name) for name in args.get('name)]
ok = True
return CreatePerson(people=people, ok=ok)
Receive a list of input, create all instances and return them all
The model node/type should be like-
class UserType(DjangoObjectType):
class Meta:
model = User
interfaces = (CustomGrapheneNode, )
filter_fields = {}
only_fields = (
'name',
'email'
)
Define Input fields
class UserInput(graphene.InputObjectType):
name = graphene.String(required=True)
password = graphene.String(required=True)
Mutation class
class CreateUser(graphene.Mutation):
users = graphene.List(UserType)
class Input:
data = graphene.List(UserInput)
Output = graphene.List(UserType)
def mutate(self, info, data):
users = []
for item in data:
user = User.objects.create(name=data['name'],
password=data['password'])
users.append(user)
return users
make this mutation callable by main schema
class Mutation():
create_user = CreateUser.Field()
the Mutation Query view will be as -
mutation{
createUser(data:[{name:"john", password:"1234"},
{name:"john", password:"1234"}]) {
user{
name
}
}
}

Get post data from CustomField in django rest framework

To make it short:
I have a serializer (django rest framework) that has two custom fields which do not directly correspond to a field of my model and also have a different name. The to_internal_value() method (probably) works, but I don't know how to access the post data of these fields.
And in case you need more details on my case:
I have a django model that looks like this:
class Requirement(models.Model):
job = models.ForeignKey('Job', related_name = 'requirements')
description = models.CharField(max_length = 140)
is_must_have = models.BooleanField() # otherwise is of type b
class Job(models.Model):
...
I want to serialize it in a manner that a job object will look like this:
{ "must_have": [must have requirements], "nice:to_have": [nice to have requirements] }
Therefore, I have custom fields in my serializer for jobs:
class JobSerializer(serializers.Serializer):
nice_to_have = NiceToHaveField(source = 'requirements', allow_null = True)
must_have = MustHaveField(source = 'requirements', allow_null = True)
The NiceToHaveField and the MustHaveField classes simpy override the to_representation() and the to_internal_value() methods, the to_representation also sorts the requirements after type.
But the validated_data in JobSerializer.create never contain these cutom fields. I know the to_internal_value gets called and does its work, but the results are not accessable.
What is the way to solve this?
I found a solution I don't like, there is probably a better way to do this. Anyways, the data is available in the view.request.data. So I used the perform_create hook like this:
def perform_create(self, serializer):
nice_to_have = None
must_have = None
if 'nice_to_have' in self.request.data and self.request.data['nice_to_have'] != None:
field = NiceToHaveField()
nice_to_have = field.to_internal_value(self.request.data['nice_to_have'])
if 'must_have' in self.request.data and self.request.data['must_have'] != None:
field = MustHaveField()
must_have = field.to_internal_value(self.request.data['must_have'])
serializer.save(owner = self.request.user, nice_to_have = nice_to_have, must_have = must_have)

Array of annotations as parameter to an annotation, in Scala

There are plenty of questions about passing an array as a parameter to an annotation, this is not a dupe of those.
I would like to use a Java-land annotation that takes an array of annotations as a parameter, e.g.
#ManagedOperation
#ManagedOperationParameters({
#ManagedOperationParameter(name="start"),
#ManagedOperationParameter(name="end")
})
def stuff(start: String, end: String): Unit = ???
But this is not valid syntax in Scala, nor is
#ManagedOperation
#ManagedOperationParameters(Array(
#ManagedOperationParameter(name="start"),
#ManagedOperationParameter(name="end")
))
def stuff(start: String, end: String): Unit = ???
so what is the correct way to do this, if it is even possible?
BTW, I even checked all of github to see if any Scala devs are using this (Spring JMX) annotation.
In scala the inner annotation should be used as regular type:
#JsonTypeInfo(
use = JsonTypeInfo.Id.NAME,
include = JsonTypeInfo.As.PROPERTY,
property = "moduleType",
defaultImpl = classOf[PuppetModule]
)
#JsonSubTypes(Array(
new Type(value = classOf[PuppetModule], name = "puppet"),
new Type(value = classOf[PluginModule], name = "plugin")
))
trait Module {
val moduleType: String = if (this.isInstanceOf[PuppetModule]) "puppet" else "plugin"
val nodes: List[String] = List[String]()
}

Resources