lmcgartland / graphene-file-upload

Enhances Graphene Django GraphQL Server for intuitive file uploads via GraphQL mutations.
MIT License
286 stars 50 forks source link

Is it possible to use graphene.List(Upload) to upload multiple files? #14

Open emilt27 opened 6 years ago

emilt27 commented 6 years ago

The question in title ^^.

screen shot 2018-09-07 at 12 29 28 pm
emilt27 commented 6 years ago

I've figured out why it does not work. I have the following:

class AddItem(graphene.relay.ClientIDMutation):
    class Input:
        files = graphene.List(Upload)
        expires = graphene.Date(required=True)

When I try to execute this mutation with wrong expires value, it tries to return the error with serialized payloads. Here is a line where it tries to serialize: https://github.com/graphql-python/graphql-core/blob/master/graphql/execution/values.py#L73

marlonpatrick commented 4 years ago

Oops man, when solving the problem of the field "expires" the upload with multiple files is working well? I am evaluating this library. I wanted to know if it is stable considering that my application will use a lot of image uploads.

sreerajkksd commented 4 years ago

Do we have a solution for uploading multiple files together ?

sreerajkksd commented 4 years ago

I spend sometime on this and this is definitely working fine. I read https://medium.com/@dilipkumar/graphql-and-file-upload-using-react-and-node-js-c1d629e1b86b to understand the payload structure and just did what they asked me to do.

In summary, we have to put the following keys and values in form-data

operations:{"query": "mutation uploadFiles($files: [Upload]) {uploadFiles(files: $files) { success }", "variables": { "files": [null,null] }}
map:{ "0": ["variables.files.0"], "1": ["variables.files.1"]}

Additionally 0 key should contain the content of the first file and 1 should contain the content of the second file.

melvyn-apryl commented 2 years ago

Here's how to create a test for Django, combining all the bits of information from above + some figuring out:

# test_upload.py

import random

import pytest
from django.core.files.uploadedfile import SimpleUploadedFile

def get_bytes(size: int) -> bytes:
    return bytes(bytearray(random.getrandbits(8) for _ in range(size)))

UPLOAD_DOCUMENTS = """mutation uploadDocuments($documents: [Upload]!) {
 uploadDocuments(documents: $documents) {
    success
    } 
}"""

def test_upload():
    # Note the keys: variablename dot index_number
    documents = {
        "documents.0": SimpleUploadedFile(
            name="scanned contract.png",
            content=get_bytes(1024),
            content_type="image/png",
        ),
        "documents.1": SimpleUploadedFile(
            name="Invoice.pdf",
            content=get_bytes(2048),
            content_type="application/pdf",
        ),
    }

    response = file_graphql_query(
        UPLOAD_DOCUMENTS, files=documents, variables={"documents": [None, None]}
    )
    assert response.json()["data"]["uploadDocuments"]["success"] is True

# schema.py

class uploadDocuments(graphene.Mutation):
    success = graphene.Boolean()
    class Arguments:
        documents = graphene.NonNull(graphene.List(Upload))

    @classmethod
    def mutate(
        cls,
        root,
        info: td.ResolveInfo,
        documents: t.List[SimpleUploadedFile],
    ):
        if isinstance(documents[0], SimpleUploadedFile) and isinstance(
            documents[1], SimpleUploadedFile
        ):
            return cls(success=True)

        return cls(success=False)