Currently it's possible to map Django models to ObjectTypes using DjangoNode. I think it would be nice to have a similar feature that allows mapping forms to Mutation with a DjangoMutation class.
This would provide several great improvements:
Input classes anymore.form.errors to info.context.errors (It took a while until I figured out how to do that) on it's own.In the simple case you'd only have to define the outputs and a method that takes the validated data and returns an instance of the mutation class. I believe that even that would be unnecessary, if you're working with ModelForms. In that case a default method could just save the form and return the model instance wrapped in the corresponding DjangoNode.
Code that gets us some of the way to such a class already appears to exist, which was written for the django-filter integration.
I'm not that familiar with the code base itself but I have read quite a bit of it and I' think it might be able to implement this. I'm interested to know what you think of it and whether this has a chance to be accepted.
Hi @DasIch,
I think it's a great proposal!
Should be good to start a discussion about how we want to use it!
I was thinking of something like:
class ArticleInput(DjangoInputObjectType):
class Meta:
form = ArticleForm
I like mapping form.errors to the context. I think would be good if is done explicitly.
Thoughts?
Hi! Here is my proof of concept code to map DRF serializers to mutations: https://gist.github.com/gcheshkov/555b3e300b45f451b5b0fe79c73531ae
@gcheshkov thanks for the gist. I noticed you're importing from .types import ErrorType. Could you post the code to that too?
@stefanfoulis ErrorType is simple graphene object type for representing errors:
class ErrorType(graphene.ObjectType):
field = graphene.String()
message = graphene.String()
However now I took different approach to error handling. Just raising ValidationError in mutation handler and adding error messages to errors object in overridden GraphQLView.format_error method:
def format_error(error):
data = {
'message': str(error),
}
if isinstance(error, GraphQLLocatedError):
data.update(format_graphql_error(error))
if isinstance(error.original_error, Exception):
error = error.original_error
else:
return data
if isinstance(error, APIException):
if isinstance(error, ValidationError):
data.update({
'message': _('Validation error'),
'code': 'validation_error',
'fields': error.detail
})
else:
if getattr(error, 'error_code', None):
data['code'] = error.error_code
if getattr(error, 'extra', None):
data.update(error.extra)
elif isinstance(error, DjangoPermissionDenied):
data.update({
'message': _('Permission denied'),
'code': 'permission_denied'
})
elif isinstance(error, GraphQLError):
pass
elif isinstance(error, HttpError):
pass
else:
data['code'] = 'unhandled_exception'
if not settings.DEBUG:
data['message'] = _('Server error')
else:
data['message'] = '{}: {}'.format(error.__class__.__name__, error)
data['traceback'] = itertools.chain(
*[[l for l in ll.split('\n') if l.strip() != '']
for ll in traceback.format_exception(
error.__class__, error, error.__traceback__)])
return data
@gcheshkov thanks. that helped me a lot :-)
Hi what is the status on this?
I need something like a UserInputType for a IntroduceUser mutation and i don't want to manually map all the fields of the Django User model.
I would like if there would be a DjangoInputObjectType that could be created similar to the DjangoObjectType. Passing it through Django Forms is a brilliant solution to handling field validation, but being able to bypass validation would be appreciated for bulk data imports from a trusted system.
i can see form.py and form_convert.py in graphene-django , but never found any how to use.
Django: Map Form to Mutation how to use?
@fangaofeng this is not implemented yet. I'm working on something similar for django rest framework's serialisers in https://github.com/graphql-python/graphene-django/pull/186
I'm happy to do the same for the Forms, but right now I don't have much time, and I'd like to finish the other PR first :)
Hi @DasIch . We're currently going through old issues that appear to have gone stale (ie. not updated in about the last 6 months) to try and clean up the issue tracker. If this is still important to you please comment and we'll re-open this.
Thanks!
@jkimbo this feature request is still valid if it is not implemented yet. Such a future would be very helpful for projects migrating from an existing Django infrastructure.
@lig could you open an issue on graphene-django then since that is where we track any issues with the Django integration
Just as a reference for who will implement this feature in the future, I found something that seems could help in another OS project: https://github.com/mirumee/saleor/blob/99d45583985eb64e62966b3411bee54ba5052b1a/saleor/dashboard/graphql/core/mutations.py
I'm too new to graphQL and I don't have the skills to take this task but I hope this serves as an inspiration to someone.
@jkimbo sorry about commenting here, I didn't find this topic in graphene-django issues.
Most helpful comment
Hi what is the status on this?
I need something like a UserInputType for a IntroduceUser mutation and i don't want to manually map all the fields of the Django User model.
I would like if there would be a DjangoInputObjectType that could be created similar to the DjangoObjectType. Passing it through Django Forms is a brilliant solution to handling field validation, but being able to bypass validation would be appreciated for bulk data imports from a trusted system.