Package: django-graphene-framework
IntroductionDGF is a framework for streamlining the writting process using django and graphene.DisclaimerThis package was initally created for personal project, so it may lack general features you need or have unnecesarry features that you don't need. If you find any of these feel free to leave a issue ongithubInstalationThe package can be found on pypi'pip install django-graphene-framework'DependenciesThis package requires you to installgrapheneanddjango. If installing using pip the dependencies will be installed automaticallypip install graphene djangoBasicsDGF allows you to give easy acces to your models through graphql.Let's assume we have a modelProfile# models.pyfromdjango.db.modelsimportModel,CharFieldclassProfile(Model):first_name=CharField(max_lenght=20)last_name=CharField(max_lenght=20)We can easily transform it to graphql-accessable model by creating a schema# schema.pyfromDGFimportSchemafrom.modelsimportProfileclassProfileSchema(Schema):classMeta:model=ProfileWe specify the information inMetaclass. Themodelfield determines of which model is the schema of.After that we have to register the schema, so it can be transformed info graphene's schemaWe create a combiner and the register the schema# schema.pyfromDGFimportSchema,Combinerfrom.modelsimportProfileclassProfileSchema(Schema):classMeta:model=Profilecombiner=Combiner()combiner.register(ProfileSchema)schema=combiner.to_schema()Theschemacan be used like any other graphene schema.!!! DGF has not built-in endpoint for graphql as of now !!!RequestsThe schema will generatequeryfor the model andadd,changeanddeletemutations.Filter parametersare in form of(lowercase) _<Name of the field>. Relation fields are excluded.Value parameteresare in form of(lowercase) <Name of the field>.
Autofields are excluded. Relations can be provided using ids.Return valuesare in form of(lowercase) <Name of the field>.QueryThe name of the query will the<Name of your model>Query. It returns chosen data about the adequate entries.{ProfileQuery(_id:1){idfirst_namelast_name}}# Will get information about every profile with id = 1MutationsThe name of mutation will be<Name of your Model>{Add,Change,Delete}depending of the type of mutation you want to use.Addmutation can getvalue parametersfor the new database entry. It returns chosed data about the added entry.mutation{ProfileAdd(first_name:"Tom"){idfirst_name}}# Will add new profile with first_name = "Tom" and return it's id and first_nameChangemutation can getvalue parametersfor the changed database entry as well asfilter paramtersfor which entries to change. It returns chosen data about the changed entries.mutation {
    ProfileChange(_first_name:"Tom", last_name:"Smith"){
        first_name
        last_name
    }
}

# Will change last_name to "Smith" of every profile with name "Tom" and then return first_name and last_name of these profiles.Deletemutation can getfilter paramteresfor which entries to delete. It returns ids of the deleted entries (will return chosen data in future versions).mutation {
    ProfileDelete(_last_name:"Smith")
}

# Will delete every entry with last_name = "Smith" and return the ids of these entries.
# Note the lack of {}Custom request handlingYou can specify which requests should be possible by overridingallowed_requests.fromDGFimportSchema,QUERY,ADDfrom.modelsimportProfileallowed_requests=[QUERY,ADD]classProfileSchema(Schema):classMeta:model=ProfileYou can specify which fields should be accessable by addingfieldsfield inMetaclass of the schema.# schema.pyfromDGFimportSchemafrom.modelsimportProfileclassProfileSchema(Schema):classMeta:model=Profilefields=['first_name','id']Iffieldsis not defined, all fields will be added.You can also add your own fields to the schema.# schema.pyfromgrapheneimportIntfromDGFimportSchema,Fieldfrom.modelsimportProfileclassProfileSchema(Schema):age=Field(name='age',field=Int())# The name is requiredclassMeta:model=Profilefields=['first_name','id','age']Iffieldsis not defined, all custom fields will be added. Custom fields will override fields from the model with the same name.Custom request logicCustom fields have to be handled by custom request logic. To add custom request logic you can override a method in the schema.The methods accepts parameters:schema- to which schema this method refersmodel- to which model this method refersdata- data from the previous link in the chain (for more information readPipeline)raw_data- the raw, unprocessed requestparams- additional data (likeschema,model,raw_data,typeand custom data added by thePipelinemodules)FetchFetch method get the data from the database. Name of the fetch method is in form offetch_{query,add,change,delete}. Fetch should return the model / list of models.ExecuteFetch fucntion execute the request on the provided data. Name of the execute method is in form ofexecute_{query,add,change,delete}. Execute should return the same type as the request's type (seeQueryandMutations)PipelineDGF has built-in pipeline that let's you customize the behaviour on every step. The default pipeline is composed of:AuthLink- tries to authenticate the user based on the provided credentials using authenticatosRequestPermissionLink- checks if the user has permission to make this requestFetchLink- fetches the data from the database about the modelObjectPermissionLink- filters the data based on the permission the user hasExecuteLink- executes the request (applies only toChangeandDeletemutations by default)First link in the pipeline get's the data from graphene, every other gets the data from previous one.You can change the pipeline by settingDGF_PIPELINEin the settings.# settings.pyDGF_PIPELINE=['DGF.builtins.FetchPipeline','DGF.builtins.ExecutePipeline']# The bare minimum for everything to work out of the boxAuth LinkAddes new paramuserthat represents the authenticated user (uses the same model as django). The authentication is done usingAuthenticators. If it's not possible to authenticate user, setsusertoAnonymousUser.Request Permission LinkUsesPermissionsto check if the user is suppose to use this request. If not, throwsUnauthorized.Fetch LinkCalls fetch method on the schema (seeFetch).Object Permission LinkUsesPermissionsto filter the data.Execute LinkCalls execute method on the schema (seeExecute)Custom linkYou can create your own link by overriding theBaseLinkclass and theprocessmethod inside.# links.pyfromDGFimportBaseLinkclassCustomLink(BaseLink):defprocess(self,data):# Your custom logicreturndataYou can get and set additional parameters by usingself.paramsorself.context.AuthAuthenticatorsAuthenticators allow you to authenticate the user without writting custom backend. Parameters for the authentication can be both in body or headers. By defaultModel Authenticatoris used.Model AuthenticatorModel authenticator is used for authenticating the user using username and password. It uses Django's default backend.Backend AuthenticatorBase class for authenticator, that use existing backends. You need to defineargsfield with names of all paramateres needed for authentication and it will call django'sauthenticateto try to authenticate the userclassModelAuthenticator(BackendAuthenticator):args=['username','password']Bearer AuthenticatorBase class for authenticator, that user the Bearer token. You need to override theauthenticate_tokenmethod, which should return the user.fromdjango.confimportsettingsfromjwtimportdecodefromdjango.contrib.authimportget_user_modelfromDGF.builtins.authenticatorsimportBearerAuthenticatorclassJWTAuthenticator(BearerAuthenticator):@classmethoddefauthenticate_token(cls,token):ifnottoken:returnNonetry:decoded=decode(token,settings.SECRET_KEY,algorithms=['HS256'])returnget_user_model().objects.get(pk=decoded['sub'])except:returnNoneCustom AuthenticatorYou can write custom authenticator by overridingBaseAuthenticatorandauthenticatemethod inside as well asargsfield.# authenticators.pyfromdjango.contrib.authimportget_user_modelimportDGF.AuthenticatorclassCustomAuthenticator(BaseAuthenticator):args=['username']@classmethoddefauthenticate(cls,username,**kwargs):try:returnget_user_model().objects.get(username=username)except:returnNonePermissionsPermissions allow you to limit the user im terms of requests and particular entries.You can set permission for each schema by overriding thepermissionsfield.# schema.pyfromDGFimportSchemafromDGF.builtinsimportReadOnlyPermissionfrom.modelsimportProfileclassProfileSchema(Schema):classMeta:model=Profilepermissions=[ReadOnlyPermission]Read Only PermissionAllows onlyQueryrequests.Custom permissionsYou can write your own permissions by overridingBasePermissionsclass as well as overriding one or more of the methods:has_object_permission- forObject Permission Linkhas_request_permission- forRequest Permission LinkBoth methods can acceptschema,model,dataandparams.# permission.pyfromDGFimportBasePermissionclassIsAuthenticated(BasePermission):@staticmethoddefhas_request_permission(params,**kwargs):returnparams['user'].is_authenticatedclassIsOwner(BasePermission):@staticmethoddefhas_object_permission(schema,data,params,**kwargs):returngetattr(data,'owner',None)==params['user']