graphql-python / graphene-django

Build powerful, efficient, and flexible GraphQL APIs with seamless Django integration.
http://docs.graphene-python.org/projects/django/en/latest/
MIT License
4.3k stars 769 forks source link

Add a feature to be able to add additional arguments in DjangoModelFormMutation and DjangoFormMutation #1110

Open MamoonAhmad opened 3 years ago

MamoonAhmad commented 3 years ago

Describe the solution you'd like DjangoModelFormMutation only reads forms fields. But I dont have the option to override a form field to change its type. Sometimes a user may have a complex object stored in database and he/she cleans and re-creates the object on retrieval. GraphQL has the ability to predefine the types and create, send or receive complex objects. It would be a good feature to override or add additional field in the inputs.

Describe alternatives you've considered Django forms does not support lots of different data types which GraphQL does. So as a backend developer, I am limited.

zbyte64 commented 3 years ago

How would the custom fields work with the internal form logic of validating and saving? Currently the form based mutations punt these operations to the form itself, if we're adding additional GraphQL fields then the mutation would need to treat those differently for them to work.

tcleonard commented 3 years ago

In this case it would probably make more sense to use a traditional mutation and set the arguments yourself in my opinion.

MamoonAhmad commented 3 years ago

@tcleonard The reason we use ModelFormMutation is to be able to not write all the inputs of a model. Re-writing all the model fields is pretty tedious. Also, it is prone to error. If we change model, we might have to change the inputs again.

MamoonAhmad commented 3 years ago

@zbyte64 What I mean is that if we have a JSON stored in database of a particular type. We should be able to get this input in the form of actual object type which is stored. Form does not support complex data types hence reading form fields cannot emit a correct data type. While it is true, that form validation can take care of complex objects in its clean method. But what I am suggesting is to put extra data validation layer as Graphql is capable of that.

MamoonAhmad commented 3 years ago

@zbyte64 @tcleonard This is a code sample which I am using locally. I have implemented a modified version of DjangoModelFormMutation.

class PurchaseArguments(ModifiedDjangoModelFormMutation):
    class Meta:
        abstract = True
    class Arguments:
        purchasable_items = graphene.Field(graphene.List(of_type=PurchasableItemsInput), required=True)

    def clean(self, **input):
        utils.from_global_id_multiple(["customer", "store"], input)
        for item in input.get("purchasable_items"):
            utils.from_global_id_multiple(["purchasable_item"], item)

        return input

class AddPurchase(PurchaseArguments):
    class Meta:
        form_class = forms.AddPurchase
        exclude_fields=["id"]

In class PurchaseArguments there is an Arguments class. ModifiedDjangoModelFormMutation reads Arguments class' fields and overrides the fields or adds additional fields (depends on the use case).

clean method in PurchaseArguments in overrode method of ModifiedDjangoModelFormMutation. Intention of this methods is to clean input arguments before being sent to the form. This helps also convert the base64 Graphql IDs before sent to the form.

rossm6 commented 3 years ago

I think this should be added to the library.

Django offers the option to override the fields on a model form so django graphene should support this as well.

# plain old django

class SomeModelForm(forms.ModelForm):
  class Meta:
      model = SomeModel
      fields = ('some_field',)
  some_field = forms.CharField()

My case which led me here is wanting to use a custom date scalar. A modal form with a date field will use the built in date scalar which wants input of form yyyy-mm-dd.