Repository: graphql-python/graphene-django

Issue:
OrderingFilter should expose camelCase fields
Graphene Django's [documentation on ordering](https://docs.graphene-python.org/projects/django/en/latest/filtering/#ordering) exposes the `orderBy` filter:

```py
query {
  group(id: "xxx") {
    users(orderBy: "-created_at") {
      createdAt
    }
  }
}
```

Since the `created_at` Django field is actually exposed in GraphQL as `createdAt`,
shouldn't the ordering filter follow a consistent style by default?

```py
query {
  group(id: "xxx") {
    users(orderBy: "-createdAt") {
      createdAt
    }
  }
}
```

The workaround I've found is to do:

```py
order_by = OrderingFilter(
  fields = (
    ('created_at', 'createdAt')
  )
)
```

but the casing conversion probably be handled by the framework itself, to avoid the unnecessary noise / maintenance bloat.


Discussion:

Resolving patch:
diff --git a/graphene_django/filter/fields.py b/graphene_django/filter/fields.py
--- a/graphene_django/filter/fields.py
+++ b/graphene_django/filter/fields.py
@@ -3,6 +3,7 @@
 
 from django.core.exceptions import ValidationError
 from graphene.types.argument import to_arguments
+from graphene.utils.str_converters import to_snake_case
 from ..fields import DjangoConnectionField
 from .utils import get_filtering_args_from_filterset, get_filterset_class
 
@@ -56,12 +57,21 @@ def filtering_args(self):
     def resolve_queryset(
         cls, connection, iterable, info, args, filtering_args, filterset_class
     ):
+        def filter_kwargs():
+            kwargs = {}
+            for k, v in args.items():
+                if k in filtering_args:
+                    if k == "order_by":
+                        v = to_snake_case(v)
+                    kwargs[k] = v
+            return kwargs
+
         qs = super(DjangoFilterConnectionField, cls).resolve_queryset(
             connection, iterable, info, args
         )
-        filter_kwargs = {k: v for k, v in args.items() if k in filtering_args}
+
         filterset = filterset_class(
-            data=filter_kwargs, queryset=qs, request=info.context
+            data=filter_kwargs(), queryset=qs, request=info.context
         )
         if filterset.form.is_valid():
             return filterset.qs


Test patch:
diff --git a/graphene_django/filter/tests/filters.py b/graphene_django/filter/tests/filters.py
--- a/graphene_django/filter/tests/filters.py
+++ b/graphene_django/filter/tests/filters.py
@@ -21,7 +21,7 @@ class Meta:
         model = Reporter
         fields = ["first_name", "last_name", "email", "pets"]
 
-    order_by = OrderingFilter(fields=("pub_date",))
+    order_by = OrderingFilter(fields=("first_name",))
 
 
 class PetFilter(django_filters.FilterSet):
diff --git a/graphene_django/filter/tests/test_fields.py b/graphene_django/filter/tests/test_fields.py
--- a/graphene_django/filter/tests/test_fields.py
+++ b/graphene_django/filter/tests/test_fields.py
@@ -713,6 +713,73 @@ def resolve_all_reporters(self, info, **args):
     assert result.data == expected
 
 
+def test_order_by():
+    class ReporterType(DjangoObjectType):
+        class Meta:
+            model = Reporter
+            interfaces = (Node,)
+
+    class Query(ObjectType):
+        all_reporters = DjangoFilterConnectionField(
+            ReporterType, filterset_class=ReporterFilter
+        )
+
+    Reporter.objects.create(first_name="b")
+    Reporter.objects.create(first_name="a")
+
+    schema = Schema(query=Query)
+    query = """
+        query NodeFilteringQuery {
+            allReporters(orderBy: "-firstName") {
+                edges {
+                    node {
+                        firstName
+                    }
+                }
+            }
+        }
+    """
+    expected = {
+        "allReporters": {
+            "edges": [{"node": {"firstName": "b"}}, {"node": {"firstName": "a"}}]
+        }
+    }
+
+    result = schema.execute(query)
+    assert not result.errors
+    assert result.data == expected
+
+    query = """
+        query NodeFilteringQuery {
+            allReporters(orderBy: "-first_name") {
+                edges {
+                    node {
+                        firstName
+                    }
+                }
+            }
+        }
+    """
+
+    result = schema.execute(query)
+    assert not result.errors
+    assert result.data == expected
+
+    query = """
+        query NodeFilteringQuery {
+            allReporters(orderBy: "-firtsnaMe") {
+                edges {
+                    node {
+                        firstName
+                    }
+                }
+            }
+        }
+    """
+    result = schema.execute(query)
+    assert result.errors
+
+
 def test_order_by_is_perserved():
     class ReporterType(DjangoObjectType):
         class Meta: