Package: django-simple-graphql
django-simple-graphqlA stupid simple GraphQL setup for DjangoThis project is still a WIP and will receive breaking changesTODOSupport mutationsSupport subscriptionsAn easy default for authenticationAccount for reverse-relations automaticallyHandle django-graphene issue with relations ponting to non-pk fields and ID encodingConfigurabilityCustom set of node interfaces (currently relay.Node)Custom relation connection handler (currently DjangoFilterConnectionField)Custom node/query/mutation/subscription builder functionsCustom schema member namingCustom searchEnable/disable search globallyEnable/disable ordering globallyGlobal default ordering optionsInjection of GraphQL ID property to models, configurable name and/or disableExamplesMore lax version pinning (Min python 3.5 or higher)Test suite against multiple version configurationsProper readmeBetter type definitionsGraphQL schema docstring generationValidation checks when building the schema to prevent blatantly incorrect configFor example, a field in search fields that doesn't exist or isn't supportedPerhaps a way to auto-render the schema for github diffs?A way to easily include extra queries for models (e.g. with different filters)Require either field exclusions or inclusions to be explicitly definedBuild a namespace package instead of a normal one (use "simple_graphql" as namespace root)Don't be as tightly coupled with graphenee.g. support tohttps://github.com/strawberry-graphql/strawberrywould be niceAutomatic CRUD operationsSupport more complex ordering options (as well as explicit naming of ordering)Run tests for code included in documentationSupport for permissionsQuery cost analysis / rate limitingConsider supporting an alternative approach where registration decorator
could be applied to a GraphQL config object instead of the model classAllow the register decorator be used with or without function call. Possibly
also allow it's use as a non-decorator registering function.Add support for using the schema builder if there's need to combine with an
existing graphene schema declaration.Features (already supported)TODO: Improve the documentationEnable GraphQL queries for Django models with a decoratorBy default, includes agetModelNameandlistModelNamequeriesConfigure by adding aGraphQLmeta class to the model classAlternatively supply a configuration class to the decoratorSupported configuration optionsfilters: Adjango-filtercompatible set of filters supported on the
model's QuerySet. List or a Dictionary.exclude_fields: A list of field names to exclude from the schemasearch_fields: A list of fields to perform search onordering_fields: A list of fields that can be used to order resultsdefault_ordering: What ordering to use if none was specifiedAdds agraphql_node_namefield to model classesAdds agraphql_idproperty to models, which can be used to retrieve the
Global ID of a model instance.UsageSetupSteps 1-3 are setup forgraphene-django.
Seehttps://docs.graphene-python.org/projects/django/en/latest/installation/for
more details.If you are already usinggraphene-django, you can skip to step 4.Addgraphene-djangoto yourINSTALLED_APPS:INSTALLED_APPS=[# ..."django.contrib.staticfiles",# Required for GraphiQL"graphene_django",]Add a GraphQL endpoint to the URL config:fromdjango.urlsimportpathfromdjango.views.decorators.csrfimportcsrf_exemptfromgraphene_django.viewsimportGraphQLViewurlpatterns=[# ...path("graphql",csrf_exempt(GraphQLView.as_view(graphiql=True))),]Create a schema file (e.g.schema.py) and configure it to Graphene:# settings.pyGRAPHENE={"SCHEMA":"myapp.shcema.schema",}Declare the schema in your schema file# schema.pyfromsimple_graphql.djangoimportSchemaschema=Schema()Default queriesBy default, all model classes registered to the schema will get a query for
fetching a single object by ID as well as a list query.For the sake of an example, let's say we have the following model declaration:fromdjango.dbimportmodelsfrommyapp.schemaimportschema@schema.graphql_model()classPerson(models.Model):first_name=models.TextField()last_name=models.TextField()Thegraphql_modeldecorator will add the model to our GraphQL schema builder,
which will build it into the following schema (relay schema omitted):typePersonimplementsNode{id:ID!lastName:String!firstName:String!}typeQuery{getPerson(id:ID!):PersonlistPerson(after:String,before:String,first:Int,last:Int,offset:Int):PersonConnection}For a more complete example of the generated schema, seeexample/schema.graphqlSearchTODOExamplesRegistering modelsThere's two ways models can be added to the schemaWith a class decoratorfromdjango.dbimportmodelsfrommyapp.schemaimportschema@schema.graphql_model()classPerson(models.Model):first_name=models.TextField()last_name=models.TextField()With a function callfromdjango.contrib.authimportget_user_modelfrommyapp.schemaimportschemaUser=get_user_model()schema.register_model(User)Configuring modelsModel specific schemas can be configured either with a metaclass or passed in
as a parameter. A base configuration also is present regardless of custom
declarations.If multiple configurations are present, they will be merged in the following
precedence:Configuration supplied via parametersMetaclass based configurationDefault configurationWhere lower number means higher priority.Metaclass configurationfromdjango.dbimportmodelsfrommyapp.schemaimportschema@schema.graphql_model()classPerson(models.Model):first_name=models.TextField()last_name=models.TextField()credit_card_number=models.TextField()parent=models.ForeignKey("self",on_delete=models.SET_NULL)classGraphQL:exclude_fields=["credit_card_number"]ordering_fields=["first_name","last_name"]default_ordering=["first_name"]search_fields=["first_name","last_name"]filters=["parent"]@staticmethoddefget_queryset(queryset:QuerySet["Person"],info:Any):ifinfo.context.user.is_superuser:returnquerysetreturnqueryset.none()Parameter configuration (with a class)fromdjango.dbimportmodelsfrommyapp.schemaimportschemaclassPersonGraphQLConfig:exclude_fields=["credit_card_number"]ordering_fields=["first_name","last_name"]default_ordering=["first_name"]search_fields=["first_name","last_name"]filters=["parent"]@schema.graphql_model(PersonGraphQLConfig)classPerson(models.Model):first_name=models.TextField()last_name=models.TextField()credit_card_number=models.TextField()parent=models.ForeignKey("self",on_delete=models.SET_NULL)Parameter configuration (with a config object)fromdjango.dbimportmodelsfromsimple_graphql.djangoimportModelSchemaConfigfrommyapp.schemaimportschema@schema.graphql_model(ModelSchemaConfig(exclude_fields=["credit_card_number"],ordering_fields=["first_name","last_name"],default_ordering=["first_name"],search_fields=["first_name","last_name"],filters=["parent"],))classPerson(models.Model):first_name=models.TextField()last_name=models.TextField()credit_card_number=models.TextField()parent=models.ForeignKey("self",on_delete=models.SET_NULL)Parameter configuration (function variant)fromdjango.contrib.authimportget_user_modelfromsimple_graphql.djangoimportModelSchemaConfigfrommyapp.schemaimportschemaUser=get_user_model()# Could also use a class here just like with the decoratorschema.register_model(User,ModelSchemaConfig(exclude_fields=["password"],))