7

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?

Quy Tang
  • 3,929
  • 1
  • 31
  • 45
  • 1
    FYI you can post your solution as an answer and accept it so people coming after you can easily see the final solution. – Jan Hančič May 20 '17 at 10:08

4 Answers4

9

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
  }
}
marktani
  • 7,578
  • 6
  • 37
  • 60
5

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)
Quy Tang
  • 3,929
  • 1
  • 31
  • 45
4

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)
Jan Hančič
  • 53,269
  • 16
  • 95
  • 99
  • great! but how can I deal with more than one field. E.g. name, address and age for the person? – Quy Tang May 19 '17 at 14:02
  • 2
    You can have complex input types, see the docs: http://docs.graphene-python.org/en/latest/types/mutations/ – Jan Hančič May 19 '17 at 14:13
  • Hi Jan, I use the InputObject and it worked but the data was not saved to the db. Would you mind helping on this. Thank you very much! – Quy Tang May 20 '17 at 03:14
4

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
        }
    }    
}
hirok biswas
  • 173
  • 1
  • 9
  • 1
    good solution. Just to add you could use the bulk_create() method there in the mutate() function as described in the docs: https://docs.djangoproject.com/en/3.2/ref/models/querysets/ – Rafael Santos Jul 16 '21 at 15:16
  • 1
    in case someone else tries this answer and you run into error, in the mutate function just change for item in data: user = User.objects.create(name=data['name'], password=data['password']) to instead: for item in data: user = User.objects.create(name=item['name'], password=item['password']) – Rafael Santos Jul 16 '21 at 15:48