Repository: tOgg1/graphene-django-cud (language: python)

Issue:
chore(docs): added example for `exclude_fields`
Closes #114 
Choices Field created via models.TextChoices(or its analogues) class
```
python version 3.10.3
django version 4.0.3
graphene-django from main branch latest commit by date of posting(f6ec0689c18929344c79ae363d2e3d5628fa4a2d)
graphene_django_cud version 0.10.0
```

I was trying to create a DjangoCreateMutation(actually it fails for any kind of mutation) with this model
```python
from django.db import models
from django.contrib.auth import get_user_model


User = get_user_model()


class Staff(models.Model):
    class StaffStatus(models.TextChoices):
        WORKING = 'working', 'Working'
        SUSPENDED = 'suspended', 'Suspended'
        FIRED = 'fired', 'Fired'

    first_name = models.CharField(max_length=64)
    middle_name = models.CharField(max_length=64)
    last_name = models.CharField(max_length=64)
    phone = models.CharField(max_length=32)
    email = models.CharField(max_length=256)
    position = models.CharField(max_length=64)
    address = models.CharField(max_length=512)
    status = models.CharField(max_length=16, choices=StaffStatus.choices, default=StaffStatus.WORKING)
    is_admin = models.BooleanField(default=False)

    user = models.OneToOneField(User, on_delete=models.SET_NULL, null=True, related_name='staff')

    def __str__(self):
        return f'{self.last_name} {self.first_name}({self.id})'
```
> I suppose most of the fields can be skipped except the one with choices which was created via class _(models.TextChoices) or its analogues in it.

And when I tried to run app it fails with message
```shell
File "lib\site-packages\graphene_django_cud\converter.py", line 116, in convert_django_field_with_choices     
    from_registry.kwargs['description'] = field.help_text
AttributeError: 'BlankValueField' object has no attribute 'kwargs'. Did you mean: 'args'?
```
Mutations and DateField issue in graphene-django-cud code
Environment info: Using Django 4.1, Python 3.8 and 0.10.0 of this library

I have a model with a date field:

```python
class MyModel:
    dob = models.DateField(null=True, blank=True, help_text="Date of birth")
```

I added this to a couple of mutations:

```python
class CreateMyModelMutation(DjangoCreateMutation):
    class Meta:
        model = MyModel
        login_required = True


class UpdateMyModelMutation(DjangoPatchMutation):
    class Meta:
        model = MyModel
        login_required = True
        only_fields = [..., "dob"]
```

When running any command (e.g. `makemigrations`, `test` or `runserver`) I receive the following error in my console:

```python
  File ".../lib/python3.8/site-packages/graphene/utils/subclass_with_meta.py", line 46, in __init_subclass__
    super_class.__init_subclass_with_meta__(**options)
  File ".../lib/python3.8/site-packages/graphene_django_cud/mutations/create.py", line 101, in __init_subclass_with_meta__
    model_fields = get_input_fields_for_model(
  File ".../lib/python3.8/site-packages/graphene_django_cud/util/model.py", line 154, in get_input_fields_for_model
    converted = convert_django_field_with_choices(
  File ".../lib/python3.8/site-packages/graphene_django_cud/converter.py", line 116, in convert_django_field_with_choices
    from_registry.kwargs['description'] = field.help_text
AttributeError: 'BlankValueField' object has no attribute 'kwargs'
```
Fix error 81, 105
Fix error #81, #105


Discussion / hints:

Fix patch:
diff --git a/.github/workflows/pre-commit.yml b/.github/workflows/pre-commit.yml
new file mode 100644
index 0000000..dac839b
--- /dev/null
+++ b/.github/workflows/pre-commit.yml
@@ -0,0 +1,16 @@
+name: pre-commit
+
+on:
+  pull_request:
+  push:
+    branches: [ develop, master ]
+
+jobs:
+  pre-commit:
+    runs-on: ubuntu-20.04
+    steps:
+    - uses: actions/checkout@v2
+    - uses: actions/setup-python@v2
+      with:
+        python-version: '3.8'
+    - uses: pre-commit/action@v2.0.3
diff --git a/.github/workflows/primary.yml b/.github/workflows/primary.yml
index 2bf89a8..0dcf9d0 100644
--- a/.github/workflows/primary.yml
+++ b/.github/workflows/primary.yml
@@ -10,39 +10,33 @@ on:
 jobs:
   test:
 
-    runs-on: ubuntu-18.04
+    runs-on: ubuntu-20.04
     strategy:
       matrix:
-        python-version: [3.6, 3.7, 3.8]
+        python-version: ["3.7", "3.8", "3.9", "3.10"]
+        poetry-version: ["1.3.1"]
 
     steps:
       - uses: actions/checkout@v2
-      - name: set up python ${{ matrix.python-version }}
-        uses: actions/setup-python@v2
+      - name: Run image
+        uses: abatilo/actions-poetry@v2.2.0
         with:
-          python-version: ${{ matrix.python-version }}
-      - name: Install Poetry
-        run: |
-          pip install poetry==1.1.4
-          poetry config virtualenvs.in-project true
-      - name: Cache pip
-        uses: actions/cache@v1
+          poetry-version: ${{ matrix.poetry-version }}
+
+      - name: Set up Python ${{ matrix.python-version }}
+        uses: actions/setup-python@v4
         with:
-          path: .venv
-          key: ${{ runner.os }}-${{ matrix.python-version }}-pip-${{ hashFiles('poetry.lock') }}
-          restore-keys: |
-            ${{ runner.os }}-${{ matrix.python-version}}-pip-
-            ${{ runner.os }}-${{ matrix.python-version}}-
-            ${{ runner.os }}-
+          python-version: ${{ matrix.python-version }}
+          cache: 'poetry'
       - name: Install dependencies
-        run: poetry install --no-interaction
+        run: poetry install
       - name: Test with coverage
         run: |
           make test-cov
   release:
     needs: test
     if: github.event_name == 'push' && startsWith(github.event.ref, 'refs/tags')
-    runs-on: ubuntu-18.04
+    runs-on: ubuntu-20.04
     env:
       TWINE_USERNAME: __token__
       TWINE_PASSWORD: ${{ secrets.PYPI_PASSWORD }}
@@ -51,7 +45,7 @@ jobs:
       - name: Set up Python
         uses: actions/setup-python@v2
         with:
-          python-version: 3.7
+          python-version: 3.9
       - name: Install dependencies
         run: |
           pip install twine
diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
new file mode 100644
index 0000000..55b10e2
--- /dev/null
+++ b/.pre-commit-config.yaml
@@ -0,0 +1,21 @@
+repos:
+-   repo: https://github.com/pre-commit/pre-commit-hooks
+    rev: v4.1.0
+    hooks:
+      - id: end-of-file-fixer
+      - id: trailing-whitespace
+-   repo: https://github.com/psf/black
+    rev: 22.3.0
+    hooks:
+    - id: black
+      language_version: python3.8
+      exclude: (migrations/|locale/|docs/)
+      args:
+        - --line-length=120
+-   repo: https://gitlab.com/pycqa/flake8
+    rev: 3.9.2
+    hooks:
+    - id: flake8
+      exclude: (migrations/|locale/|docs/)
+      args:
+        - --max-line-length=120
diff --git a/CHANGELOG.md b/CHANGELOG.md
index e918940..607f901 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,12 +1,25 @@
 # Changelog
 
+## Version 0.11.0
+
+* Fix graphene-django 3.x compatibility issues (thanks @sjdemartini, @wito-alex).
+* Improve documentation (thanks @sjdemartini, @Plebbimon).
+* Add `perform_delete` override to `DjangoDeleteMutation` (thanks @calummackervoy). This allows for better soft deletes.
+* Add `get_return_id` override to `DjangoBatchDeleteMutation`, enabling ID overwrites (thanks @rymanso).
+* Fix compatability issues with custom pks (thanks @NwawelAIroume).
+* Bump some package versions.
+* Some general project and file clean up.
+* Remove debug prints. Pardon all the mlogs.
+
 ## Version 0.10.0
+
 * Put `select_for_update` behind a new option `use_select_for_update`, which is enabled by default.
 * Rename `only_fields` -> `fields` and `exclude_fields` -> `exclude`. Alias the old names but add deprecation warnings.
 * Make the library graphene(-django) 3.x compatible.
 * Respect required_fields in Patch and BatchPatch mutations (thanks @mbuvarp).
 
 ## Version 0.9.1
+
 * Improve atomicity of patch/update-calls (thanks @keithhackbarth)
 * Improve documentation
 * Security-critical package updates
@@ -15,7 +28,7 @@
 * (BREAKING) Ensure inputs are sent to all after_mutate hooks.
 
 ## Version 0.8.1
-* (BREAKING) DjangoDeleteMutation now returns three id fields: deletedId, deletedRawId and deletedInputId. The default behaviour of deletedId is now to return a global id if the associated model type has a GlobalIDField for the "id" field. 
+* (BREAKING) DjangoDeleteMutation now returns three id fields: deletedId, deletedRawId and deletedInputId. The default behaviour of deletedId is now to return a global id if the associated model type has a GlobalIDField for the "id" field.
 
 ## Version 0.8.0
 * Add customisation of resolving IDs via the resolve_id(s) methods (@bjmc)
@@ -185,4 +198,3 @@ Initial release, add core and classes:
  * DjangoUpdateMutation
  * DjangoDeleteMutation
  * DjangoBatchDeleteMutation
- 
diff --git a/LICENSE.md b/LICENSE.md
index 1ddbb13..eb77a32 100644
--- a/LICENSE.md
+++ b/LICENSE.md
@@ -4,4 +4,4 @@ Permission is hereby granted, free of charge, to any person obtaining a copy of
 
 The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
\ No newline at end of file
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
diff --git a/Makefile b/Makefile
index c272b26..6105414 100644
--- a/Makefile
+++ b/Makefile
@@ -38,5 +38,3 @@ build:
 .PHONY: release
 release:
 	poetry run twine upload dist/*
-
-
diff --git a/README.md b/README.md
index f00cfe5..60fc9ad 100644
--- a/README.md
+++ b/README.md
@@ -52,7 +52,7 @@ class CreateUserMutation(DjangoCreateMutation):
 class Mutation(graphene.ObjectType):
     create_user = CreateUserMutation.Field()
 
-    
+
 class Query(graphene.ObjectType):
     user = graphene.Field(UserNode, id=graphene.String())
 
@@ -75,7 +75,7 @@ mutation {
             id
             name
             address
-        } 
+        }
     }
 }
 ```
diff --git a/docs/conf.py b/docs/conf.py
index fa9ac18..b879fd3 100644
--- a/docs/conf.py
+++ b/docs/conf.py
@@ -24,29 +24,27 @@
 
 from sphinx.highlighting import lexers
 
-project = 'graphene-django-cud'
-copyright = '2021, Tormod Haugland'
-author = 'Tormod Haugland'
+project = "graphene-django-cud"
+copyright = "2021, Tormod Haugland"
+author = "Tormod Haugland"
 
 # The full version, including alpha/beta/rc tags
-release = '0.10.0'
+release = "0.11.0"
 
 # -- General configuration ---------------------------------------------------
 
 # Add any Sphinx extension module names here, as strings. They can be
 # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
 # ones.
-extensions = [
-        "sphinx_rtd_theme"
-]
+extensions = ["sphinx_rtd_theme"]
 
 # Add any paths that contain templates here, relative to this directory.
-templates_path = ['_templates']
+templates_path = ["_templates"]
 
 # List of patterns, relative to source directory, that match files and
 # directories to ignore when looking for source files.
 # This pattern also affects html_static_path and html_extra_path.
-exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store']
+exclude_patterns = ["_build", "Thumbs.db", ".DS_Store"]
 
 
 # -- Options for HTML output -------------------------------------------------
@@ -54,14 +52,14 @@
 # The theme to use for HTML and HTML Help pages.  See the documentation for
 # a list of builtin themes.
 #
-html_theme = 'sphinx_rtd_theme'
+html_theme = "sphinx_rtd_theme"
 
 # Add any paths that contain custom static files (such as style sheets) here,
 # relative to this directory. They are copied after the builtin static files,
 # so a file named "default.css" will overwrite the builtin "default.css".
-html_static_path = ['_static']
+html_static_path = ["_static"]
 
-master_doc = 'index'
+master_doc = "index"
 
 # Add custom graphql lexer
 
@@ -80,24 +78,30 @@ class GraphqlLexer(RegexLexer):
     Lexer for GraphQL.
     """
 
-    name = 'GraphQL'
-    aliases = ['graphql', 'gql']
-    filenames = ['*.graphql', '*.gql']
-    mimetypes = ['application/graphql']
+    name = "GraphQL"
+    aliases = ["graphql", "gql"]
+    filenames = ["*.graphql", "*.gql"]
+    mimetypes = ["application/graphql"]
 
     tokens = {
-        'root': [
-            (r'#.*', Comment.Singline),
-            (r'\.\.\.', Operator),
+        "root": [
+            (r"#.*", Comment.Singline),
+            (r"\.\.\.", Operator),
             (r'"([^\\"]|\\")*"', String.Double),
-            (r'(-?0|-?[1-9][0-9]*)(\.[0-9]+[eE][+-]?[0-9]+|\.[0-9]+|[eE][+-]?[0-9]+)', Number.Float),
-            (r'(-?0|-?[1-9][0-9]*)', Number.Integer),
-            (r'\$+[_A-Za-z][_0-9A-Za-z]*', Name.Variable),
-            (r'[_A-Za-z][_0-9A-Za-z]+\s?:', Text),
-            (r'(type|query|fragment|mutation|@[a-z]+|on|true|false|null)\b', Keyword.Type),
-            (r'[!$():=@\[\]{|}]+?', Punctuation),
-            (r'[_A-Za-z][_0-9A-Za-z]*', Keyword),
-            (r'(\s|,)', Text),
+            (
+                r"(-?0|-?[1-9][0-9]*)(\.[0-9]+[eE][+-]?[0-9]+|\.[0-9]+|[eE][+-]?[0-9]+)",
+                Number.Float,
+            ),
+            (r"(-?0|-?[1-9][0-9]*)", Number.Integer),
+            (r"\$+[_A-Za-z][_0-9A-Za-z]*", Name.Variable),
+            (r"[_A-Za-z][_0-9A-Za-z]+\s?:", Text),
+            (
+                r"(type|query|fragment|mutation|@[a-z]+|on|true|false|null)\b",
+                Keyword.Type,
+            ),
+            (r"[!$():=@\[\]{|}]+?", Punctuation),
+            (r"[_A-Za-z][_0-9A-Za-z]*", Keyword),
+            (r"(\s|,)", Text),
         ]
     }
 
diff --git a/docs/guide/auto-context-fields.rst b/docs/guide/auto-context-fields.rst
index 9d6a45d..a6a2e5c 100644
--- a/docs/guide/auto-context-fields.rst
+++ b/docs/guide/auto-context-fields.rst
@@ -34,4 +34,3 @@ that auto context fields are automatically set as ``required=False``, to
 please Graphene. Finally note that if we add an explicit value to the
 ``createdBy`` field when calling the mutation, this value will override
 the auto context field.
-
diff --git a/docs/guide/custom-fields.rst b/docs/guide/custom-fields.rst
index 270512f..9542754 100644
--- a/docs/guide/custom-fields.rst
+++ b/docs/guide/custom-fields.rst
@@ -48,4 +48,3 @@ Running the below mutation will increase the bark count by one:
             barkCount
         }
     }
-
diff --git a/docs/guide/field-types.rst b/docs/guide/field-types.rst
index b45726e..d563e12 100644
--- a/docs/guide/field-types.rst
+++ b/docs/guide/field-types.rst
@@ -33,5 +33,3 @@ Django model field; then you must implement a :ref:`custom handler<custom_field_
         @classmethod
         def handle_tag(cls, value, *args, **kwargs):
             return "Dog-" + str(value)
-
-
diff --git a/docs/guide/included-and-excluded-fields.rst b/docs/guide/included-and-excluded-fields.rst
index 643bde9..b85aaaf 100644
--- a/docs/guide/included-and-excluded-fields.rst
+++ b/docs/guide/included-and-excluded-fields.rst
@@ -38,4 +38,4 @@ included, and let all others be excluded. This can be achieved with the ``only_f
 
 
 If both ``only_fields`` and ``exclude_fields`` are supplied, first the fields matching ``only_fields`` are extracted,
-and then the fields matching ``exclude_fields`` are removed from this list.
\ No newline at end of file
+and then the fields matching ``exclude_fields`` are removed from this list.
diff --git a/docs/guide/mutations.rst b/docs/guide/mutations.rst
index 8c2580e..dd62112 100644
--- a/docs/guide/mutations.rst
+++ b/docs/guide/mutations.rst
@@ -336,4 +336,3 @@ The mutation returns two fields for resolving:
             }
         }
     }
-
diff --git a/docs/guide/naming.rst b/docs/guide/naming.rst
index 53ffa3a..1970494 100644
--- a/docs/guide/naming.rst
+++ b/docs/guide/naming.rst
@@ -42,4 +42,4 @@ The two others can be customized by the following meta parameters:
 
 Given the existence of `GraphQL aliasing`_, the utility of the latter is questionable.
 
-.. _GraphQL aliasing: https://graphql.org/learn/queries/#aliases
\ No newline at end of file
+.. _GraphQL aliasing: https://graphql.org/learn/queries/#aliases
diff --git a/docs/guide/nested-fields.rst b/docs/guide/nested-fields.rst
index c7d3bbd..4b0b7df 100644
--- a/docs/guide/nested-fields.rst
+++ b/docs/guide/nested-fields.rst
@@ -153,7 +153,7 @@ Cat objects to be added by id.
 Many to many extras
 ~~~~~~~~~~~~~~~~~~~
 
-The ``many_to_one_extras`` field is a dictionary containing information
+The ``many_to_many_extras`` field is a dictionary containing information
 regarding how to handle many to many relations. Suppose we have the
 ``Cat`` model as above, and a ``Dog`` model like:
 
@@ -358,6 +358,29 @@ The name of the argument will be ``killEnemies`` instead of the default
 ``enemiesKill``. The name will be translated from snake\_case to
 camelCase as per usual.
 
+Excluding fields
+~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+By default, all fields are included in the input type. However, you can
+exclude fields by using the ``exclude_fields`` attribute:
+
+.. code:: python
+
+    class CreateDogMutation(DjangoCreateMutation):
+        class Meta:
+            model = Dog
+            many_to_many_extras = {
+                "enemies": {
+                    "exact": {
+                        "type": "CreateCatInput",
+                        "exclude_fields": ("name",),
+                    },
+                }
+            }
+
+This will exclude the ``name`` field from the input type.
+
+
 Deep nested arguments
 ~~~~~~~~~~~~~~~~~~~~~
 
diff --git a/docs/guide/optional-fields.rst b/docs/guide/optional-fields.rst
index a565125..611cfed 100644
--- a/docs/guide/optional-fields.rst
+++ b/docs/guide/optional-fields.rst
@@ -32,4 +32,3 @@ A field can explicitly be marked as optional or required with the meta-attribute
             model = User
             required_fields = ("first_name",)
             optional_fields = ("last_name",)
-
diff --git a/docs/ref/models/DjangoBatchDeleteMutation.rst b/docs/ref/models/DjangoBatchDeleteMutation.rst
index 7241a2e..9cb5c14 100644
--- a/docs/ref/models/DjangoBatchDeleteMutation.rst
+++ b/docs/ref/models/DjangoBatchDeleteMutation.rst
@@ -46,4 +46,3 @@ All meta arguments:
             deletionCount
         }
     }
-
diff --git a/docs/ref/models/DjangoFilterDeleteMutation.rst b/docs/ref/models/DjangoFilterDeleteMutation.rst
index 4ea0cbc..00aa15f 100644
--- a/docs/ref/models/DjangoFilterDeleteMutation.rst
+++ b/docs/ref/models/DjangoFilterDeleteMutation.rst
@@ -48,4 +48,3 @@ If there are multiple filters, these will be combined with
             deletionCount
         }
     }
-
diff --git a/docs/ref/models/DjangoFilterUpdateMutation.rst b/docs/ref/models/DjangoFilterUpdateMutation.rst
index cf26912..d00ffa7 100644
--- a/docs/ref/models/DjangoFilterUpdateMutation.rst
+++ b/docs/ref/models/DjangoFilterUpdateMutation.rst
@@ -65,4 +65,3 @@ If there are multiple filters, these will be combined with
             }
         }
     }
-
diff --git a/docs/ref/models/DjangoUpdateMutation.rst b/docs/ref/models/DjangoUpdateMutation.rst
index 95d316d..05ca301 100644
--- a/docs/ref/models/DjangoUpdateMutation.rst
+++ b/docs/ref/models/DjangoUpdateMutation.rst
@@ -71,5 +71,3 @@ All meta arguments:
             }
         }
     }
-
-
diff --git a/graphene_django_cud/consts.py b/graphene_django_cud/consts.py
index 08201e1..f704f7a 100644
--- a/graphene_django_cud/consts.py
+++ b/graphene_django_cud/consts.py
@@ -1,4 +1,3 @@
-
 OPERATION_UPDATE = "update"
 OPERATION_DELETE = "delete"
 OPERATION_CREATE = "create"
diff --git a/graphene_django_cud/converter.py b/graphene_django_cud/converter.py
index b3af9b4..ed5df0b 100644
--- a/graphene_django_cud/converter.py
+++ b/graphene_django_cud/converter.py
@@ -8,7 +8,9 @@
 #
 # From the last point, users of this module are expected to discard any field returning None
 from functools import singledispatch
+from typing import Union
 
+import graphql
 from django.db import models
 from django.db.models import FileField, ImageField
 from django.utils.encoding import force_str
@@ -29,33 +31,53 @@
     Dynamic,
     Decimal,
 )
+from graphene.types import enum
 from graphene.types.json import JSONString
-from graphene_django.compat import ArrayField, HStoreField, JSONField, RangeField
+from graphene_django.compat import ArrayField, HStoreField, RangeField
 from graphene_file_upload.scalars import Upload
-from graphql import assert_valid_name, GraphQLError
+
+if graphql.__version__.startswith("3.2"):
+    from graphql import GraphQLError, assert_name
+else:
+    from graphql import GraphQLError, assert_valid_name as assert_name
 
 from graphene_django_cud.types import TimeDelta
 from graphene_django_cud.util.string import to_camel_case, to_const
 
 
 def is_required(field, required=None, is_many_to_many=False):
+    """
+    Helper method to determine if a field is required or not.
+
+    :param field: The field to check for requirement.
+    :param required: Optional. Explicitly set requirement. If provided, this value will be returned.
+    :param is_many_to_many: Optional. Specifies whether the field is a many-to-many field. Default is False.
+    :return: True if the field is required, False otherwise.
+    """
+
+    # If required is explicitly set, use that
     if required is not None:
         return required
 
+    # If the field has a default value, it is not required as lack of a value
+    # will cause the default value to be used.
     field_default = getattr(field, "default", None)
     if field_default is not None and field_default != models.fields.NOT_PROVIDED:
         return False
 
+    # Many to many fields that have blank=True are not required either
+    # as the relation may be empty.
     if is_many_to_many and getattr(field, "blank", False):
         return False
 
+    # If the field is nullable, it is not required
     return not field.null
 
 
-def convert_choice_name(name):
+def convert_choice_name(name: str) -> str:
     name = to_const(force_str(name))
     try:
-        assert_valid_name(name)
+        assert_name(name)
     except AssertionError:
         name = "A_%s" % name
     return name
@@ -79,6 +101,7 @@ def get_choices(choices):
 def convert_choices_field(field, choices, required=None):
     meta = field.model._meta
     name = to_camel_case("{}_{}".format(meta.object_name, field.name))
+
     choices = list(get_choices(choices))
     named_choices = [(c[0], c[1]) for c in choices]
     named_choices_descriptions = {c[0]: c[2] for c in choices}
@@ -89,43 +112,24 @@ def description(self):
             return named_choices_descriptions[self.name]
 
     enum = Enum(name, list(named_choices), type=EnumWithDescriptionsType)
+
     # Note that we do not instantiate the field here, so we can store it un-instantiated in the registry.
     # This is the allow different parameters (e.g. `required`) to be passed to the field.
     return enum
-    # return enum(description=field.help_text, required=is_required(field, required))
 
 
 def convert_django_field_with_choices(
-    field,
-    registry=None,
-    required=None,
-    field_many_to_many_extras=None,
-    field_foreign_key_extras=None,
-    field_one_to_one_extras=None,
+        field,
+        registry=None,
+        required=None,
+        field_many_to_many_extras=None,
+        field_foreign_key_extras=None,
+        field_one_to_one_extras=None,
 ):
     choices = getattr(field, "choices", None)
-    if choices:
-        registry_name = to_camel_case(
-            "{}_{}".format(field.model._meta.object_name, field.name)
-        )
-        # Fetch this from registry, if exists. We don't want to duplicate enum fields.
-        enum = None
-        if registry:
-            from_registry = registry.get_converted_field(field)
-            if from_registry:
-                from_registry.kwargs['description'] = field.help_text
-                from_registry.kwargs['required'] = is_required(field, required)
-                return from_registry
-
-        converted = convert_choices_field(field, choices, required)
-        # Register enum fields
-        if registry:
-            registry.register_converted_field(registry_name, converted)
-        return converted(
-            description=field.help_text, required=is_required(field, required)
-        )
-    else:
-        converted = convert_django_field_to_input(
+
+    if not choices:
+        return convert_django_field_to_input(
             field,
             registry,
             required,
@@ -133,21 +137,56 @@ def convert_django_field_with_choices(
             field_foreign_key_extras,
             field_one_to_one_extras,
         )
-    return converted
+
+    registry_name = to_camel_case("{}_{}".format(field.model._meta.object_name, field.name))  # noqa
+
+    # Attempt to get the field from the registry. This is useful when the field already has been converted to
+    # a choice field by graphene-django. This conversion can be reused by us.
+    if registry:
+        # As of graphene-django 3.0, this is a Choices class mounted in a BlankValueField. We need to
+        # get the actual field from it and use that.
+        # In graphene-django 2.0, it is a regular `enum` type.
+        existing_conversion_in_registry = registry.get_converted_field(field)
+
+        if existing_conversion_in_registry:
+
+            # This is the graphene-django 2.0 case
+            if hasattr(existing_conversion_in_registry, "kwargs"):
+                existing_conversion_in_registry.kwargs["description"] = field.help_text
+                existing_conversion_in_registry.kwargs["required"] = is_required(field, required)
+
+                return existing_conversion_in_registry
+            # And this is the graphene-django 3.0 case
+            else:
+                # Fetch the actual converted Choices class. We have to do this with a slightly shady usage of
+                # the protected "_of_type" property of the NonNull type.
+                UnderlyingEnumCls = existing_conversion_in_registry.type._of_type if isinstance( # noqa
+                    existing_conversion_in_registry.type,
+                    NonNull) else existing_conversion_in_registry.type
+
+                # Return the converted field with the correct description and required value.
+                return UnderlyingEnumCls(description=field.help_text, required=is_required(field, required))
+
+    # If the field is not in the registry, perform a new conversion.
+    EnumCls = convert_choices_field(field, choices, required)
+
+    # Register enum fields if the registry exist.
+    if registry:
+        registry.register_converted_field(registry_name, EnumCls)
+
+    return EnumCls(description=field.help_text, required=is_required(field, required))  # noqa
 
 
 @singledispatch
 def convert_django_field_to_input(
-    field,
-    registry=None,
-    required=None,
-    field_many_to_many_extras=None,
-    field_foreign_key_extras=None,
-    field_one_to_one_extras=None,
+        field,
+        registry=None,
+        required=None,
+        field_many_to_many_extras=None,
+        field_foreign_key_extras=None,
+        field_one_to_one_extras=None,
 ):
-    raise Exception(
-        "Don't know how to convert the Django field %s (%s)" % (field, field.__class__)
-    )
+    raise Exception("Don't know how to convert the Django field %s (%s)" % (field, field.__class__))
 
 
 @convert_django_field_to_input.register(models.CharField)
@@ -158,12 +197,12 @@ def convert_django_field_to_input(
 @convert_django_field_to_input.register(models.GenericIPAddressField)
 @convert_django_field_to_input.register(models.FilePathField)
 def convert_field_to_string_extended(
-    field,
-    registry=None,
-    required=None,
-    field_many_to_many_extras=None,
-    field_foreign_key_extras=None,
-    field_one_to_one_extras=None,
+        field,
+        registry=None,
+        required=None,
+        field_many_to_many_extras=None,
+        field_foreign_key_extras=None,
+        field_one_to_one_extras=None,
 ):
     return String(description=field.help_text, required=is_required(field, required))
 
@@ -171,16 +210,14 @@ def convert_field_to_string_extended(
 @convert_django_field_to_input.register(models.OneToOneField)
 @convert_django_field_to_input.register(models.OneToOneRel)
 def convert_one_to_one_field(
-    field,
-    registry=None,
-    required=None,
-    field_many_to_many_extras=None,
-    field_foreign_key_extras=None,
-    field_one_to_one_extras=None,
+        field,
+        registry=None,
+        required=None,
+        field_many_to_many_extras=None,
+        field_foreign_key_extras=None,
+        field_one_to_one_extras=None,
 ):
-    type_name = (
-        field_one_to_one_extras.get("type", "ID") if field_one_to_one_extras else "ID"
-    )
+    type_name = field_one_to_one_extras.get("type", "ID") if field_one_to_one_extras else "ID"
     if type_name == "ID":
         return ID(
             description=getattr(field, "help_text", ""),
@@ -205,12 +242,12 @@ def dynamic_type():
 @convert_django_field_to_input.register(models.AutoField)
 @convert_django_field_to_input.register(models.ForeignKey)
 def convert_field_to_id(
-    field,
-    registry=None,
-    required=None,
-    field_many_to_many_extras=None,
-    field_foreign_key_extras=None,
-    field_one_to_one_extras=None,
+        field,
+        registry=None,
+        required=None,
+        field_many_to_many_extras=None,
+        field_foreign_key_extras=None,
+        field_one_to_one_extras=None,
 ):
     # Call getattr here, as OneToOneRel does not carry the attribute whatsoeever.
     id_type = ID(
@@ -230,21 +267,19 @@ def dynamic_type():
         if not _type:
             raise GraphQLError(f"The type {_type_name} does not exist.")
 
-        return InputField(
-            _type, description=field.help_text, required=is_required(field, required)
-        )
+        return InputField(_type, description=field.help_text, required=is_required(field, required))
 
     return Dynamic(dynamic_type)
 
 
 @convert_django_field_to_input.register(models.UUIDField)
 def convert_field_to_uuid(
-    field,
-    registry=None,
-    required=None,
-    field_many_to_many_extras=None,
-    field_foreign_key_extras=None,
-    field_one_to_one_extras=None,
+        field,
+        registry=None,
+        required=None,
+        field_many_to_many_extras=None,
+        field_foreign_key_extras=None,
+        field_one_to_one_extras=None,
 ):
     return UUID(description=field.help_text, required=is_required(field, required))
 
@@ -255,24 +290,24 @@ def convert_field_to_uuid(
 @convert_django_field_to_input.register(models.BigIntegerField)
 @convert_django_field_to_input.register(models.IntegerField)
 def convert_field_to_int(
-    field,
-    registry=None,
-    required=None,
-    field_many_to_many_extras=None,
-    field_foreign_key_extras=None,
-    field_one_to_one_extras=None,
+        field,
+        registry=None,
+        required=None,
+        field_many_to_many_extras=None,
+        field_foreign_key_extras=None,
+        field_one_to_one_extras=None,
 ):
     return Int(description=field.help_text, required=is_required(field, required))
 
 
 @convert_django_field_to_input.register(models.BooleanField)
 def convert_field_to_boolean(
-    field,
-    registry=None,
-    required=None,
-    field_many_to_many_extras=None,
-    field_foreign_key_extras=None,
-    field_one_to_one_extras=None,
+        field,
+        registry=None,
+        required=None,
+        field_many_to_many_extras=None,
+        field_foreign_key_extras=None,
+        field_one_to_one_extras=None,
 ):
     if is_required(field, required):
         return NonNull(Boolean, description=field.help_text)
@@ -283,65 +318,63 @@ def convert_field_to_boolean(
 
 @convert_django_field_to_input.register(models.NullBooleanField)
 def convert_field_to_nullboolean(
-    field,
-    registry=None,
-    required=None,
-    field_many_to_many_extras=None,
-    field_foreign_key_extras=None,
-    field_one_to_one_extras=None,
+        field,
+        registry=None,
+        required=None,
+        field_many_to_many_extras=None,
+        field_foreign_key_extras=None,
+        field_one_to_one_extras=None,
 ):
     return Boolean(description=field.help_text, required=is_required(field, required))
 
 
 @convert_django_field_to_input.register(models.FloatField)
 def convert_field_to_float(
-    field,
-    registry=None,
-    required=None,
-    field_many_to_many_extras=None,
-    field_foreign_key_extras=None,
-    field_one_to_one_extras=None,
+        field,
+        registry=None,
+        required=None,
+        field_many_to_many_extras=None,
+        field_foreign_key_extras=None,
+        field_one_to_one_extras=None,
 ):
     return Float(description=field.help_text, required=is_required(field, required))
 
 
 @convert_django_field_to_input.register(models.DecimalField)
 def convert_field_to_decimal(
-    field,
-    registry=None,
-    required=None,
-    field_many_to_many_extras=None,
-    field_foreign_key_extras=None,
-    field_one_to_one_extras=None,
+        field,
+        registry=None,
+        required=None,
+        field_many_to_many_extras=None,
+        field_foreign_key_extras=None,
+        field_one_to_one_extras=None,
 ):
     return Decimal(description=field.help_text, required=is_required(field, required))
 
 
 @convert_django_field_to_input.register(models.DurationField)
 def convert_field_to_time_delta(
-    field,
-    registry=None,
-    required=None,
-    field_many_to_many_extras=None,
-    field_foreign_key_extras=None,
-    field_one_to_one_extras=None,
+        field,
+        registry=None,
+        required=None,
+        field_many_to_many_extras=None,
+        field_foreign_key_extras=None,
+        field_one_to_one_extras=None,
 ):
     return TimeDelta(description=field.help_text, required=is_required(field, required))
 
 
 @convert_django_field_to_input.register(models.DateTimeField)
 def convert_datetime_to_string(
-    field,
-    registry=None,
-    required=None,
-    field_many_to_many_extras=None,
-    field_foreign_key_extras=None,
-    field_one_to_one_extras=None,
+        field,
+        registry=None,
+        required=None,
+        field_many_to_many_extras=None,
+        field_foreign_key_extras=None,
+        field_one_to_one_extras=None,
 ):
     # We only render DateTimeFields with auto_now[_add] if they are explicitly required or not
-    if required is None and (
-        getattr(field, "auto_now", None) or getattr(field, "auto_now_add", None)
-    ):
+    if required is None and (getattr(field, "auto_now", None) or getattr(field, "auto_now_add", None)):
         return
 
     return DateTime(description=field.help_text, required=is_required(field, required))
@@ -349,17 +382,15 @@ def convert_datetime_to_string(
 
 @convert_django_field_to_input.register(models.DateField)
 def convert_date_to_string(
-    field,
-    registry=None,
-    required=None,
-    field_many_to_many_extras=None,
-    field_foreign_key_extras=None,
-    field_one_to_one_extras=None,
+        field,
+        registry=None,
+        required=None,
+        field_many_to_many_extras=None,
+        field_foreign_key_extras=None,
+        field_one_to_one_extras=None,
 ):
     # We only render DateFields with auto_now[_add] if they are explicitly required or not
-    if required is None and (
-        getattr(field, "auto_now", None) or getattr(field, "auto_now_add", None)
-    ):
+    if required is None and (getattr(field, "auto_now", None) or getattr(field, "auto_now_add", None)):
         return
 
     return Date(description=field.help_text, required=is_required(field, required))
@@ -367,12 +398,12 @@ def convert_date_to_string(
 
 @convert_django_field_to_input.register(models.TimeField)
 def convert_time_to_string(
-    field,
-    registry=None,
-    required=None,
-    field_many_to_many_extras=None,
-    field_foreign_key_extras=None,
-    field_one_to_one_extras=None,
+        field,
+        registry=None,
+        required=None,
+        field_many_to_many_extras=None,
+        field_foreign_key_extras=None,
+        field_one_to_one_extras=None,
 ):
     return Time(description=field.help_text, required=is_required(field, required))
 
@@ -381,12 +412,12 @@ def convert_time_to_string(
 @convert_django_field_to_input.register(models.ManyToManyRel)
 @convert_django_field_to_input.register(models.ManyToOneRel)
 def convert_many_to_many_field(
-    field,
-    registry=None,
-    required=None,
-    field_many_to_many_extras=None,
-    field_foreign_key_extras=None,
-    field_one_to_one_extras=None,
+        field,
+        registry=None,
+        required=None,
+        field_many_to_many_extras=None,
+        field_foreign_key_extras=None,
+        field_one_to_one_extras=None,
 ):
     # Use getattr on help_text here as ManyToOnRel does not possess this.
     list_id_type = List(
@@ -417,61 +448,55 @@ def dynamic_type():
 
 @convert_django_field_to_input.register(ArrayField)
 def convert_postgres_array_to_list(
-    field,
-    registry=None,
-    required=None,
-    field_many_to_many_extras=None,
-    field_foreign_key_extras=None,
-    field_one_to_one_extras=None,
+        field,
+        registry=None,
+        required=None,
+        field_many_to_many_extras=None,
+        field_foreign_key_extras=None,
+        field_one_to_one_extras=None,
 ):
     base_type = convert_django_field_to_input(field.base_field)
     if not isinstance(base_type, (List, NonNull)):
         base_type = type(base_type)
-    return List(
-        base_type, description=field.help_text, required=is_required(field, required)
-    )
+    return List(base_type, description=field.help_text, required=is_required(field, required))
 
 
 @convert_django_field_to_input.register(HStoreField)
-@convert_django_field_to_input.register(JSONField)
+@convert_django_field_to_input.register(models.JSONField)
 def convert_posgres_field_to_string(
-    field,
-    registry=None,
-    required=None,
-    field_many_to_many_extras=None,
-    field_foreign_key_extras=None,
-    field_one_to_one_extras=None,
+        field,
+        registry=None,
+        required=None,
+        field_many_to_many_extras=None,
+        field_foreign_key_extras=None,
+        field_one_to_one_extras=None,
 ):
-    return JSONString(
-        description=field.help_text, required=is_required(field, required)
-    )
+    return JSONString(description=field.help_text, required=is_required(field, required))
 
 
 @convert_django_field_to_input.register(RangeField)
 def convert_postgres_range_to_string(
-    field,
-    registry=None,
-    required=None,
-    field_many_to_many_extras=None,
-    field_foreign_key_extras=None,
-    field_one_to_one_extras=None,
+        field,
+        registry=None,
+        required=None,
+        field_many_to_many_extras=None,
+        field_foreign_key_extras=None,
+        field_one_to_one_extras=None,
 ):
     inner_type = convert_django_field_to_input(field.base_field)
     if not isinstance(inner_type, (List, NonNull)):
         inner_type = type(inner_type)
-    return List(
-        inner_type, description=field.help_text, required=is_required(field, required)
-    )
+    return List(inner_type, description=field.help_text, required=is_required(field, required))
 
 
 @convert_django_field_to_input.register(FileField)
 @convert_django_field_to_input.register(ImageField)
 def convert_file_field_to_upload(
-    field,
-    registry=None,
-    required=None,
-    field_many_to_many_extras=None,
-    field_foreign_key_extras=None,
-    field_one_to_one_extras=None,
+        field,
+        registry=None,
+        required=None,
+        field_many_to_many_extras=None,
+        field_foreign_key_extras=None,
+        field_one_to_one_extras=None,
 ):
     return Upload(required=is_required(field, required))
diff --git a/graphene_django_cud/mutations/batch_create.py b/graphene_django_cud/mutations/batch_create.py
index ace506f..65390ea 100644
--- a/graphene_django_cud/mutations/batch_create.py
+++ b/graphene_django_cud/mutations/batch_create.py
@@ -80,15 +80,11 @@ def __init_subclass_with_meta__(
             raise Exception("Cannot set both `fields` and `only_fields` on a mutation")
 
         if exclude and exclude_fields:
-            raise Exception(
-                "Cannot set both `exclude` and `exclude_fields` on a mutation"
-            )
+            raise Exception("Cannot set both `exclude` and `exclude_fields` on a mutation")
 
         if only_fields:
             fields = only_fields
-            warnings.warn(
-                "`only_fields` is deprecated in favor of `fields`", DeprecationWarning
-            )
+            warnings.warn("`only_fields` is deprecated in favor of `fields`", DeprecationWarning)
 
         if exclude_fields:
             exclude = exclude_fields
@@ -101,9 +97,7 @@ def __init_subclass_with_meta__(
             input_type_name = use_type_name
             InputType = registry.get_converted_field(input_type_name)
             if not InputType:
-                raise GraphQLError(
-                    f"Could not find input type with name {input_type_name}"
-                )
+                raise GraphQLError(f"Could not find input type with name {input_type_name}")
         else:
             input_type_name = type_name or f"BatchCreate{model.__name__}Input"
 
@@ -166,9 +160,7 @@ def __init_subclass_with_meta__(
         _meta.field_types = field_types or {}
         _meta.InputType = InputType
         _meta.input_type_name = input_type_name
-        _meta.login_required = login_required or (
-            _meta.permissions and len(_meta.permissions) > 0
-        )
+        _meta.login_required = login_required or (_meta.permissions and len(_meta.permissions) > 0)
 
         super().__init_subclass_with_meta__(arguments=arguments, _meta=_meta, **kwargs)
 
@@ -212,7 +204,6 @@ def mutate(cls, root, info, input):
         cls.check_permissions(root, info, input)
 
         Model = cls._meta.model
-        model_field_values = {}
         auto_context_fields = cls._meta.auto_context_fields or {}
 
         created_objs = []
diff --git a/graphene_django_cud/mutations/batch_delete.py b/graphene_django_cud/mutations/batch_delete.py
index d5f98c4..8eed8c6 100644
--- a/graphene_django_cud/mutations/batch_delete.py
+++ b/graphene_django_cud/mutations/batch_delete.py
@@ -2,6 +2,7 @@
 from typing import Iterable
 
 import graphene
+from graphene import GlobalID
 from graphene.types.mutation import MutationOptions
 from graphene.types.utils import yank_fields_from_attrs
 from graphene.utils.str_converters import to_snake_case
@@ -33,6 +34,9 @@ def __init_subclass_with_meta__(
         **kwargs,
     ):
         registry = get_global_registry()
+        model_type = registry.get_type_for_model(model)
+
+        assert model_type, f"Model type must be registered for model {model}"
 
         if not return_field_name:
             return_field_name = to_snake_case(model.__name__)
@@ -48,15 +52,25 @@ def __init_subclass_with_meta__(
             _meta = DjangoBatchDeleteMutationOptions(cls)
 
         _meta.model = model
+        _meta.model_type = model_type
         _meta.fields = yank_fields_from_attrs(output_fields, _as=graphene.Field)
         _meta.return_field_name = return_field_name
         _meta.permissions = permissions
-        _meta.login_required = login_required or (
-            _meta.permissions and len(_meta.permissions) > 0
-        )
+        _meta.login_required = login_required or (_meta.permissions and len(_meta.permissions) > 0)
 
         super().__init_subclass_with_meta__(arguments=arguments, _meta=_meta, **kwargs)
 
+    @classmethod
+    def get_return_id(cls, id):
+        model_type = cls._meta.model_type
+
+        id_field = model_type._meta.fields.get("id", None)
+
+        if isinstance(id_field, GlobalID):
+            return to_global_id(cls._meta.model_type._meta.name, id)
+        else:
+            return id
+
     @classmethod
     def get_permissions(cls, root, info, input) -> Iterable[str]:
         return super().get_permissions(root, info, input)
@@ -100,7 +114,7 @@ def mutate(cls, root, info, ids):
 
         cls.validate(root, info, ids)
 
-        qs_to_delete = cls.get_queryset(root, info, ids).filter(id__in=ids)
+        qs_to_delete = cls.get_queryset(root, info, ids).filter(pk__in=ids)
 
         updated_qs = cls.before_save(root, info, ids, qs_to_delete)
 
@@ -108,15 +122,10 @@ def mutate(cls, root, info, ids):
             qs_to_delete = updated_qs
 
         # Find out which (global) ids are deleted, and which were not found.
-        deleted_ids = [
-            to_global_id(get_global_registry().get_type_for_model(Model).__name__, id)
-            for id in qs_to_delete.values_list("id", flat=True)
-        ]
-
-        all_global_ids = [
-            to_global_id(get_global_registry().get_type_for_model(Model).__name__, id)
-            for id in ids
-        ]
+        deleted_ids = [cls.get_return_id(id) for id in qs_to_delete.values_list("id", flat=True)]
+
+        all_global_ids = [cls.get_return_id(id) for id in ids]
+
 
         missed_ids = list(set(all_global_ids).difference(deleted_ids))
 
diff --git a/graphene_django_cud/mutations/batch_patch.py b/graphene_django_cud/mutations/batch_patch.py
index f53bc8e..2e4e882 100644
--- a/graphene_django_cud/mutations/batch_patch.py
+++ b/graphene_django_cud/mutations/batch_patch.py
@@ -1,5 +1,3 @@
-
-
 from graphene_django.utils import get_model_fields
 
 from .batch_update import DjangoBatchUpdateMutation
@@ -16,13 +14,13 @@ class Meta:
 
     @classmethod
     def __init_subclass_with_meta__(
-            cls,
-            _meta=None,
-            model=None,
-            optional_fields=None,
-            required_fields=None,
-            type_name=None,
-            **kwargs
+        cls,
+        _meta=None,
+        model=None,
+        optional_fields=None,
+        required_fields=None,
+        type_name=None,
+        **kwargs,
     ):
         all_field_names = tuple(name for name, _ in get_model_fields(model))
 
@@ -40,5 +38,5 @@ def __init_subclass_with_meta__(
             optional_fields=optional_fields,
             required_fields=required_fields,
             type_name=input_type_name,
-            **kwargs
+            **kwargs,
         )
diff --git a/graphene_django_cud/mutations/batch_update.py b/graphene_django_cud/mutations/batch_update.py
index 4aeb18f..a9b6d30 100644
--- a/graphene_django_cud/mutations/batch_update.py
+++ b/graphene_django_cud/mutations/batch_update.py
@@ -80,15 +80,11 @@ def __init_subclass_with_meta__(
             raise Exception("Cannot set both `fields` and `only_fields` on a mutation")
 
         if exclude and exclude_fields:
-            raise Exception(
-                "Cannot set both `exclude` and `exclude_fields` on a mutation"
-            )
+            raise Exception("Cannot set both `exclude` and `exclude_fields` on a mutation")
 
         if only_fields:
             fields = only_fields
-            warnings.warn(
-                "`only_fields` is deprecated in favor of `fields`", DeprecationWarning
-            )
+            warnings.warn("`only_fields` is deprecated in favor of `fields`", DeprecationWarning)
 
         if exclude_fields:
             exclude = exclude_fields
@@ -101,9 +97,7 @@ def __init_subclass_with_meta__(
             input_type_name = use_type_name
             InputType = registry.get_converted_field(input_type_name)
             if not InputType:
-                raise GraphQLError(
-                    f"Could not find input type with name {input_type_name}"
-                )
+                raise GraphQLError(f"Could not find input type with name {input_type_name}")
         else:
             input_type_name = type_name or f"BatchUpdate{model.__name__}Input"
 
@@ -167,9 +161,7 @@ def __init_subclass_with_meta__(
         _meta.field_types = field_types or {}
         _meta.InputType = InputType
         _meta.input_type_name = input_type_name
-        _meta.login_required = login_required or (
-            _meta.permissions and len(_meta.permissions) > 0
-        )
+        _meta.login_required = login_required or (_meta.permissions and len(_meta.permissions) > 0)
 
         super().__init_subclass_with_meta__(arguments=arguments, _meta=_meta, **kwargs)
 
@@ -208,9 +200,7 @@ def validate(cls, root, info, input, full_input):
 
     @classmethod
     def get_object(cls, root, info, input, full_input):
-        return cls.get_queryset(root, info, full_input).get(
-            pk=cls.resolve_id(input["id"])
-        )
+        return cls.get_queryset(root, info, full_input).get(pk=cls.resolve_id(input["id"]))
 
     @classmethod
     def mutate(cls, root, info, input):
@@ -224,7 +214,6 @@ def mutate(cls, root, info, input):
         cls.check_permissions(root, info, input)
 
         Model = cls._meta.model
-        model_field_values = {}
         auto_context_fields = cls._meta.auto_context_fields or {}
 
         updated_objs = []
diff --git a/graphene_django_cud/mutations/core.py b/graphene_django_cud/mutations/core.py
index d67dfdb..c27444f 100644
--- a/graphene_django_cud/mutations/core.py
+++ b/graphene_django_cud/mutations/core.py
@@ -1,7 +1,6 @@
 import enum
 from typing import Iterable, Union
 
-import graphene
 from django.db import models
 from graphene import Mutation
 from graphene.types.mutation import MutationOptions
@@ -15,7 +14,6 @@
     get_m2m_all_extras_field_names,
     disambiguate_ids,
     is_field_many_to_many,
-    is_field_one_to_one,
     is_field_many_to_one,
     get_model_field_or_none,
 )
@@ -46,7 +44,7 @@ def get_or_create_foreign_obj(cls, field, value, data, info):
                 input_type_meta.get("one_to_one_extras", {}),
                 field.related_model,
             )
-            return related_obj.id
+            return related_obj.pk
 
     @classmethod
     def create_or_update_one_to_one_relation(cls, obj, field, value, data, info):
@@ -165,16 +163,12 @@ def get_or_upsert_m2o_objs(cls, obj, field, values, data, operation, info, Model
                 }
 
                 if field_type == "auto":
-                    # In this case, a new type has been created for us. Let's first find it's name,
-                    # then get it's meta, and then create it. We also need to attach the obj as the
+                    # In this case, a new type has been created for us. Let's first find its name,
+                    # then get its meta, and then create it. We also need to attach the obj as the
                     # foreign key.
-                    _type_name = data.get(
-                        "type_name",
-                        f"{operation.capitalize()}{Model.__name__}{field.name.capitalize()}",
-                    )
 
                     # Ensure the parent relation exists and has the correct id.
-                    value[field.field.name] = obj.id
+                    value[field.field.name] = obj.pk
 
                     # We use upsert here, as the operation might be "update", where we
                     # want to update the object.
@@ -270,8 +264,6 @@ def create_obj(
         one_to_one_extras,
         Model,
     ):
-        meta_registry = get_type_meta_registry()
-
         many_to_many_to_add = {}
         many_to_many_to_remove = {}
         many_to_many_to_set = {}
@@ -281,16 +273,10 @@ def create_obj(
         model_field_values = {}
         one_to_one_rels = {}
 
-        many_to_many_extras_field_names = get_m2m_all_extras_field_names(
-            many_to_many_extras
-        )
+        many_to_many_extras_field_names = get_m2m_all_extras_field_names(many_to_many_extras)
         # The layout is the same as for m2m
-        many_to_one_extras_field_names = get_m2m_all_extras_field_names(
-            many_to_one_extras
-        )
-        foreign_key_extras_field_names = get_fk_all_extras_field_names(
-            foreign_key_extras
-        )
+        many_to_one_extras_field_names = get_m2m_all_extras_field_names(many_to_one_extras)
+        foreign_key_extras_field_names = get_fk_all_extras_field_names(foreign_key_extras)
 
         for field_name, context_name in auto_context_fields.items():
             if hasattr(info.context, context_name):
@@ -333,9 +319,7 @@ def create_obj(
             value_handle_name = "handle_" + name
             if hasattr(cls, value_handle_name):
                 handle_func = getattr(cls, value_handle_name)
-                assert callable(
-                    handle_func
-                ), f"Property {value_handle_name} on {cls.__name__} is not a function."
+                assert callable(handle_func), f"Property {value_handle_name} on {cls.__name__} is not a function."
                 new_value = handle_func(value, name, info)
 
             # On some fields we perform some default conversion, if the value was not transformed above.
@@ -363,9 +347,7 @@ def create_obj(
                             extra_data.get("one_to_one_extras", {}),
                             field.related_model,
                         )
-                elif isinstance(field, models.OneToOneRel) or isinstance(
-                    field, models.ForeignKey
-                ):
+                elif isinstance(field, models.OneToOneRel) or isinstance(field, models.ForeignKey):
                     # Delete auto context field here, if it exists. We have to do this explicitly
                     # as we change the name below
                     if name in auto_context_fields:
@@ -379,13 +361,9 @@ def create_obj(
                     new_value = new_value.value
 
             if field_is_many_to_many:
-                many_to_many_to_set[name] = cls.get_all_objs(
-                    field.related_model, new_value
-                )
+                many_to_many_to_set[name] = cls.get_all_objs(field.related_model, new_value)
             elif field_is_many_to_one:
-                many_to_one_to_set[name] = cls.get_all_objs(
-                    field.related_model, new_value
-                )
+                many_to_one_to_set[name] = cls.get_all_objs(field.related_model, new_value)
             else:
                 model_field_values[name] = new_value
 
@@ -399,7 +377,6 @@ def create_obj(
 
             model_field_values[name + "_id"] = obj_id
 
-        print(model_field_values)
         # Foreign keys are added, we are ready to create our object
         obj = Model.objects.create(**model_field_values)
 
@@ -413,9 +390,7 @@ def create_obj(
                 value_handle_name = "handle_" + name
                 if hasattr(cls, value_handle_name):
                     handle_func = getattr(cls, value_handle_name)
-                    assert callable(
-                        handle_func
-                    ), f"Property {value_handle_name} on {cls.__name__} is not a function."
+                    assert callable(handle_func), f"Property {value_handle_name} on {cls.__name__} is not a function."
                     new_value = handle_func(value, name, info)
 
                 # Value was not transformed
@@ -428,10 +403,8 @@ def create_obj(
                         extra_data = one_to_one_extras.get(name, {})
 
                         # This is a nested field we need to take care of.
-                        value[field.field.name] = obj.id
-                        new_value = cls.create_or_update_one_to_one_relation(
-                            obj, field, value, extra_data, info
-                        )
+                        value[field.field.name] = obj.pk
+                        new_value = cls.create_or_update_one_to_one_relation(obj, field, value, extra_data, info)
 
                 setattr(obj, name, new_value)
 
@@ -440,12 +413,10 @@ def create_obj(
         # Handle extras fields
         for name, extras in many_to_many_extras.items():
             field = Model._meta.get_field(name)
-            if not name in many_to_many_to_add:
+            if name not in many_to_many_to_add:
                 many_to_many_to_add[name] = []
                 many_to_many_to_remove[name] = []
-                many_to_many_to_set[
-                    name
-                ] = None  # None means that we should not (re)set the relation.
+                many_to_many_to_set[name] = None  # None means that we should not (re)set the relation.
 
             for extra_name, data in extras.items():
                 field_name = name
@@ -457,9 +428,7 @@ def create_obj(
                 if isinstance(data, bool):
                     data = {}
 
-                operation = data.get("operation") or get_likely_operation_from_name(
-                    extra_name
-                )
+                operation = data.get("operation") or get_likely_operation_from_name(extra_name)
                 objs = cls.get_or_create_m2m_objs(field, values, data, operation, info)
 
                 if operation == "exact":
@@ -473,12 +442,10 @@ def create_obj(
         for name, extras in many_to_one_extras.items():
             field = Model._meta.get_field(name)
 
-            if not name in many_to_one_to_add:
+            if name not in many_to_one_to_add:
                 many_to_one_to_add[name] = []
                 many_to_one_to_remove[name] = []
-                many_to_one_to_set[
-                    name
-                ] = None  # None means that we should not (re)set the relation.
+                many_to_one_to_set[name] = None  # None means that we should not (re)set the relation.
 
             for extra_name, data in extras.items():
                 field_name = name
@@ -493,19 +460,13 @@ def create_obj(
                 if isinstance(data, bool):
                     data = {}
 
-                operation = data.get("operation") or get_likely_operation_from_name(
-                    extra_name
-                )
+                operation = data.get("operation") or get_likely_operation_from_name(extra_name)
 
                 if operation == "exact":
-                    objs = cls.get_or_upsert_m2o_objs(
-                        obj, field, values, data, operation, info, Model
-                    )
+                    objs = cls.get_or_upsert_m2o_objs(obj, field, values, data, operation, info, Model)
                     many_to_one_to_set[name] = objs
                 elif operation == "add" or operation == "update":
-                    objs = cls.get_or_upsert_m2o_objs(
-                        obj, field, values, data, operation, info, Model
-                    )
+                    objs = cls.get_or_upsert_m2o_objs(obj, field, values, data, operation, info, Model)
                     many_to_one_to_add[name] += objs
                 else:
                     many_to_one_to_remove[name] += cls.resolve_ids(values)
@@ -519,7 +480,7 @@ def create_obj(
                     field.add(*objs)
                 else:
                     # Remove the related objects by deletion, and set the new ones.
-                    field.exclude(id__in=[obj.id for obj in objs]).delete()
+                    field.exclude(pk__in=[obj.pk for obj in objs]).delete()
                     getattr(obj, name).add(*objs)
 
         for name, objs in many_to_one_to_add.items():
@@ -530,11 +491,11 @@ def create_obj(
             if hasattr(field, "remove"):
                 # The field is nullable, and we simply remove the relation
                 related_name = Model._meta.get_field(name).remote_field.name
-                getattr(obj, name).filter(id__in=objs).update(**{related_name: None})
+                getattr(obj, name).filter(pk__in=objs).update(**{related_name: None})
             else:
                 # Only nullable foreign key reverse rels have the remove method.
                 # For other's we have to delete the relations
-                getattr(obj, name).filter(id__in=objs).delete()
+                getattr(obj, name).filter(pk__in=objs).delete()
 
         for name, objs in many_to_many_to_set.items():
             if objs is not None:
@@ -569,15 +530,11 @@ def update_obj(
         many_to_one_to_remove = {}
         many_to_one_to_set = {}
 
-        many_to_many_extras_field_names = get_m2m_all_extras_field_names(
-            many_to_many_extras
-        )
+        many_to_many_extras_field_names = get_m2m_all_extras_field_names(many_to_many_extras)
         many_to_one_extras_field_names = get_m2m_all_extras_field_names(
             many_to_one_extras
         )  # The layout is the same as for m2m
-        foreign_key_extras_field_names = get_fk_all_extras_field_names(
-            foreign_key_extras
-        )
+        foreign_key_extras_field_names = get_fk_all_extras_field_names(foreign_key_extras)
 
         for field_name, context_name in auto_context_fields.items():
             if hasattr(info.context, context_name):
@@ -608,14 +565,10 @@ def update_obj(
             # .set()-method, instead of direct assignment
             field_is_many_to_one = is_field_many_to_one(field)
 
-            field_is_one_to_one = is_field_one_to_one(field)
-
             value_handle_name = "handle_" + name
             if hasattr(cls, value_handle_name):
                 handle_func = getattr(cls, value_handle_name)
-                assert callable(
-                    handle_func
-                ), f"Property {value_handle_name} on {cls.__name__} is not a function."
+                assert callable(handle_func), f"Property {value_handle_name} on {cls.__name__} is not a function."
                 new_value = handle_func(value, name, info)
 
             # On some fields we perform some default conversion, if the value was not transformed above.
@@ -630,10 +583,8 @@ def update_obj(
                     else:
                         extra_data = one_to_one_extras.get(name, {})
                         # This is a nested field we need to take care of.
-                        value[field.remote_field.name] = obj.id
-                        new_value = cls.create_or_update_one_to_one_relation(
-                            obj, field, value, extra_data, info
-                        )
+                        value[field.remote_field.name] = obj.pk
+                        new_value = cls.create_or_update_one_to_one_relation(obj, field, value, extra_data, info)
                 elif isinstance(field, models.OneToOneRel):
                     # If the value is an integer or a string, we assume it is an ID
                     if isinstance(value, str) or isinstance(value, int):
@@ -642,10 +593,8 @@ def update_obj(
                     else:
                         extra_data = one_to_one_extras.get(name, {})
                         # This is a nested field we need to take care of.
-                        value[field.field.name] = obj.id
-                        new_value = cls.create_or_update_one_to_one_relation(
-                            obj, field, value, extra_data, info
-                        )
+                        value[field.field.name] = obj.pk
+                        new_value = cls.create_or_update_one_to_one_relation(obj, field, value, extra_data, info)
                 elif isinstance(field, models.ForeignKey):
                     # Delete auto context field here, if it exists. We have to do this explicitly
                     # as we change the name below
@@ -660,15 +609,10 @@ def update_obj(
                     new_value = new_value.value
 
             if field_is_many_to_many:
-                many_to_many_to_set[name] = cls.get_all_objs(
-                    field.related_model, new_value
-                )
+                many_to_many_to_set[name] = cls.get_all_objs(field.related_model, new_value)
             elif field_is_many_to_one:
-                many_to_one_to_set[name] = cls.get_all_objs(
-                    field.related_model, new_value
-                )
+                many_to_one_to_set[name] = cls.get_all_objs(field.related_model, new_value)
             else:
-                print(obj, name, new_value)
                 setattr(obj, name, new_value)
 
         # Handle extras fields
@@ -681,12 +625,10 @@ def update_obj(
 
         for name, extras in many_to_many_extras.items():
             field = Model._meta.get_field(name)
-            if not name in many_to_many_to_add:
+            if name not in many_to_many_to_add:
                 many_to_many_to_add[name] = []
                 many_to_many_to_remove[name] = []
-                many_to_many_to_set[
-                    name
-                ] = None  # None means that we should not (re)set the relation.
+                many_to_many_to_set[name] = None  # None means that we should not (re)set the relation.
 
             for extra_name, data in extras.items():
                 field_name = name
@@ -698,9 +640,7 @@ def update_obj(
                 if isinstance(data, bool):
                     data = {}
 
-                operation = data.get("operation") or get_likely_operation_from_name(
-                    extra_name
-                )
+                operation = data.get("operation") or get_likely_operation_from_name(extra_name)
                 objs = cls.get_or_create_m2m_objs(field, values, data, operation, info)
 
                 if operation == "exact":
@@ -713,12 +653,10 @@ def update_obj(
         for name, extras in many_to_one_extras.items():
             field = Model._meta.get_field(name)
 
-            if not name in many_to_one_to_add:
+            if name not in many_to_one_to_add:
                 many_to_one_to_add[name] = []
                 many_to_one_to_remove[name] = []
-                many_to_one_to_set[
-                    name
-                ] = None  # None means that we should not (re)set the relation.
+                many_to_one_to_set[name] = None  # None means that we should not (re)set the relation.
 
             for extra_name, data in extras.items():
                 field_name = name
@@ -733,19 +671,13 @@ def update_obj(
                 if isinstance(data, bool):
                     data = {}
 
-                operation = data.get("operation") or get_likely_operation_from_name(
-                    extra_name
-                )
+                operation = data.get("operation") or get_likely_operation_from_name(extra_name)
 
                 if operation == "exact":
-                    objs = cls.get_or_upsert_m2o_objs(
-                        obj, field, values, data, operation, info, Model
-                    )
+                    objs = cls.get_or_upsert_m2o_objs(obj, field, values, data, operation, info, Model)
                     many_to_one_to_set[name] = objs
                 elif operation == "add" or operation == "update":
-                    objs = cls.get_or_upsert_m2o_objs(
-                        obj, field, values, data, operation, info, Model
-                    )
+                    objs = cls.get_or_upsert_m2o_objs(obj, field, values, data, operation, info, Model)
                     many_to_one_to_add[name] += objs
                 else:
                     many_to_one_to_remove[name] += cls.resolve_ids(values)
@@ -759,7 +691,7 @@ def update_obj(
                     field.add(*objs)
                 else:
                     # Remove the related objects by deletion, and set the new ones.
-                    field.exclude(id__in=[obj.id for obj in objs]).delete()
+                    field.exclude(pk__in=[obj.pk for obj in objs]).delete()
                     getattr(obj, name).add(*objs)
 
         for name, objs in many_to_one_to_add.items():
@@ -770,11 +702,11 @@ def update_obj(
             if hasattr(field, "remove"):
                 # The field is nullable, and we simply remove the relation
                 related_name = Model._meta.get_field(name).remote_field.name
-                getattr(obj, name).filter(id__in=objs).update(**{related_name: None})
+                getattr(obj, name).filter(pk__in=objs).update(**{related_name: None})
             else:
                 # Only nullable foreign key reverse rels have the remove method.
                 # For other's we have to delete the relations
-                getattr(obj, name).filter(id__in=objs).delete()
+                getattr(obj, name).filter(pk__in=objs).delete()
 
         for name, objs in many_to_many_to_set.items():
             if objs is not None:
@@ -796,9 +728,7 @@ def get_permissions(cls, root, info, *args, **kwargs) -> Iterable[str]:
     def check_permissions(cls, root, info, *args, **kwargs) -> None:
         get_permissions = getattr(cls, "get_permissions", None)
         if not callable(get_permissions):
-            raise TypeError(
-                "The `get_permissions` attribute of a mutation must be callable."
-            )
+            raise TypeError("The `get_permissions` attribute of a mutation must be callable.")
 
         permissions = cls.get_permissions(root, info, *args, **kwargs)
 
diff --git a/graphene_django_cud/mutations/create.py b/graphene_django_cud/mutations/create.py
index cc5162a..b6f8753 100644
--- a/graphene_django_cud/mutations/create.py
+++ b/graphene_django_cud/mutations/create.py
@@ -79,15 +79,11 @@ def __init_subclass_with_meta__(
             raise Exception("Cannot set both `fields` and `only_fields` on a mutation")
 
         if exclude and exclude_fields:
-            raise Exception(
-                "Cannot set both `exclude` and `exclude_fields` on a mutation"
-            )
+            raise Exception("Cannot set both `exclude` and `exclude_fields` on a mutation")
 
         if only_fields:
             fields = only_fields
-            warnings.warn(
-                "`only_fields` is deprecated in favor of `fields`", DeprecationWarning
-            )
+            warnings.warn("`only_fields` is deprecated in favor of `fields`", DeprecationWarning)
 
         if exclude_fields:
             exclude = exclude_fields
@@ -158,9 +154,7 @@ def __init_subclass_with_meta__(
         _meta.field_types = field_types or {}
         _meta.InputType = InputType
         _meta.input_type_name = input_type_name
-        _meta.login_required = login_required or (
-            _meta.permissions and len(_meta.permissions) > 0
-        )
+        _meta.login_required = login_required or (_meta.permissions and len(_meta.permissions) > 0)
 
         super().__init_subclass_with_meta__(arguments=arguments, _meta=_meta, **kwargs)
 
@@ -201,7 +195,6 @@ def mutate(cls, root, info, input):
         cls.validate(root, info, input)
 
         Model = cls._meta.model
-        model_field_values = {}
         auto_context_fields = cls._meta.auto_context_fields or {}
 
         with transaction.atomic():
diff --git a/graphene_django_cud/mutations/delete.py b/graphene_django_cud/mutations/delete.py
index 86c8805..8a93ac4 100644
--- a/graphene_django_cud/mutations/delete.py
+++ b/graphene_django_cud/mutations/delete.py
@@ -60,9 +60,7 @@ def __init_subclass_with_meta__(
         _meta.fields = yank_fields_from_attrs(output_fields, _as=graphene.Field)
         _meta.return_field_name = return_field_name
         _meta.permissions = permissions
-        _meta.login_required = login_required or (
-            _meta.permissions and len(_meta.permissions) > 0
-        )
+        _meta.login_required = login_required or (_meta.permissions and len(_meta.permissions) > 0)
 
         super().__init_subclass_with_meta__(arguments=arguments, _meta=_meta, **kwargs)
 
@@ -102,9 +100,13 @@ def get_return_id(cls, obj):
         id_field = model_type._meta.fields.get("id", None)
 
         if isinstance(id_field, GlobalID):
-            return to_global_id(cls._meta.model_type._meta.name, obj.id)
+            return to_global_id(cls._meta.model_type._meta.name, obj.pk)
         else:
-            return obj.id
+            return obj.pk
+
+    @classmethod
+    def perform_delete(cls, obj):
+        obj.delete()
 
     @classmethod
     def mutate(cls, root, info, id):
@@ -115,7 +117,6 @@ def mutate(cls, root, info, id):
 
         cls.validate(root, info, id)
 
-        Model = cls._meta.model
         resolved_id = cls.resolve_id(id)
 
         try:
@@ -127,8 +128,8 @@ def mutate(cls, root, info, id):
                 obj = updated_obj
 
             return_id = cls.get_return_id(obj)
-            raw_id = obj.id
-            obj.delete()
+            raw_id = obj.pk
+            cls.perform_delete(obj)
             cls.after_mutate(root, info, id, True)
             return cls(
                 found=True,
diff --git a/graphene_django_cud/mutations/filter_delete.py b/graphene_django_cud/mutations/filter_delete.py
index 8b9f507..10f4781 100644
--- a/graphene_django_cud/mutations/filter_delete.py
+++ b/graphene_django_cud/mutations/filter_delete.py
@@ -42,15 +42,11 @@ def __init_subclass_with_meta__(
         model_type = registry.get_type_for_model(model)
 
         assert model_type, f"Model type must be registered for model {model}"
-        assert (
-            len(filter_fields) > 0
-        ), f"You must specify at least one field to filter on for deletion."
+        assert len(filter_fields) > 0, "You must specify at least one field to filter on for deletion."
 
         input_arguments = get_filter_fields_input_args(filter_fields, model)
 
-        InputType = type(
-            f"BatchDelete{model.__name__}Input", (InputObjectType,), input_arguments
-        )
+        InputType = type(f"BatchDelete{model.__name__}Input", (InputObjectType,), input_arguments)
 
         arguments = OrderedDict(input=InputType(required=True))
 
@@ -65,9 +61,7 @@ def __init_subclass_with_meta__(
         _meta.fields = yank_fields_from_attrs(output_fields, _as=graphene.Field)
         _meta.filter_fields = filter_fields
         _meta.permissions = permissions
-        _meta.login_required = login_required or (
-            _meta.permissions and len(_meta.permissions) > 0
-        )
+        _meta.login_required = login_required or (_meta.permissions and len(_meta.permissions) > 0)
 
         super().__init_subclass_with_meta__(arguments=arguments, _meta=_meta, **kwargs)
 
@@ -138,9 +132,7 @@ def mutate(cls, root, info, input):
             value_handle_name = "handle_" + name
             if hasattr(cls, value_handle_name):
                 handle_func = getattr(cls, value_handle_name)
-                assert callable(
-                    handle_func
-                ), f"Property {value_handle_name} on {cls.__name__} is not a function."
+                assert callable(handle_func), f"Property {value_handle_name} on {cls.__name__} is not a function."
                 new_value = handle_func(value, name, info)
 
             # On some fields we perform some default conversion, if the value was not transformed above.
diff --git a/graphene_django_cud/mutations/filter_update.py b/graphene_django_cud/mutations/filter_update.py
index 6d23335..24b8826 100644
--- a/graphene_django_cud/mutations/filter_update.py
+++ b/graphene_django_cud/mutations/filter_update.py
@@ -58,23 +58,17 @@ def __init_subclass_with_meta__(
             optional_fields = tuple(name for name, _ in get_model_fields(model))
 
         assert model_type, f"Model type must be registered for model {model}"
-        assert (
-            len(filter_fields) > 0
-        ), f"You must specify at least one field to filter on for deletion."
+        assert len(filter_fields) > 0, "You must specify at least one field to filter on for deletion."
 
         if fields and only_fields:
             raise Exception("Cannot set both `fields` and `only_fields` on a mutation")
 
         if exclude and exclude_fields:
-            raise Exception(
-                "Cannot set both `exclude` and `exclude_fields` on a mutation"
-            )
+            raise Exception("Cannot set both `exclude` and `exclude_fields` on a mutation")
 
         if only_fields:
             fields = only_fields
-            warnings.warn(
-                "`only_fields` is deprecated in favor of `fields`", DeprecationWarning
-            )
+            warnings.warn("`only_fields` is deprecated in favor of `fields`", DeprecationWarning)
 
         if exclude_fields:
             exclude = exclude_fields
@@ -127,9 +121,7 @@ def __init_subclass_with_meta__(
 
         registry.register_converted_field(input_type_name, DataInputType)
 
-        arguments = OrderedDict(
-            filter=FilterInputType(required=True), data=DataInputType(required=True)
-        )
+        arguments = OrderedDict(filter=FilterInputType(required=True), data=DataInputType(required=True))
 
         output_fields = OrderedDict()
         output_fields["updated_count"] = graphene.Int()
@@ -142,9 +134,7 @@ def __init_subclass_with_meta__(
         _meta.fields = yank_fields_from_attrs(output_fields, _as=graphene.Field)
         _meta.filter_fields = filter_fields
         _meta.permissions = permissions
-        _meta.login_required = login_required or (
-            _meta.permissions and len(_meta.permissions) > 0
-        )
+        _meta.login_required = login_required or (_meta.permissions and len(_meta.permissions) > 0)
 
         super().__init_subclass_with_meta__(arguments=arguments, _meta=_meta, **kwargs)
 
@@ -216,9 +206,7 @@ def mutate(cls, root, info, filter, data):
             value_handle_name = "handle_" + name
             if hasattr(cls, value_handle_name):
                 handle_func = getattr(cls, value_handle_name)
-                assert callable(
-                    handle_func
-                ), f"Property {value_handle_name} on {cls.__name__} is not a function."
+                assert callable(handle_func), f"Property {value_handle_name} on {cls.__name__} is not a function."
                 new_value = handle_func(value, name, info)
 
             # On some fields we perform some default conversion, if the value was not transformed above.
@@ -239,9 +227,7 @@ def mutate(cls, root, info, filter, data):
 
             model_field_values[name] = new_value
 
-        filter_qs = cls.get_queryset(root, info, filter, data).filter(
-            **model_field_values
-        )
+        filter_qs = cls.get_queryset(root, info, filter, data).filter(**model_field_values)
         updated_qs = cls.before_save(root, info, filter_qs, filter, data)
 
         if updated_qs:
diff --git a/graphene_django_cud/mutations/patch.py b/graphene_django_cud/mutations/patch.py
index d036f58..8caf892 100644
--- a/graphene_django_cud/mutations/patch.py
+++ b/graphene_django_cud/mutations/patch.py
@@ -1,4 +1,3 @@
-
 from graphene_django.utils import get_model_fields
 
 from .update import DjangoUpdateMutation
@@ -21,7 +20,7 @@ def __init_subclass_with_meta__(
         optional_fields=None,
         required_fields=None,
         type_name=None,
-        **kwargs
+        **kwargs,
     ):
         all_field_names = tuple(name for name, _ in get_model_fields(model))
 
@@ -39,5 +38,5 @@ def __init_subclass_with_meta__(
             optional_fields=optional_fields,
             required_fields=required_fields,
             type_name=input_type_name,
-            **kwargs
+            **kwargs,
         )
diff --git a/graphene_django_cud/mutations/update.py b/graphene_django_cud/mutations/update.py
index 623de1d..dc78e0f 100644
--- a/graphene_django_cud/mutations/update.py
+++ b/graphene_django_cud/mutations/update.py
@@ -30,10 +30,10 @@ def __init_subclass_with_meta__(
         permissions=None,
         login_required=None,
         fields=(),
-            only_fields=(),  # Deprecated in favor of `fields`
-            exclude=(),
-            exclude_fields=(),  # Deprecated in favor of `exclude`
-            optional_fields=(),
+        only_fields=(),  # Deprecated in favor of `fields`
+        exclude=(),
+        exclude_fields=(),  # Deprecated in favor of `exclude`
+        optional_fields=(),
         required_fields=(),
         auto_context_fields=None,
         return_field_name=None,
@@ -78,15 +78,11 @@ def __init_subclass_with_meta__(
             raise Exception("Cannot set both `fields` and `only_fields` on a mutation")
 
         if exclude and exclude_fields:
-            raise Exception(
-                "Cannot set both `exclude` and `exclude_fields` on a mutation"
-            )
+            raise Exception("Cannot set both `exclude` and `exclude_fields` on a mutation")
 
         if only_fields:
             fields = only_fields
-            warnings.warn(
-                "`only_fields` is deprecated in favor of `fields`", DeprecationWarning
-            )
+            warnings.warn("`only_fields` is deprecated in favor of `fields`", DeprecationWarning)
 
         if exclude_fields:
             exclude = exclude_fields
@@ -133,9 +129,7 @@ def __init_subclass_with_meta__(
 
         registry.register_converted_field(input_type_name, InputType)
 
-        arguments = OrderedDict(
-            id=graphene.ID(required=True), input=InputType(required=True)
-        )
+        arguments = OrderedDict(id=graphene.ID(required=True), input=InputType(required=True))
 
         output_fields = OrderedDict()
         output_fields[return_field_name] = graphene.Field(model_type)
@@ -158,9 +152,7 @@ def __init_subclass_with_meta__(
         _meta.field_types = field_types or {}
         _meta.InputType = InputType
         _meta.input_type_name = input_type_name
-        _meta.login_required = login_required or (
-            _meta.permissions and len(_meta.permissions) > 0
-        )
+        _meta.login_required = login_required or (_meta.permissions and len(_meta.permissions) > 0)
         _meta.use_select_for_update = use_select_for_update
 
         super().__init_subclass_with_meta__(arguments=arguments, _meta=_meta, **kwargs)
diff --git a/graphene_django_cud/types.py b/graphene_django_cud/types.py
index a577636..dec8a31 100644
--- a/graphene_django_cud/types.py
+++ b/graphene_django_cud/types.py
@@ -53,6 +53,4 @@ def parse_value(value):
         if seconds:
             seconds = int(seconds)
 
-        return timezone.timedelta(
-            days=days, hours=hours, minutes=minutes, seconds=seconds
-        )
+        return timezone.timedelta(days=days, hours=hours, minutes=minutes, seconds=seconds)
diff --git a/graphene_django_cud/urls.py b/graphene_django_cud/urls.py
index 0501690..f2e68e0 100644
--- a/graphene_django_cud/urls.py
+++ b/graphene_django_cud/urls.py
@@ -18,6 +18,6 @@
 from graphene_file_upload.django import FileUploadGraphQLView
 
 urlpatterns = [
-    path('admin/', admin.site.urls),
-    path('graphql', FileUploadGraphQLView(graphiql=True).as_view())
+    path("admin/", admin.site.urls),
+    path("graphql", FileUploadGraphQLView(graphiql=True).as_view()),
 ]
diff --git a/graphene_django_cud/util/__init__.py b/graphene_django_cud/util/__init__.py
index 28fe2c1..f1c2dc7 100644
--- a/graphene_django_cud/util/__init__.py
+++ b/graphene_django_cud/util/__init__.py
@@ -1,3 +1,2 @@
-
-from .model import *
-from .string import *
\ No newline at end of file
+from .model import *  # noqa: F401 F403
+from .string import *  # noqa: F401 F403
diff --git a/graphene_django_cud/util/model.py b/graphene_django_cud/util/model.py
index d9f0fdf..c681a2e 100644
--- a/graphene_django_cud/util/model.py
+++ b/graphene_django_cud/util/model.py
@@ -1,5 +1,4 @@
 import binascii
-import re
 import uuid
 from collections import OrderedDict
 from typing import Union, List, Optional
@@ -73,9 +72,7 @@ def overload_nested_fields(nested_fields):
         for el in nested_fields:
             # Should be a string
             if not isinstance(el, str):
-                raise ValueError(
-                    f"Nested field iterable entry has to be a string. Got {type(el)}"
-                )
+                raise ValueError(f"Nested field iterable entry has to be a string. Got {type(el)}")
 
             result[el] = ["all"]
         return result
@@ -97,7 +94,6 @@ def get_input_fields_for_model(
     field_types=None,
     ignore_primary_key=True,
 ) -> OrderedDict:
-
     registry = get_global_registry()
     meta_registry = get_type_meta_registry()
     model_fields = get_model_fields(model)
@@ -105,15 +101,9 @@ def get_input_fields_for_model(
     many_to_many_extras = resolve_many_to_many_extra_auto_field_names(
         many_to_many_extras or {}, model, parent_type_name
     )
-    many_to_one_extras = resolve_many_to_one_extra_auto_field_names(
-        many_to_one_extras or {}, model, parent_type_name
-    )
-    foreign_key_extras = resolve_foreign_key_extra_auto_field_names(
-        foreign_key_extras or {}, model, parent_type_name
-    )
-    one_to_one_extras = resolve_one_to_one_extra_auto_field_names(
-        one_to_one_extras or {}, model, parent_type_name
-    )
+    many_to_one_extras = resolve_many_to_one_extra_auto_field_names(many_to_one_extras or {}, model, parent_type_name)
+    foreign_key_extras = resolve_foreign_key_extra_auto_field_names(foreign_key_extras or {}, model, parent_type_name)
+    one_to_one_extras = resolve_one_to_one_extra_auto_field_names(one_to_one_extras or {}, model, parent_type_name)
 
     field_types = field_types or {}
     one_to_one_fields: List[Union[models.OneToOneRel, models.OneToOneField]] = []
@@ -170,9 +160,7 @@ def get_input_fields_for_model(
         field: models.ForeignKey = fields_lookup.get(name)
 
         if field is None:
-            raise ValueError(
-                f"Error adding extras for {name} in model f{model}. Field {name} does not exist."
-            )
+            raise ValueError(f"Error adding extras for {name} in model f{model}. Field {name} does not exist.")
 
         type_name = data.get("type")
 
@@ -192,9 +180,7 @@ def get_input_fields_for_model(
             # TODO: Remove only_fields and exclude_fields when the deprecated fields are removed.
             tuple(data.get("fields", data.get("only_fields", ()))),
             tuple(data.get("exclude", data.get("exclude_fields", ())))
-            + (
-                reverse_field_name,
-            ),  # Exclude the field referring back to the foreign key
+            + (reverse_field_name,),  # Exclude the field referring back to the foreign key
             data.get("optional_fields", ()),
             data.get("required_fields", ()),
             data.get("many_to_many_extras"),
@@ -213,9 +199,7 @@ def get_input_fields_for_model(
         field: Union[models.OneToOneRel, models.OneToOneField] = fields_lookup.get(name)
 
         if field is None:
-            raise ValueError(
-                f"Error adding extras for {name} in model f{model}. Field {name} does not exist."
-            )
+            raise ValueError(f"Error adding extras for {name} in model f{model}. Field {name} does not exist.")
 
         type_name = data.get("type")
 
@@ -224,20 +208,14 @@ def get_input_fields_for_model(
 
         # On OneToOnerels we can get the reverse field name from "field.field.name", as we have a direct
         # reference to the reverse field that way. For OneToOneFields we need to go through "field.target_field".
-        reverse_field_name = (
-            field.field.name
-            if isinstance(field, models.OneToOneRel)
-            else field.remote_field.name
-        )
+        reverse_field_name = field.field.name if isinstance(field, models.OneToOneRel) else field.remote_field.name
 
         one_to_one_converted_fields = get_input_fields_for_model(
             field.related_model,
             # TODO: Remove only_fields and exclude_fields when the deprecated fields are removed.
             tuple(data.get("fields", data.get("only_fields", ()))),
             tuple(data.get("exclude", data.get("exclude_fields", ())))
-            + (
-                reverse_field_name,
-            ),  # Exclude the field referring back to the foreign key
+            + (reverse_field_name,),  # Exclude the field referring back to the foreign key
             data.get("optional_fields", ()),
             data.get("required_fields", ()),
             data.get("many_to_many_extras"),
@@ -253,13 +231,9 @@ def get_input_fields_for_model(
 
     # Create extra many_to_many_fields
     for name, extras in many_to_many_extras.items():
-        field: Optional[
-            Union[models.ManyToManyField, models.ManyToManyRel]
-        ] = fields_lookup.get(name)
+        field: Optional[Union[models.ManyToManyField, models.ManyToManyRel]] = fields_lookup.get(name)
         if field is None:
-            raise GraphQLError(
-                f"Error adding extras for {name} in model f{model}. Field {name} does not exist."
-            )
+            raise GraphQLError(f"Error adding extras for {name} in model f{model}. Field {name} does not exist.")
 
         for extra_name, data in extras.items():
 
@@ -276,9 +250,7 @@ def get_input_fields_for_model(
     for name, extras in many_to_one_extras.items():
         field: models.ManyToOneRel = fields_lookup.get(name)
         if field is None:
-            raise GraphQLError(
-                f"Error adding extras for {name} in model f{model}. Field {name} does not exist."
-            )
+            raise GraphQLError(f"Error adding extras for {name} in model f{model}. Field {name} does not exist.")
 
         for extra_name, data in extras.items():
 
@@ -295,9 +267,7 @@ def get_input_fields_for_model(
     return converted_input_fields
 
 
-def convert_many_to_many_like_field(
-    data, name, extra_name, parent_type_name, field, registry, meta_registry
-):
+def convert_many_to_many_like_field(data, name, extra_name, parent_type_name, field, registry, meta_registry):
     if isinstance(data, bool):
         data = {"type": "ID"}
 
@@ -315,9 +285,7 @@ def convert_many_to_many_like_field(
             return create_dynamic_list_type(field, type_name, registry, False)
 
         # Create new type.
-        operation_name = data.get(
-            "operation", get_likely_operation_from_name(extra_name)
-        )
+        operation_name = data.get("operation", get_likely_operation_from_name(extra_name))
 
         exclude_fields = ()
         if isinstance(field, models.ManyToOneRel):
@@ -326,9 +294,7 @@ def convert_many_to_many_like_field(
         converted_fields = get_input_fields_for_model(
             field.related_model,
             data.get("only_fields", ()),
-            data.get(
-                "exclude_fields", exclude_fields
-            ),  # Exclude the field referring back to the foreign key
+            data.get("exclude_fields", exclude_fields),  # Exclude the field referring back to the foreign key
             data.get("optional_fields", ()),
             data.get("required_fields", ()),
             data.get("many_to_many_extras"),
@@ -456,9 +422,7 @@ def get_filter_fields_input_args(filter_fields, model):
 def is_field_many_to_many(field):
     # We check type equality for ManyToManyRel to ensure we don't get false positives for
     # OnetoOneRel
-    return isinstance(field, models.ManyToManyField) or isinstance(
-        field, models.ManyToManyRel
-    )
+    return isinstance(field, models.ManyToManyField) or isinstance(field, models.ManyToManyRel)
 
 
 def is_field_many_to_one(field):
@@ -499,15 +463,12 @@ def get_m2m_all_extras_field_names(extras):
 
 
 def get_fk_all_extras_field_names(extras):
-    res = []
     if not extras:
         return []
     return extras.keys()
 
 
-def resolve_many_to_many_extra_auto_field_names(
-    many_to_many_extras, model, parent_type_name
-):
+def resolve_many_to_many_extra_auto_field_names(many_to_many_extras, model, parent_type_name):
     new_many_to_many_extras = {}
     for name, extras in many_to_many_extras.items():
         new_extras = {}
@@ -518,14 +479,13 @@ def resolve_many_to_many_extra_auto_field_names(
             type_name = data.get("type", "ID")
 
             if type_name == "auto":
-                operation_name = data.get(
-                    "operation", get_likely_operation_from_name(extra_name)
-                )
+                operation_name = data.get("operation", get_likely_operation_from_name(extra_name))
                 new_extras[extra_name] = {
                     **data,
                     # Add auto marker. This will become important when actually creating the types
                     "auto": True,
-                    "type": f"{parent_type_name or ''}{operation_name.capitalize()}{model.__name__}{to_camel_case(name).capitalize()}",
+                    "type": f"{parent_type_name or ''}"
+                    f"{operation_name.capitalize()}{model.__name__}{to_camel_case(name).capitalize()}",
                 }
             else:
                 new_extras[extra_name] = data
@@ -534,9 +494,7 @@ def resolve_many_to_many_extra_auto_field_names(
     return new_many_to_many_extras
 
 
-def resolve_many_to_one_extra_auto_field_names(
-    many_to_one_extras, model, parent_type_name
-):
+def resolve_many_to_one_extra_auto_field_names(many_to_one_extras, model, parent_type_name):
     new_many_to_one_extras = {}
     for name, extras in many_to_one_extras.items():
         new_extras = {}
@@ -547,13 +505,12 @@ def resolve_many_to_one_extra_auto_field_names(
             type_name = data.get("type", "ID")
 
             if type_name == "auto":
-                operation_name = data.get(
-                    "operation", get_likely_operation_from_name(extra_name)
-                )
+                operation_name = data.get("operation", get_likely_operation_from_name(extra_name))
                 new_extras[extra_name] = {
                     **data,
                     "auto": True,
-                    "type": f"{parent_type_name or ''}{operation_name.capitalize()}{model.__name__}{to_camel_case(name).capitalize()}",
+                    "type": f"{parent_type_name or ''}"
+                    f"{operation_name.capitalize()}{model.__name__}{to_camel_case(name).capitalize()}",
                 }
             else:
                 new_extras[extra_name] = data
@@ -562,9 +519,7 @@ def resolve_many_to_one_extra_auto_field_names(
     return new_many_to_one_extras
 
 
-def resolve_foreign_key_extra_auto_field_names(
-    foreign_key_extras, model, parent_type_name
-):
+def resolve_foreign_key_extra_auto_field_names(foreign_key_extras, model, parent_type_name):
     new_foreign_key_extras = {}
     for name, data in foreign_key_extras.items():
         type_name = data.get("type", "ID")
@@ -580,9 +535,7 @@ def resolve_foreign_key_extra_auto_field_names(
     return new_foreign_key_extras
 
 
-def resolve_one_to_one_extra_auto_field_names(
-    one_to_one_extras, model, parent_type_name
-):
+def resolve_one_to_one_extra_auto_field_names(one_to_one_extras, model, parent_type_name):
     new_one_to_one_extras = {}
     for name, data in one_to_one_extras.items():
         type_name = data.get("type", "ID")
diff --git a/graphene_django_cud/util/string.py b/graphene_django_cud/util/string.py
index ef3dd13..d15ed49 100644
--- a/graphene_django_cud/util/string.py
+++ b/graphene_django_cud/util/string.py
@@ -1,5 +1,6 @@
 import re
 
+
 # http://stackoverflow.com/a/1176023/1072990
 def to_snake_case(name):
     s1 = re.sub("(.)([A-Z][a-z]+)", r"\1_\2", name)
diff --git a/graphene_django_cud/wsgi.py b/graphene_django_cud/wsgi.py
index d00445b..c7c2932 100644
--- a/graphene_django_cud/wsgi.py
+++ b/graphene_django_cud/wsgi.py
@@ -11,6 +11,6 @@
 
 from django.core.wsgi import get_wsgi_application
 
-os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'graphene_django_cud.settings')
+os.environ.setdefault("DJANGO_SETTINGS_MODULE", "graphene_django_cud.settings")
 
 application = get_wsgi_application()
diff --git a/manage.py b/manage.py
index 496934c..e45881c 100755
--- a/manage.py
+++ b/manage.py
@@ -2,8 +2,8 @@
 import os
 import sys
 
-if __name__ == '__main__':
-    os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'test_settings')
+if __name__ == "__main__":
+    os.environ.setdefault("DJANGO_SETTINGS_MODULE", "test_settings")
     try:
         from django.core.management import execute_from_command_line
     except ImportError as exc:
diff --git a/poetry.lock b/poetry.lock
index 7ed55e4..8885def 100644
--- a/poetry.lock
+++ b/poetry.lock
@@ -1,571 +1,529 @@
+# This file is automatically @generated by Poetry 1.5.1 and should not be changed by hand.
+
 [[package]]
 name = "addict"
 version = "2.4.0"
 description = "Addict is a dictionary whose items can be set using both attribute and item syntax."
-category = "dev"
 optional = false
 python-versions = "*"
+files = [
+    {file = "addict-2.4.0-py3-none-any.whl", hash = "sha256:249bb56bbfd3cdc2a004ea0ff4c2b6ddc84d53bc2194761636eb314d5cfa5dfc"},
+    {file = "addict-2.4.0.tar.gz", hash = "sha256:b3b2210e0e067a281f5646c8c5db92e99b7231ea8b0eb5f74dbdf9e259d4e494"},
+]
 
 [[package]]
 name = "aniso8601"
 version = "9.0.1"
 description = "A library for parsing ISO 8601 strings."
-category = "main"
 optional = false
 python-versions = "*"
+files = [
+    {file = "aniso8601-9.0.1-py2.py3-none-any.whl", hash = "sha256:1d2b7ef82963909e93c4f24ce48d4de9e66009a21bf1c1e1c85bdd0812fe412f"},
+    {file = "aniso8601-9.0.1.tar.gz", hash = "sha256:72e3117667eedf66951bb2d93f4296a56b94b078a8a95905a052611fb3f1b973"},
+]
 
 [package.extras]
 dev = ["black", "coverage", "isort", "pre-commit", "pyenchant", "pylint"]
 
 [[package]]
-name = "atomicwrites"
-version = "1.4.0"
-description = "Atomic file writes."
-category = "dev"
+name = "asgiref"
+version = "3.7.2"
+description = "ASGI specs, helper code, and adapters"
 optional = false
-python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
+python-versions = ">=3.7"
+files = [
+    {file = "asgiref-3.7.2-py3-none-any.whl", hash = "sha256:89b2ef2247e3b562a16eef663bc0e2e703ec6468e2fa8a5cd61cd449786d4f6e"},
+    {file = "asgiref-3.7.2.tar.gz", hash = "sha256:9e0ce3aa93a819ba5b45120216b23878cf6e8525eb3848653452b4192b92afed"},
+]
 
-[[package]]
-name = "attrs"
-version = "21.4.0"
-description = "Classes Without Boilerplate"
-category = "dev"
-optional = false
-python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
+[package.dependencies]
+typing-extensions = {version = ">=4", markers = "python_version < \"3.11\""}
 
 [package.extras]
-dev = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "mypy", "pytest-mypy-plugins", "zope.interface", "furo", "sphinx", "sphinx-notfound-page", "pre-commit", "cloudpickle"]
-docs = ["furo", "sphinx", "zope.interface", "sphinx-notfound-page"]
-tests = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "mypy", "pytest-mypy-plugins", "zope.interface", "cloudpickle"]
-tests_no_zope = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "mypy", "pytest-mypy-plugins", "cloudpickle"]
+tests = ["mypy (>=0.800)", "pytest", "pytest-asyncio"]
 
 [[package]]
 name = "colorama"
-version = "0.4.4"
+version = "0.4.6"
 description = "Cross-platform colored terminal text."
-category = "dev"
 optional = false
-python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
+python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7"
+files = [
+    {file = "colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"},
+    {file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"},
+]
 
 [[package]]
 name = "coverage"
-version = "6.2"
+version = "7.2.7"
 description = "Code coverage measurement for Python"
-category = "dev"
 optional = false
-python-versions = ">=3.6"
+python-versions = ">=3.7"
+files = [
+    {file = "coverage-7.2.7-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d39b5b4f2a66ccae8b7263ac3c8170994b65266797fb96cbbfd3fb5b23921db8"},
+    {file = "coverage-7.2.7-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:6d040ef7c9859bb11dfeb056ff5b3872436e3b5e401817d87a31e1750b9ae2fb"},
+    {file = "coverage-7.2.7-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ba90a9563ba44a72fda2e85302c3abc71c5589cea608ca16c22b9804262aaeb6"},
+    {file = "coverage-7.2.7-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e7d9405291c6928619403db1d10bd07888888ec1abcbd9748fdaa971d7d661b2"},
+    {file = "coverage-7.2.7-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:31563e97dae5598556600466ad9beea39fb04e0229e61c12eaa206e0aa202063"},
+    {file = "coverage-7.2.7-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:ebba1cd308ef115925421d3e6a586e655ca5a77b5bf41e02eb0e4562a111f2d1"},
+    {file = "coverage-7.2.7-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:cb017fd1b2603ef59e374ba2063f593abe0fc45f2ad9abdde5b4d83bd922a353"},
+    {file = "coverage-7.2.7-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:d62a5c7dad11015c66fbb9d881bc4caa5b12f16292f857842d9d1871595f4495"},
+    {file = "coverage-7.2.7-cp310-cp310-win32.whl", hash = "sha256:ee57190f24fba796e36bb6d3aa8a8783c643d8fa9760c89f7a98ab5455fbf818"},
+    {file = "coverage-7.2.7-cp310-cp310-win_amd64.whl", hash = "sha256:f75f7168ab25dd93110c8a8117a22450c19976afbc44234cbf71481094c1b850"},
+    {file = "coverage-7.2.7-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:06a9a2be0b5b576c3f18f1a241f0473575c4a26021b52b2a85263a00f034d51f"},
+    {file = "coverage-7.2.7-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:5baa06420f837184130752b7c5ea0808762083bf3487b5038d68b012e5937dbe"},
+    {file = "coverage-7.2.7-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fdec9e8cbf13a5bf63290fc6013d216a4c7232efb51548594ca3631a7f13c3a3"},
+    {file = "coverage-7.2.7-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:52edc1a60c0d34afa421c9c37078817b2e67a392cab17d97283b64c5833f427f"},
+    {file = "coverage-7.2.7-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:63426706118b7f5cf6bb6c895dc215d8a418d5952544042c8a2d9fe87fcf09cb"},
+    {file = "coverage-7.2.7-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:afb17f84d56068a7c29f5fa37bfd38d5aba69e3304af08ee94da8ed5b0865833"},
+    {file = "coverage-7.2.7-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:48c19d2159d433ccc99e729ceae7d5293fbffa0bdb94952d3579983d1c8c9d97"},
+    {file = "coverage-7.2.7-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:0e1f928eaf5469c11e886fe0885ad2bf1ec606434e79842a879277895a50942a"},
+    {file = "coverage-7.2.7-cp311-cp311-win32.whl", hash = "sha256:33d6d3ea29d5b3a1a632b3c4e4f4ecae24ef170b0b9ee493883f2df10039959a"},
+    {file = "coverage-7.2.7-cp311-cp311-win_amd64.whl", hash = "sha256:5b7540161790b2f28143191f5f8ec02fb132660ff175b7747b95dcb77ac26562"},
+    {file = "coverage-7.2.7-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:f2f67fe12b22cd130d34d0ef79206061bfb5eda52feb6ce0dba0644e20a03cf4"},
+    {file = "coverage-7.2.7-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a342242fe22407f3c17f4b499276a02b01e80f861f1682ad1d95b04018e0c0d4"},
+    {file = "coverage-7.2.7-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:171717c7cb6b453aebac9a2ef603699da237f341b38eebfee9be75d27dc38e01"},
+    {file = "coverage-7.2.7-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:49969a9f7ffa086d973d91cec8d2e31080436ef0fb4a359cae927e742abfaaa6"},
+    {file = "coverage-7.2.7-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:b46517c02ccd08092f4fa99f24c3b83d8f92f739b4657b0f146246a0ca6a831d"},
+    {file = "coverage-7.2.7-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:a3d33a6b3eae87ceaefa91ffdc130b5e8536182cd6dfdbfc1aa56b46ff8c86de"},
+    {file = "coverage-7.2.7-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:976b9c42fb2a43ebf304fa7d4a310e5f16cc99992f33eced91ef6f908bd8f33d"},
+    {file = "coverage-7.2.7-cp312-cp312-win32.whl", hash = "sha256:8de8bb0e5ad103888d65abef8bca41ab93721647590a3f740100cd65c3b00511"},
+    {file = "coverage-7.2.7-cp312-cp312-win_amd64.whl", hash = "sha256:9e31cb64d7de6b6f09702bb27c02d1904b3aebfca610c12772452c4e6c21a0d3"},
+    {file = "coverage-7.2.7-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:58c2ccc2f00ecb51253cbe5d8d7122a34590fac9646a960d1430d5b15321d95f"},
+    {file = "coverage-7.2.7-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d22656368f0e6189e24722214ed8d66b8022db19d182927b9a248a2a8a2f67eb"},
+    {file = "coverage-7.2.7-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a895fcc7b15c3fc72beb43cdcbdf0ddb7d2ebc959edac9cef390b0d14f39f8a9"},
+    {file = "coverage-7.2.7-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e84606b74eb7de6ff581a7915e2dab7a28a0517fbe1c9239eb227e1354064dcd"},
+    {file = "coverage-7.2.7-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:0a5f9e1dbd7fbe30196578ca36f3fba75376fb99888c395c5880b355e2875f8a"},
+    {file = "coverage-7.2.7-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:419bfd2caae268623dd469eff96d510a920c90928b60f2073d79f8fe2bbc5959"},
+    {file = "coverage-7.2.7-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:2aee274c46590717f38ae5e4650988d1af340fe06167546cc32fe2f58ed05b02"},
+    {file = "coverage-7.2.7-cp37-cp37m-win32.whl", hash = "sha256:61b9a528fb348373c433e8966535074b802c7a5d7f23c4f421e6c6e2f1697a6f"},
+    {file = "coverage-7.2.7-cp37-cp37m-win_amd64.whl", hash = "sha256:b1c546aca0ca4d028901d825015dc8e4d56aac4b541877690eb76490f1dc8ed0"},
+    {file = "coverage-7.2.7-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:54b896376ab563bd38453cecb813c295cf347cf5906e8b41d340b0321a5433e5"},
+    {file = "coverage-7.2.7-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:3d376df58cc111dc8e21e3b6e24606b5bb5dee6024f46a5abca99124b2229ef5"},
+    {file = "coverage-7.2.7-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5e330fc79bd7207e46c7d7fd2bb4af2963f5f635703925543a70b99574b0fea9"},
+    {file = "coverage-7.2.7-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1e9d683426464e4a252bf70c3498756055016f99ddaec3774bf368e76bbe02b6"},
+    {file = "coverage-7.2.7-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8d13c64ee2d33eccf7437961b6ea7ad8673e2be040b4f7fd4fd4d4d28d9ccb1e"},
+    {file = "coverage-7.2.7-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:b7aa5f8a41217360e600da646004f878250a0d6738bcdc11a0a39928d7dc2050"},
+    {file = "coverage-7.2.7-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:8fa03bce9bfbeeef9f3b160a8bed39a221d82308b4152b27d82d8daa7041fee5"},
+    {file = "coverage-7.2.7-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:245167dd26180ab4c91d5e1496a30be4cd721a5cf2abf52974f965f10f11419f"},
+    {file = "coverage-7.2.7-cp38-cp38-win32.whl", hash = "sha256:d2c2db7fd82e9b72937969bceac4d6ca89660db0a0967614ce2481e81a0b771e"},
+    {file = "coverage-7.2.7-cp38-cp38-win_amd64.whl", hash = "sha256:2e07b54284e381531c87f785f613b833569c14ecacdcb85d56b25c4622c16c3c"},
+    {file = "coverage-7.2.7-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:537891ae8ce59ef63d0123f7ac9e2ae0fc8b72c7ccbe5296fec45fd68967b6c9"},
+    {file = "coverage-7.2.7-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:06fb182e69f33f6cd1d39a6c597294cff3143554b64b9825d1dc69d18cc2fff2"},
+    {file = "coverage-7.2.7-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:201e7389591af40950a6480bd9edfa8ed04346ff80002cec1a66cac4549c1ad7"},
+    {file = "coverage-7.2.7-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f6951407391b639504e3b3be51b7ba5f3528adbf1a8ac3302b687ecababf929e"},
+    {file = "coverage-7.2.7-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6f48351d66575f535669306aa7d6d6f71bc43372473b54a832222803eb956fd1"},
+    {file = "coverage-7.2.7-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:b29019c76039dc3c0fd815c41392a044ce555d9bcdd38b0fb60fb4cd8e475ba9"},
+    {file = "coverage-7.2.7-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:81c13a1fc7468c40f13420732805a4c38a105d89848b7c10af65a90beff25250"},
+    {file = "coverage-7.2.7-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:975d70ab7e3c80a3fe86001d8751f6778905ec723f5b110aed1e450da9d4b7f2"},
+    {file = "coverage-7.2.7-cp39-cp39-win32.whl", hash = "sha256:7ee7d9d4822c8acc74a5e26c50604dff824710bc8de424904c0982e25c39c6cb"},
+    {file = "coverage-7.2.7-cp39-cp39-win_amd64.whl", hash = "sha256:eb393e5ebc85245347950143969b241d08b52b88a3dc39479822e073a1a8eb27"},
+    {file = "coverage-7.2.7-pp37.pp38.pp39-none-any.whl", hash = "sha256:b7b4c971f05e6ae490fef852c218b0e79d4e52f79ef0c8475566584a8fb3e01d"},
+    {file = "coverage-7.2.7.tar.gz", hash = "sha256:924d94291ca674905fe9481f12294eb11f2d3d3fd1adb20314ba89e94f44ed59"},
+]
+
+[package.dependencies]
+tomli = {version = "*", optional = true, markers = "python_full_version <= \"3.11.0a6\" and extra == \"toml\""}
 
 [package.extras]
 toml = ["tomli"]
 
 [[package]]
 name = "django"
-version = "2.2.27"
+version = "3.2.19"
 description = "A high-level Python Web framework that encourages rapid development and clean, pragmatic design."
-category = "main"
 optional = false
-python-versions = ">=3.5"
+python-versions = ">=3.6"
+files = [
+    {file = "Django-3.2.19-py3-none-any.whl", hash = "sha256:21cc991466245d659ab79cb01204f9515690f8dae00e5eabde307f14d24d4d7d"},
+    {file = "Django-3.2.19.tar.gz", hash = "sha256:031365bae96814da19c10706218c44dff3b654cc4de20a98bd2d29b9bde469f0"},
+]
 
 [package.dependencies]
+asgiref = ">=3.3.2,<4"
 pytz = "*"
 sqlparse = ">=0.2.2"
 
 [package.extras]
-argon2 = ["argon2-cffi (>=16.1.0)"]
+argon2 = ["argon2-cffi (>=19.1.0)"]
 bcrypt = ["bcrypt"]
 
+[[package]]
+name = "exceptiongroup"
+version = "1.1.1"
+description = "Backport of PEP 654 (exception groups)"
+optional = false
+python-versions = ">=3.7"
+files = [
+    {file = "exceptiongroup-1.1.1-py3-none-any.whl", hash = "sha256:232c37c63e4f682982c8b6459f33a8981039e5fb8756b2074364e5055c498c9e"},
+    {file = "exceptiongroup-1.1.1.tar.gz", hash = "sha256:d484c3090ba2889ae2928419117447a14daf3c1231d5e30d0aae34f354f01785"},
+]
+
+[package.extras]
+test = ["pytest (>=6)"]
+
 [[package]]
 name = "factory-boy"
-version = "2.12.0"
+version = "3.2.1"
 description = "A versatile test fixtures replacement based on thoughtbot's factory_bot for Ruby."
-category = "dev"
 optional = false
-python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
+python-versions = ">=3.6"
+files = [
+    {file = "factory_boy-3.2.1-py2.py3-none-any.whl", hash = "sha256:eb02a7dd1b577ef606b75a253b9818e6f9eaf996d94449c9d5ebb124f90dc795"},
+    {file = "factory_boy-3.2.1.tar.gz", hash = "sha256:a98d277b0c047c75eb6e4ab8508a7f81fb03d2cb21986f627913546ef7a2a55e"},
+]
 
 [package.dependencies]
 Faker = ">=0.7.0"
 
+[package.extras]
+dev = ["Django", "Pillow", "SQLAlchemy", "coverage", "flake8", "isort", "mongoengine", "tox", "wheel (>=0.32.0)", "zest.releaser[recommended]"]
+doc = ["Sphinx", "sphinx-rtd-theme", "sphinxcontrib-spelling"]
+
 [[package]]
 name = "faker"
-version = "13.3.1"
+version = "18.11.2"
 description = "Faker is a Python package that generates fake data for you."
-category = "dev"
 optional = false
-python-versions = ">=3.6"
+python-versions = ">=3.7"
+files = [
+    {file = "Faker-18.11.2-py3-none-any.whl", hash = "sha256:21c2c29638e98502f3bba9ad6a4f07a4b09c5e2150bb491ff02411a5888f6955"},
+    {file = "Faker-18.11.2.tar.gz", hash = "sha256:ec6e2824bb1d3546b36c156324b9df6bca5a3d6d03adf991e6a5586756dcab9d"},
+]
 
 [package.dependencies]
 python-dateutil = ">=2.4"
-typing-extensions = {version = ">=3.10.0.2", markers = "python_version < \"3.8\""}
+typing-extensions = {version = ">=3.10.0.1", markers = "python_version < \"3.8\""}
 
 [[package]]
 name = "graphene"
-version = "3.0"
+version = "3.2.2"
 description = "GraphQL Framework for Python"
-category = "main"
 optional = false
 python-versions = "*"
+files = [
+    {file = "graphene-3.2.2-py2.py3-none-any.whl", hash = "sha256:753de13948cbf42e32cc87fb533167c88907066eb984251fdbb006c0aab8da00"},
+    {file = "graphene-3.2.2.tar.gz", hash = "sha256:5b03e72770dc901f40be55784058d6bb1d952a49eb819a4a085962d5e1cf5fcf"},
+]
 
 [package.dependencies]
 aniso8601 = ">=8,<10"
-graphql-core = ">=3.1.2,<3.2.0"
-graphql-relay = ">=3.0,<4"
+graphql-core = ">=3.1,<3.3"
+graphql-relay = ">=3.1,<3.3"
 
 [package.extras]
-dev = ["black (==19.10b0)", "flake8 (>=3.7,<4)", "pytest (>=5.3,<6)", "pytest-benchmark (>=3.2,<4)", "pytest-cov (>=2.8,<3)", "pytest-mock (>=2,<3)", "pytest-asyncio (>=0.10,<2)", "snapshottest (>=0.5,<1)", "coveralls (>=1.11,<2)", "promise (>=2.3,<3)", "mock (>=4.0,<5)", "pytz (==2021.1)", "iso8601 (>=0.1,<2)"]
-test = ["pytest (>=5.3,<6)", "pytest-benchmark (>=3.2,<4)", "pytest-cov (>=2.8,<3)", "pytest-mock (>=2,<3)", "pytest-asyncio (>=0.10,<2)", "snapshottest (>=0.5,<1)", "coveralls (>=1.11,<2)", "promise (>=2.3,<3)", "mock (>=4.0,<5)", "pytz (==2021.1)", "iso8601 (>=0.1,<2)"]
+dev = ["black (==22.3.0)", "coveralls (>=3.3,<4)", "flake8 (>=4,<5)", "iso8601 (>=1,<2)", "mock (>=4,<5)", "pytest (>=6,<7)", "pytest-asyncio (>=0.16,<2)", "pytest-benchmark (>=3.4,<4)", "pytest-cov (>=3,<4)", "pytest-mock (>=3,<4)", "pytz (==2022.1)", "snapshottest (>=0.6,<1)"]
+test = ["coveralls (>=3.3,<4)", "iso8601 (>=1,<2)", "mock (>=4,<5)", "pytest (>=6,<7)", "pytest-asyncio (>=0.16,<2)", "pytest-benchmark (>=3.4,<4)", "pytest-cov (>=3,<4)", "pytest-mock (>=3,<4)", "pytz (==2022.1)", "snapshottest (>=0.6,<1)"]
 
 [[package]]
 name = "graphene-django"
-version = "3.0.0b7"
+version = "3.1.2"
 description = "Graphene Django integration"
-category = "main"
 optional = false
 python-versions = "*"
+files = [
+    {file = "graphene-django-3.1.2.tar.gz", hash = "sha256:f12cce91d516d4e23aa0cf46c1faed031adea09254534a6a5afbd29f3268e68a"},
+    {file = "graphene_django-3.1.2-py2.py3-none-any.whl", hash = "sha256:ef4eb21c4e1c98f933ae4335fd6d2bbacfdab1aa8785f1f0cb308716821c5fa2"},
+]
 
 [package.dependencies]
-Django = ">=2.2"
-graphene = ">=3.0.0b5,<4"
+Django = ">=3.2"
+graphene = ">=3.0,<4"
 graphql-core = ">=3.1.0,<4"
+graphql-relay = ">=3.1.1,<4"
 promise = ">=2.1"
 text-unidecode = "*"
 
 [package.extras]
-dev = ["black (==19.10b0)", "flake8 (==3.7.9)", "flake8-black (==0.1.1)", "flake8-bugbear (==20.1.4)", "pytest (>=3.6.3)", "pytest-cov", "pytest-random-order", "coveralls", "mock", "pytz", "django-filter (>=2)", "pytest-django (>=3.3.2)", "djangorestframework (>=3.6.3)"]
-rest_framework = ["djangorestframework (>=3.6.3)"]
-test = ["pytest (>=3.6.3)", "pytest-cov", "pytest-random-order", "coveralls", "mock", "pytz", "django-filter (>=2)", "pytest-django (>=3.3.2)", "djangorestframework (>=3.6.3)"]
+dev = ["black (==23.3.0)", "coveralls", "django-filter (>=22.1)", "djangorestframework (>=3.6.3)", "flake8 (==6.0.0)", "flake8-black (==0.3.6)", "flake8-bugbear (==23.3.23)", "mock", "pre-commit", "pytest (>=7.3.1)", "pytest-cov", "pytest-django (>=4.5.2)", "pytest-random-order", "pytz"]
+rest-framework = ["djangorestframework (>=3.6.3)"]
+test = ["coveralls", "django-filter (>=22.1)", "djangorestframework (>=3.6.3)", "mock", "pytest (>=7.3.1)", "pytest-cov", "pytest-django (>=4.5.2)", "pytest-random-order", "pytz"]
 
 [[package]]
 name = "graphene-file-upload"
 version = "1.3.0"
 description = "Lib for adding file upload functionality to GraphQL mutations in Graphene Django and Flask-Graphql"
-category = "main"
 optional = false
 python-versions = "*"
+files = [
+    {file = "graphene_file_upload-1.3.0-py3-none-any.whl", hash = "sha256:5afe50f409f50e3d198fd92c883d98d868e6c6aaadf5df3a3f4d88ecad90ed97"},
+    {file = "graphene_file_upload-1.3.0.tar.gz", hash = "sha256:6898480b0556826472c80971032917c01968ade5800d84054008fe598795b063"},
+]
 
 [package.dependencies]
 six = ">=1.11.0"
 
 [package.extras]
-all = ["Flask (>=1.0.2)", "graphene (>=2.1.2)", "Flask-Graphql (>=2.0.0)", "graphene-django (>=2.0.0)"]
+all = ["Flask (>=1.0.2)", "Flask-Graphql (>=2.0.0)", "graphene (>=2.1.2)", "graphene-django (>=2.0.0)"]
 django = ["graphene-django (>=2.0.0)"]
-flask = ["Flask (>=1.0.2)", "graphene (>=2.1.2)", "Flask-Graphql (>=2.0.0)"]
+flask = ["Flask (>=1.0.2)", "Flask-Graphql (>=2.0.0)", "graphene (>=2.1.2)"]
 tests = ["coverage", "pytest", "pytest-cov", "pytest-django"]
 
 [[package]]
 name = "graphql-core"
-version = "3.1.7"
+version = "3.2.3"
 description = "GraphQL implementation for Python, a port of GraphQL.js, the JavaScript reference implementation for GraphQL."
-category = "main"
 optional = false
 python-versions = ">=3.6,<4"
+files = [
+    {file = "graphql-core-3.2.3.tar.gz", hash = "sha256:06d2aad0ac723e35b1cb47885d3e5c45e956a53bc1b209a9fc5369007fe46676"},
+    {file = "graphql_core-3.2.3-py3-none-any.whl", hash = "sha256:5766780452bd5ec8ba133f8bf287dc92713e3868ddd83aee4faab9fc3e303dc3"},
+]
+
+[package.dependencies]
+typing-extensions = {version = ">=4.2,<5", markers = "python_version < \"3.8\""}
 
 [[package]]
 name = "graphql-relay"
-version = "3.1.5"
+version = "3.2.0"
 description = "Relay library for graphql-core"
-category = "main"
 optional = false
 python-versions = ">=3.6,<4"
+files = [
+    {file = "graphql-relay-3.2.0.tar.gz", hash = "sha256:1ff1c51298356e481a0be009ccdff249832ce53f30559c1338f22a0e0d17250c"},
+    {file = "graphql_relay-3.2.0-py3-none-any.whl", hash = "sha256:c9b22bd28b170ba1fe674c74384a8ff30a76c8e26f88ac3aa1584dd3179953e5"},
+]
 
 [package.dependencies]
-graphql-core = ">=3.1,<3.2"
-typing-extensions = {version = ">=4,<5", markers = "python_version < \"3.8\""}
+graphql-core = ">=3.2,<3.3"
+typing-extensions = {version = ">=4.1,<5", markers = "python_version < \"3.8\""}
 
 [[package]]
 name = "importlib-metadata"
-version = "4.8.3"
+version = "6.7.0"
 description = "Read metadata from Python packages"
-category = "dev"
 optional = false
-python-versions = ">=3.6"
+python-versions = ">=3.7"
+files = [
+    {file = "importlib_metadata-6.7.0-py3-none-any.whl", hash = "sha256:cb52082e659e97afc5dac71e79de97d8681de3aa07ff18578330904a9d18e5b5"},
+    {file = "importlib_metadata-6.7.0.tar.gz", hash = "sha256:1aaf550d4f73e5d6783e7acb77aec43d49da8017410afae93822cc9cca98c4d4"},
+]
 
 [package.dependencies]
 typing-extensions = {version = ">=3.6.4", markers = "python_version < \"3.8\""}
 zipp = ">=0.5"
 
 [package.extras]
-docs = ["sphinx", "jaraco.packaging (>=8.2)", "rst.linker (>=1.9)"]
+docs = ["furo", "jaraco.packaging (>=9)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"]
 perf = ["ipython"]
-testing = ["pytest (>=6)", "pytest-checkdocs (>=2.4)", "pytest-flake8", "pytest-cov", "pytest-enabler (>=1.0.1)", "packaging", "pep517", "pyfakefs", "flufl.flake8", "pytest-perf (>=0.9.2)", "pytest-black (>=0.3.7)", "pytest-mypy", "importlib-resources (>=1.3)"]
+testing = ["flufl.flake8", "importlib-resources (>=1.3)", "packaging", "pyfakefs", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=1.3)", "pytest-mypy (>=0.9.1)", "pytest-perf (>=0.9.2)", "pytest-ruff"]
 
 [[package]]
-name = "more-itertools"
-version = "8.12.0"
-description = "More routines for operating on iterables, beyond itertools"
-category = "dev"
+name = "iniconfig"
+version = "2.0.0"
+description = "brain-dead simple config-ini parsing"
 optional = false
-python-versions = ">=3.5"
+python-versions = ">=3.7"
+files = [
+    {file = "iniconfig-2.0.0-py3-none-any.whl", hash = "sha256:b6a85871a79d2e3b22d2d1b94ac2824226a63c6b741c88f7ae975f18b6778374"},
+    {file = "iniconfig-2.0.0.tar.gz", hash = "sha256:2d91e135bf72d31a410b17c16da610a82cb55f6b0477d1a902134b24a455b8b3"},
+]
 
 [[package]]
 name = "packaging"
-version = "21.3"
+version = "23.1"
 description = "Core utilities for Python packages"
-category = "dev"
 optional = false
-python-versions = ">=3.6"
-
-[package.dependencies]
-pyparsing = ">=2.0.2,<3.0.5 || >3.0.5"
+python-versions = ">=3.7"
+files = [
+    {file = "packaging-23.1-py3-none-any.whl", hash = "sha256:994793af429502c4ea2ebf6bf664629d07c1a9fe974af92966e4b8d2df7edc61"},
+    {file = "packaging-23.1.tar.gz", hash = "sha256:a392980d2b6cffa644431898be54b0045151319d1e7ec34f0cfed48767dd334f"},
+]
 
 [[package]]
 name = "pluggy"
-version = "0.13.1"
+version = "1.2.0"
 description = "plugin and hook calling mechanisms for python"
-category = "dev"
 optional = false
-python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
+python-versions = ">=3.7"
+files = [
+    {file = "pluggy-1.2.0-py3-none-any.whl", hash = "sha256:c2fd55a7d7a3863cba1a013e4e2414658b1d07b6bc57b3919e0c63c9abb99849"},
+    {file = "pluggy-1.2.0.tar.gz", hash = "sha256:d12f0c4b579b15f5e054301bb226ee85eeeba08ffec228092f8defbaa3a4c4b3"},
+]
 
 [package.dependencies]
 importlib-metadata = {version = ">=0.12", markers = "python_version < \"3.8\""}
 
 [package.extras]
 dev = ["pre-commit", "tox"]
+testing = ["pytest", "pytest-benchmark"]
 
 [[package]]
 name = "promise"
 version = "2.3"
 description = "Promises/A+ implementation for Python"
-category = "main"
 optional = false
 python-versions = "*"
+files = [
+    {file = "promise-2.3.tar.gz", hash = "sha256:dfd18337c523ba4b6a58801c164c1904a9d4d1b1747c7d5dbf45b693a49d93d0"},
+]
 
 [package.dependencies]
 six = "*"
 
 [package.extras]
-test = ["pytest (>=2.7.3)", "pytest-cov", "coveralls", "futures", "pytest-benchmark", "mock"]
-
-[[package]]
-name = "py"
-version = "1.11.0"
-description = "library with cross-python path, ini-parsing, io, code, log facilities"
-category = "dev"
-optional = false
-python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
-
-[[package]]
-name = "pyparsing"
-version = "3.0.7"
-description = "Python parsing module"
-category = "dev"
-optional = false
-python-versions = ">=3.6"
-
-[package.extras]
-diagrams = ["jinja2", "railroad-diagrams"]
+test = ["coveralls", "futures", "mock", "pytest (>=2.7.3)", "pytest-benchmark", "pytest-cov"]
 
 [[package]]
 name = "pytest"
-version = "5.4.3"
+version = "7.4.0"
 description = "pytest: simple powerful testing with Python"
-category = "dev"
 optional = false
-python-versions = ">=3.5"
+python-versions = ">=3.7"
+files = [
+    {file = "pytest-7.4.0-py3-none-any.whl", hash = "sha256:78bf16451a2eb8c7a2ea98e32dc119fd2aa758f1d5d66dbf0a59d69a3969df32"},
+    {file = "pytest-7.4.0.tar.gz", hash = "sha256:b4bf8c45bd59934ed84001ad51e11b4ee40d40a1229d2c79f9c592b0a3f6bd8a"},
+]
 
 [package.dependencies]
-atomicwrites = {version = ">=1.0", markers = "sys_platform == \"win32\""}
-attrs = ">=17.4.0"
 colorama = {version = "*", markers = "sys_platform == \"win32\""}
+exceptiongroup = {version = ">=1.0.0rc8", markers = "python_version < \"3.11\""}
 importlib-metadata = {version = ">=0.12", markers = "python_version < \"3.8\""}
-more-itertools = ">=4.0.0"
+iniconfig = "*"
 packaging = "*"
-pluggy = ">=0.12,<1.0"
-py = ">=1.5.0"
-wcwidth = "*"
+pluggy = ">=0.12,<2.0"
+tomli = {version = ">=1.0.0", markers = "python_version < \"3.11\""}
 
 [package.extras]
-checkqa-mypy = ["mypy (==v0.761)"]
-testing = ["argcomplete", "hypothesis (>=3.56)", "mock", "nose", "requests", "xmlschema"]
+testing = ["argcomplete", "attrs (>=19.2.0)", "hypothesis (>=3.56)", "mock", "nose", "pygments (>=2.7.2)", "requests", "setuptools", "xmlschema"]
 
 [[package]]
 name = "pytest-cov"
-version = "2.12.1"
+version = "4.1.0"
 description = "Pytest plugin for measuring coverage."
-category = "dev"
 optional = false
-python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
+python-versions = ">=3.7"
+files = [
+    {file = "pytest-cov-4.1.0.tar.gz", hash = "sha256:3904b13dfbfec47f003b8e77fd5b589cd11904a21ddf1ab38a64f204d6a10ef6"},
+    {file = "pytest_cov-4.1.0-py3-none-any.whl", hash = "sha256:6ba70b9e97e69fcc3fb45bfeab2d0a138fb65c4d0d6a41ef33983ad114be8c3a"},
+]
 
 [package.dependencies]
-coverage = ">=5.2.1"
+coverage = {version = ">=5.2.1", extras = ["toml"]}
 pytest = ">=4.6"
-toml = "*"
 
 [package.extras]
-testing = ["fields", "hunter", "process-tests", "six", "pytest-xdist", "virtualenv"]
+testing = ["fields", "hunter", "process-tests", "pytest-xdist", "six", "virtualenv"]
 
 [[package]]
 name = "pytest-django"
-version = "3.10.0"
+version = "4.5.2"
 description = "A Django plugin for pytest."
-category = "dev"
 optional = false
-python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
+python-versions = ">=3.5"
+files = [
+    {file = "pytest-django-4.5.2.tar.gz", hash = "sha256:d9076f759bb7c36939dbdd5ae6633c18edfc2902d1a69fdbefd2426b970ce6c2"},
+    {file = "pytest_django-4.5.2-py3-none-any.whl", hash = "sha256:c60834861933773109334fe5a53e83d1ef4828f2203a1d6a0fa9972f4f75ab3e"},
+]
 
 [package.dependencies]
-pytest = ">=3.6"
+pytest = ">=5.4.0"
 
 [package.extras]
 docs = ["sphinx", "sphinx-rtd-theme"]
-testing = ["django", "django-configurations (>=2.0)", "six"]
+testing = ["Django", "django-configurations (>=2.0)"]
 
 [[package]]
 name = "python-dateutil"
 version = "2.8.2"
 description = "Extensions to the standard Python datetime module"
-category = "dev"
 optional = false
 python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7"
+files = [
+    {file = "python-dateutil-2.8.2.tar.gz", hash = "sha256:0123cacc1627ae19ddf3c27a5de5bd67ee4586fbdd6440d9748f8abb483d3e86"},
+    {file = "python_dateutil-2.8.2-py2.py3-none-any.whl", hash = "sha256:961d03dc3453ebbc59dbdea9e4e11c5651520a876d0f4db161e8674aae935da9"},
+]
 
 [package.dependencies]
 six = ">=1.5"
 
 [[package]]
 name = "pytz"
-version = "2021.3"
+version = "2023.3"
 description = "World timezone definitions, modern and historical"
-category = "main"
 optional = false
 python-versions = "*"
+files = [
+    {file = "pytz-2023.3-py2.py3-none-any.whl", hash = "sha256:a151b3abb88eda1d4e34a9814df37de2a80e301e68ba0fd856fb9b46bfbbbffb"},
+    {file = "pytz-2023.3.tar.gz", hash = "sha256:1d8ce29db189191fb55338ee6d0387d82ab59f3d00eac103412d64e0ebd0c588"},
+]
 
 [[package]]
 name = "six"
 version = "1.16.0"
 description = "Python 2 and 3 compatibility utilities"
-category = "main"
 optional = false
 python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*"
+files = [
+    {file = "six-1.16.0-py2.py3-none-any.whl", hash = "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"},
+    {file = "six-1.16.0.tar.gz", hash = "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926"},
+]
 
 [[package]]
 name = "sqlparse"
-version = "0.4.2"
+version = "0.4.4"
 description = "A non-validating SQL parser."
-category = "main"
 optional = false
 python-versions = ">=3.5"
+files = [
+    {file = "sqlparse-0.4.4-py3-none-any.whl", hash = "sha256:5430a4fe2ac7d0f93e66f1efc6e1338a41884b7ddf2a350cedd20ccc4d9d28f3"},
+    {file = "sqlparse-0.4.4.tar.gz", hash = "sha256:d446183e84b8349fa3061f0fe7f06ca94ba65b426946ffebe6e3e8295332420c"},
+]
+
+[package.extras]
+dev = ["build", "flake8"]
+doc = ["sphinx"]
+test = ["pytest", "pytest-cov"]
 
 [[package]]
 name = "text-unidecode"
 version = "1.3"
 description = "The most basic Text::Unidecode port"
-category = "main"
 optional = false
 python-versions = "*"
+files = [
+    {file = "text-unidecode-1.3.tar.gz", hash = "sha256:bad6603bb14d279193107714b288be206cac565dfa49aa5b105294dd5c4aab93"},
+    {file = "text_unidecode-1.3-py2.py3-none-any.whl", hash = "sha256:1311f10e8b895935241623731c2ba64f4c455287888b18189350b67134a822e8"},
+]
 
 [[package]]
-name = "toml"
-version = "0.10.2"
-description = "Python Library for Tom's Obvious, Minimal Language"
-category = "dev"
+name = "tomli"
+version = "2.0.1"
+description = "A lil' TOML parser"
 optional = false
-python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*"
+python-versions = ">=3.7"
+files = [
+    {file = "tomli-2.0.1-py3-none-any.whl", hash = "sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc"},
+    {file = "tomli-2.0.1.tar.gz", hash = "sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f"},
+]
 
 [[package]]
 name = "typing-extensions"
-version = "4.1.1"
-description = "Backported and Experimental Type Hints for Python 3.6+"
-category = "main"
-optional = false
-python-versions = ">=3.6"
-
-[[package]]
-name = "wcwidth"
-version = "0.2.5"
-description = "Measures the displayed width of unicode strings in a terminal"
-category = "dev"
+version = "4.7.0"
+description = "Backported and Experimental Type Hints for Python 3.7+"
 optional = false
-python-versions = "*"
+python-versions = ">=3.7"
+files = [
+    {file = "typing_extensions-4.7.0-py3-none-any.whl", hash = "sha256:5d8c9dac95c27d20df12fb1d97b9793ab8b2af8a3a525e68c80e21060c161771"},
+    {file = "typing_extensions-4.7.0.tar.gz", hash = "sha256:935ccf31549830cda708b42289d44b6f74084d616a00be651601a4f968e77c82"},
+]
 
 [[package]]
 name = "zipp"
-version = "3.6.0"
+version = "3.15.0"
 description = "Backport of pathlib-compatible object wrapper for zip files"
-category = "dev"
 optional = false
-python-versions = ">=3.6"
+python-versions = ">=3.7"
+files = [
+    {file = "zipp-3.15.0-py3-none-any.whl", hash = "sha256:48904fc76a60e542af151aded95726c1a5c34ed43ab4134b597665c86d7ad556"},
+    {file = "zipp-3.15.0.tar.gz", hash = "sha256:112929ad649da941c23de50f356a2b5570c954b65150642bccdd66bf194d224b"},
+]
 
 [package.extras]
-docs = ["sphinx", "jaraco.packaging (>=8.2)", "rst.linker (>=1.9)"]
-testing = ["pytest (>=4.6)", "pytest-checkdocs (>=2.4)", "pytest-flake8", "pytest-cov", "pytest-enabler (>=1.0.1)", "jaraco.itertools", "func-timeout", "pytest-black (>=0.3.7)", "pytest-mypy"]
+docs = ["furo", "jaraco.packaging (>=9)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"]
+testing = ["big-O", "flake8 (<5)", "jaraco.functools", "jaraco.itertools", "more-itertools", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=1.3)", "pytest-flake8", "pytest-mypy (>=0.9.1)"]
 
 [metadata]
-lock-version = "1.1"
-python-versions = "^3.6"
-content-hash = "4bd0181f28757238e172111f7a62abff07a9e306bc09c0bae8a18d684332f81f"
-
-[metadata.files]
-addict = [
-    {file = "addict-2.4.0-py3-none-any.whl", hash = "sha256:249bb56bbfd3cdc2a004ea0ff4c2b6ddc84d53bc2194761636eb314d5cfa5dfc"},
-    {file = "addict-2.4.0.tar.gz", hash = "sha256:b3b2210e0e067a281f5646c8c5db92e99b7231ea8b0eb5f74dbdf9e259d4e494"},
-]
-aniso8601 = [
-    {file = "aniso8601-9.0.1-py2.py3-none-any.whl", hash = "sha256:1d2b7ef82963909e93c4f24ce48d4de9e66009a21bf1c1e1c85bdd0812fe412f"},
-    {file = "aniso8601-9.0.1.tar.gz", hash = "sha256:72e3117667eedf66951bb2d93f4296a56b94b078a8a95905a052611fb3f1b973"},
-]
-atomicwrites = [
-    {file = "atomicwrites-1.4.0-py2.py3-none-any.whl", hash = "sha256:6d1784dea7c0c8d4a5172b6c620f40b6e4cbfdf96d783691f2e1302a7b88e197"},
-    {file = "atomicwrites-1.4.0.tar.gz", hash = "sha256:ae70396ad1a434f9c7046fd2dd196fc04b12f9e91ffb859164193be8b6168a7a"},
-]
-attrs = [
-    {file = "attrs-21.4.0-py2.py3-none-any.whl", hash = "sha256:2d27e3784d7a565d36ab851fe94887c5eccd6a463168875832a1be79c82828b4"},
-    {file = "attrs-21.4.0.tar.gz", hash = "sha256:626ba8234211db98e869df76230a137c4c40a12d72445c45d5f5b716f076e2fd"},
-]
-colorama = [
-    {file = "colorama-0.4.4-py2.py3-none-any.whl", hash = "sha256:9f47eda37229f68eee03b24b9748937c7dc3868f906e8ba69fbcbdd3bc5dc3e2"},
-    {file = "colorama-0.4.4.tar.gz", hash = "sha256:5941b2b48a20143d2267e95b1c2a7603ce057ee39fd88e7329b0c292aa16869b"},
-]
-coverage = [
-    {file = "coverage-6.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:6dbc1536e105adda7a6312c778f15aaabe583b0e9a0b0a324990334fd458c94b"},
-    {file = "coverage-6.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:174cf9b4bef0db2e8244f82059a5a72bd47e1d40e71c68ab055425172b16b7d0"},
-    {file = "coverage-6.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:92b8c845527eae547a2a6617d336adc56394050c3ed8a6918683646328fbb6da"},
-    {file = "coverage-6.2-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:c7912d1526299cb04c88288e148c6c87c0df600eca76efd99d84396cfe00ef1d"},
-    {file = "coverage-6.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:d5d2033d5db1d58ae2d62f095e1aefb6988af65b4b12cb8987af409587cc0739"},
-    {file = "coverage-6.2-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:3feac4084291642165c3a0d9eaebedf19ffa505016c4d3db15bfe235718d4971"},
-    {file = "coverage-6.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:276651978c94a8c5672ea60a2656e95a3cce2a3f31e9fb2d5ebd4c215d095840"},
-    {file = "coverage-6.2-cp310-cp310-win32.whl", hash = "sha256:f506af4f27def639ba45789fa6fde45f9a217da0be05f8910458e4557eed020c"},
-    {file = "coverage-6.2-cp310-cp310-win_amd64.whl", hash = "sha256:3f7c17209eef285c86f819ff04a6d4cbee9b33ef05cbcaae4c0b4e8e06b3ec8f"},
-    {file = "coverage-6.2-cp311-cp311-macosx_10_14_x86_64.whl", hash = "sha256:13362889b2d46e8d9f97c421539c97c963e34031ab0cb89e8ca83a10cc71ac76"},
-    {file = "coverage-6.2-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:22e60a3ca5acba37d1d4a2ee66e051f5b0e1b9ac950b5b0cf4aa5366eda41d47"},
-    {file = "coverage-6.2-cp311-cp311-win_amd64.whl", hash = "sha256:b637c57fdb8be84e91fac60d9325a66a5981f8086c954ea2772efe28425eaf64"},
-    {file = "coverage-6.2-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:f467bbb837691ab5a8ca359199d3429a11a01e6dfb3d9dcc676dc035ca93c0a9"},
-    {file = "coverage-6.2-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2641f803ee9f95b1f387f3e8f3bf28d83d9b69a39e9911e5bfee832bea75240d"},
-    {file = "coverage-6.2-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:1219d760ccfafc03c0822ae2e06e3b1248a8e6d1a70928966bafc6838d3c9e48"},
-    {file = "coverage-6.2-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:9a2b5b52be0a8626fcbffd7e689781bf8c2ac01613e77feda93d96184949a98e"},
-    {file = "coverage-6.2-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:8e2c35a4c1f269704e90888e56f794e2d9c0262fb0c1b1c8c4ee44d9b9e77b5d"},
-    {file = "coverage-6.2-cp36-cp36m-musllinux_1_1_i686.whl", hash = "sha256:5d6b09c972ce9200264c35a1d53d43ca55ef61836d9ec60f0d44273a31aa9f17"},
-    {file = "coverage-6.2-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:e3db840a4dee542e37e09f30859f1612da90e1c5239a6a2498c473183a50e781"},
-    {file = "coverage-6.2-cp36-cp36m-win32.whl", hash = "sha256:4e547122ca2d244f7c090fe3f4b5a5861255ff66b7ab6d98f44a0222aaf8671a"},
-    {file = "coverage-6.2-cp36-cp36m-win_amd64.whl", hash = "sha256:01774a2c2c729619760320270e42cd9e797427ecfddd32c2a7b639cdc481f3c0"},
-    {file = "coverage-6.2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:fb8b8ee99b3fffe4fd86f4c81b35a6bf7e4462cba019997af2fe679365db0c49"},
-    {file = "coverage-6.2-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:619346d57c7126ae49ac95b11b0dc8e36c1dd49d148477461bb66c8cf13bb521"},
-    {file = "coverage-6.2-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:0a7726f74ff63f41e95ed3a89fef002916c828bb5fcae83b505b49d81a066884"},
-    {file = "coverage-6.2-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:cfd9386c1d6f13b37e05a91a8583e802f8059bebfccde61a418c5808dea6bbfa"},
-    {file = "coverage-6.2-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:17e6c11038d4ed6e8af1407d9e89a2904d573be29d51515f14262d7f10ef0a64"},
-    {file = "coverage-6.2-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:c254b03032d5a06de049ce8bca8338a5185f07fb76600afff3c161e053d88617"},
-    {file = "coverage-6.2-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:dca38a21e4423f3edb821292e97cec7ad38086f84313462098568baedf4331f8"},
-    {file = "coverage-6.2-cp37-cp37m-win32.whl", hash = "sha256:600617008aa82032ddeace2535626d1bc212dfff32b43989539deda63b3f36e4"},
-    {file = "coverage-6.2-cp37-cp37m-win_amd64.whl", hash = "sha256:bf154ba7ee2fd613eb541c2bc03d3d9ac667080a737449d1a3fb342740eb1a74"},
-    {file = "coverage-6.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:f9afb5b746781fc2abce26193d1c817b7eb0e11459510fba65d2bd77fe161d9e"},
-    {file = "coverage-6.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:edcada2e24ed68f019175c2b2af2a8b481d3d084798b8c20d15d34f5c733fa58"},
-    {file = "coverage-6.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:a9c8c4283e17690ff1a7427123ffb428ad6a52ed720d550e299e8291e33184dc"},
-    {file = "coverage-6.2-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:f614fc9956d76d8a88a88bb41ddc12709caa755666f580af3a688899721efecd"},
-    {file = "coverage-6.2-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:9365ed5cce5d0cf2c10afc6add145c5037d3148585b8ae0e77cc1efdd6aa2953"},
-    {file = "coverage-6.2-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:8bdfe9ff3a4ea37d17f172ac0dff1e1c383aec17a636b9b35906babc9f0f5475"},
-    {file = "coverage-6.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:63c424e6f5b4ab1cf1e23a43b12f542b0ec2e54f99ec9f11b75382152981df57"},
-    {file = "coverage-6.2-cp38-cp38-win32.whl", hash = "sha256:49dbff64961bc9bdd2289a2bda6a3a5a331964ba5497f694e2cbd540d656dc1c"},
-    {file = "coverage-6.2-cp38-cp38-win_amd64.whl", hash = "sha256:9a29311bd6429be317c1f3fe4bc06c4c5ee45e2fa61b2a19d4d1d6111cb94af2"},
-    {file = "coverage-6.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:03b20e52b7d31be571c9c06b74746746d4eb82fc260e594dc662ed48145e9efd"},
-    {file = "coverage-6.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:215f8afcc02a24c2d9a10d3790b21054b58d71f4b3c6f055d4bb1b15cecce685"},
-    {file = "coverage-6.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:a4bdeb0a52d1d04123b41d90a4390b096f3ef38eee35e11f0b22c2d031222c6c"},
-    {file = "coverage-6.2-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:c332d8f8d448ded473b97fefe4a0983265af21917d8b0cdcb8bb06b2afe632c3"},
-    {file = "coverage-6.2-cp39-cp39-win32.whl", hash = "sha256:6e1394d24d5938e561fbeaa0cd3d356207579c28bd1792f25a068743f2d5b282"},
-    {file = "coverage-6.2-cp39-cp39-win_amd64.whl", hash = "sha256:86f2e78b1eff847609b1ca8050c9e1fa3bd44ce755b2ec30e70f2d3ba3844644"},
-    {file = "coverage-6.2-pp36.pp37.pp38-none-any.whl", hash = "sha256:5829192582c0ec8ca4a2532407bc14c2f338d9878a10442f5d03804a95fac9de"},
-    {file = "coverage-6.2.tar.gz", hash = "sha256:e2cad8093172b7d1595b4ad66f24270808658e11acf43a8f95b41276162eb5b8"},
-]
-django = [
-    {file = "Django-2.2.27-py3-none-any.whl", hash = "sha256:90763c764738586b11d7e1f44828032c153366e43ad7f782908193a1bb2d6d92"},
-    {file = "Django-2.2.27.tar.gz", hash = "sha256:1ee37046b0bf2b61e83b3a01d067323516ec3b6f2b17cd49b1326dd4ba9dc913"},
-]
-factory-boy = [
-    {file = "factory_boy-2.12.0-py2.py3-none-any.whl", hash = "sha256:728df59b372c9588b83153facf26d3d28947fc750e8e3c95cefa9bed0e6394ee"},
-    {file = "factory_boy-2.12.0.tar.gz", hash = "sha256:faf48d608a1735f0d0a3c9cbf536d64f9132b547dae7ba452c4d99a79e84a370"},
-]
-faker = [
-    {file = "Faker-13.3.1-py3-none-any.whl", hash = "sha256:c88c8b5ee9376a242deca8fe829f9a3215ffa43c31da6f66d9594531fb344453"},
-    {file = "Faker-13.3.1.tar.gz", hash = "sha256:fa060e331ffffb57cfa4c07f95d54911e339984ed72596ba6a9e7b6fa569d799"},
-]
-graphene = [
-    {file = "graphene-3.0-py2.py3-none-any.whl", hash = "sha256:57ce5ee7c9dc194224a1df96e4f7cb48d31eae96c791091d059f8f3d4d131390"},
-    {file = "graphene-3.0.tar.gz", hash = "sha256:af48066e152200a071aac1e0b703954c717ec7268720ba190a0c91d9bcb0a122"},
-]
-graphene-django = [
-    {file = "graphene-django-3.0.0b7.tar.gz", hash = "sha256:b1a4ce1a2227b1e77f67f0bc2fadd59c1d05016cb9aced45ab65f8612fba2c87"},
-    {file = "graphene_django-3.0.0b7-py2.py3-none-any.whl", hash = "sha256:0f226ec7db744a54dbc5d6db2aa52d945701ae800e1055046dec2b76a539550a"},
-]
-graphene-file-upload = [
-    {file = "graphene_file_upload-1.3.0-py3-none-any.whl", hash = "sha256:5afe50f409f50e3d198fd92c883d98d868e6c6aaadf5df3a3f4d88ecad90ed97"},
-    {file = "graphene_file_upload-1.3.0.tar.gz", hash = "sha256:6898480b0556826472c80971032917c01968ade5800d84054008fe598795b063"},
-]
-graphql-core = [
-    {file = "graphql-core-3.1.7.tar.gz", hash = "sha256:62ec192150ccecd9a18cfb79e3e72eb7d1fd68fb594ef19c40099b6deec8ef0c"},
-    {file = "graphql_core-3.1.7-py3-none-any.whl", hash = "sha256:9b460f60320be01c7f3b1766cf3e406933003008055079b9d983b8f3988f4400"},
-]
-graphql-relay = [
-    {file = "graphql-relay-3.1.5.tar.gz", hash = "sha256:127f40913f11cb847452ef794931261aae3b222eaaf976f7c8430298534e54d3"},
-    {file = "graphql_relay-3.1.5-py3-none-any.whl", hash = "sha256:d1455316182e1017d06f0b4d4a2ce8bafad38253a6c7c5666fc80d5d516ee5c8"},
-]
-importlib-metadata = [
-    {file = "importlib_metadata-4.8.3-py3-none-any.whl", hash = "sha256:65a9576a5b2d58ca44d133c42a241905cc45e34d2c06fd5ba2bafa221e5d7b5e"},
-    {file = "importlib_metadata-4.8.3.tar.gz", hash = "sha256:766abffff765960fcc18003801f7044eb6755ffae4521c8e8ce8e83b9c9b0668"},
-]
-more-itertools = [
-    {file = "more-itertools-8.12.0.tar.gz", hash = "sha256:7dc6ad46f05f545f900dd59e8dfb4e84a4827b97b3cfecb175ea0c7d247f6064"},
-    {file = "more_itertools-8.12.0-py3-none-any.whl", hash = "sha256:43e6dd9942dffd72661a2c4ef383ad7da1e6a3e968a927ad7a6083ab410a688b"},
-]
-packaging = [
-    {file = "packaging-21.3-py3-none-any.whl", hash = "sha256:ef103e05f519cdc783ae24ea4e2e0f508a9c99b2d4969652eed6a2e1ea5bd522"},
-    {file = "packaging-21.3.tar.gz", hash = "sha256:dd47c42927d89ab911e606518907cc2d3a1f38bbd026385970643f9c5b8ecfeb"},
-]
-pluggy = [
-    {file = "pluggy-0.13.1-py2.py3-none-any.whl", hash = "sha256:966c145cd83c96502c3c3868f50408687b38434af77734af1e9ca461a4081d2d"},
-    {file = "pluggy-0.13.1.tar.gz", hash = "sha256:15b2acde666561e1298d71b523007ed7364de07029219b604cf808bfa1c765b0"},
-]
-promise = [
-    {file = "promise-2.3.tar.gz", hash = "sha256:dfd18337c523ba4b6a58801c164c1904a9d4d1b1747c7d5dbf45b693a49d93d0"},
-]
-py = [
-    {file = "py-1.11.0-py2.py3-none-any.whl", hash = "sha256:607c53218732647dff4acdfcd50cb62615cedf612e72d1724fb1a0cc6405b378"},
-    {file = "py-1.11.0.tar.gz", hash = "sha256:51c75c4126074b472f746a24399ad32f6053d1b34b68d2fa41e558e6f4a98719"},
-]
-pyparsing = [
-    {file = "pyparsing-3.0.7-py3-none-any.whl", hash = "sha256:a6c06a88f252e6c322f65faf8f418b16213b51bdfaece0524c1c1bc30c63c484"},
-    {file = "pyparsing-3.0.7.tar.gz", hash = "sha256:18ee9022775d270c55187733956460083db60b37d0d0fb357445f3094eed3eea"},
-]
-pytest = [
-    {file = "pytest-5.4.3-py3-none-any.whl", hash = "sha256:5c0db86b698e8f170ba4582a492248919255fcd4c79b1ee64ace34301fb589a1"},
-    {file = "pytest-5.4.3.tar.gz", hash = "sha256:7979331bfcba207414f5e1263b5a0f8f521d0f457318836a7355531ed1a4c7d8"},
-]
-pytest-cov = [
-    {file = "pytest-cov-2.12.1.tar.gz", hash = "sha256:261ceeb8c227b726249b376b8526b600f38667ee314f910353fa318caa01f4d7"},
-    {file = "pytest_cov-2.12.1-py2.py3-none-any.whl", hash = "sha256:261bb9e47e65bd099c89c3edf92972865210c36813f80ede5277dceb77a4a62a"},
-]
-pytest-django = [
-    {file = "pytest-django-3.10.0.tar.gz", hash = "sha256:4de6dbd077ed8606616958f77655fed0d5e3ee45159475671c7fa67596c6dba6"},
-    {file = "pytest_django-3.10.0-py2.py3-none-any.whl", hash = "sha256:c33e3d3da14d8409b125d825d4e74da17bb252191bf6fc3da6856e27a8b73ea4"},
-]
-python-dateutil = [
-    {file = "python-dateutil-2.8.2.tar.gz", hash = "sha256:0123cacc1627ae19ddf3c27a5de5bd67ee4586fbdd6440d9748f8abb483d3e86"},
-    {file = "python_dateutil-2.8.2-py2.py3-none-any.whl", hash = "sha256:961d03dc3453ebbc59dbdea9e4e11c5651520a876d0f4db161e8674aae935da9"},
-]
-pytz = [
-    {file = "pytz-2021.3-py2.py3-none-any.whl", hash = "sha256:3672058bc3453457b622aab7a1c3bfd5ab0bdae451512f6cf25f64ed37f5b87c"},
-    {file = "pytz-2021.3.tar.gz", hash = "sha256:acad2d8b20a1af07d4e4c9d2e9285c5ed9104354062f275f3fcd88dcef4f1326"},
-]
-six = [
-    {file = "six-1.16.0-py2.py3-none-any.whl", hash = "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"},
-    {file = "six-1.16.0.tar.gz", hash = "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926"},
-]
-sqlparse = [
-    {file = "sqlparse-0.4.2-py3-none-any.whl", hash = "sha256:48719e356bb8b42991bdbb1e8b83223757b93789c00910a616a071910ca4a64d"},
-    {file = "sqlparse-0.4.2.tar.gz", hash = "sha256:0c00730c74263a94e5a9919ade150dfc3b19c574389985446148402998287dae"},
-]
-text-unidecode = [
-    {file = "text-unidecode-1.3.tar.gz", hash = "sha256:bad6603bb14d279193107714b288be206cac565dfa49aa5b105294dd5c4aab93"},
-    {file = "text_unidecode-1.3-py2.py3-none-any.whl", hash = "sha256:1311f10e8b895935241623731c2ba64f4c455287888b18189350b67134a822e8"},
-]
-toml = [
-    {file = "toml-0.10.2-py2.py3-none-any.whl", hash = "sha256:806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b"},
-    {file = "toml-0.10.2.tar.gz", hash = "sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f"},
-]
-typing-extensions = [
-    {file = "typing_extensions-4.1.1-py3-none-any.whl", hash = "sha256:21c85e0fe4b9a155d0799430b0ad741cdce7e359660ccbd8b530613e8df88ce2"},
-    {file = "typing_extensions-4.1.1.tar.gz", hash = "sha256:1a9462dcc3347a79b1f1c0271fbe79e844580bb598bafa1ed208b94da3cdcd42"},
-]
-wcwidth = [
-    {file = "wcwidth-0.2.5-py2.py3-none-any.whl", hash = "sha256:beb4802a9cebb9144e99086eff703a642a13d6a0052920003a230f3294bbe784"},
-    {file = "wcwidth-0.2.5.tar.gz", hash = "sha256:c4d647b99872929fdb7bdcaa4fbe7f01413ed3d98077df798530e5b04f116c83"},
-]
-zipp = [
-    {file = "zipp-3.6.0-py3-none-any.whl", hash = "sha256:9fe5ea21568a0a70e50f273397638d39b03353731e6cbbb3fd8502a33fec40bc"},
-    {file = "zipp-3.6.0.tar.gz", hash = "sha256:71c644c5369f4a6e07636f0aa966270449561fcea2e3d6747b8d23efaa9d7832"},
-]
+lock-version = "2.0"
+python-versions = "^3.7"
+content-hash = "503caaf3c9962761287862d5633516086e0f18400ac266adbd7c8a7571ee8957"
diff --git a/pyproject.toml b/pyproject.toml
index aa8cbb0..bc261d6 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -1,22 +1,39 @@
 [tool.poetry]
 name = "graphene-django-cud"
-version = "0.10.0"
+version = "0.11.0"
 description = ""
 authors = ["Tormod Haugland <tormod.haugland@gmail.com>"]
 license = "MIT"
 
 [tool.poetry.dependencies]
-python = "^3.6"
-graphene-django = "^3.0.0b7"
+python = "^3.7"
+graphene-django = "^3.0"
 graphene-file-upload = "^1.2"
 
 [tool.poetry.dev-dependencies]
-django = "^2.2"
-pytest = "^5.2"
-pytest-django = "^3.7"
-factory_boy = "^2.12"
+django = "^3.2"
+pytest = "^7.4"
+pytest-django = "^4.0"
+factory_boy = "^3.2"
 addict = "^2.2"
-pytest-cov = "^2.8"
+pytest-cov = "^4.1"
+
+[tool.black]
+line-length = 120
+target-version = ['py38']
+include = '\.pyi?$'
+extend-exclude = '''
+/(
+\.git
+|\.github
+|\.pytest_cache
+|\.idea
+|build
+|__pycache__
+|manage\.py
+|migrations
+)/
+'''
 
 [build-system]
 requires = ["poetry>=0.12"]
diff --git a/setup.py b/setup.py
index 4ae7dbb..c05d839 100644
--- a/setup.py
+++ b/setup.py
@@ -5,7 +5,7 @@
 
 setuptools.setup(
     name="graphene-django-cud",
-    version="0.10.0",
+    version="0.11.0",
     author="Tormod Haugland",
     author_email="tormod.haugland@gmail.com",
     description="Create, update and delete mutations for graphene-django",
@@ -13,13 +13,10 @@
     long_description_content_type="text/markdown",
     url="https://github.com/tOgg1/graphene-django-cud",
     packages=setuptools.find_packages(),
-    install_requires=[
-        "graphene-django>=2.0",
-        "graphene-file-upload>=1.2"
-    ],
+    install_requires=["graphene-django>=3.0", "graphene-file-upload>=1.2"],
     classifiers=[
         "Programming Language :: Python :: 3",
         "License :: OSI Approved :: MIT License",
-        "Operating System :: OS Independent"
-    ]
+        "Operating System :: OS Independent",
+    ],
 )


Test patch:
diff --git a/graphene_django_cud/tests/dummy_query.py b/graphene_django_cud/tests/dummy_query.py
index 5869e9e..c92baf1 100644
--- a/graphene_django_cud/tests/dummy_query.py
+++ b/graphene_django_cud/tests/dummy_query.py
@@ -1,5 +1,3 @@
-
-
 # Dummy Query object for testing so that GraphQL 3.0 does not complain
 import graphene
 
diff --git a/graphene_django_cud/tests/factories.py b/graphene_django_cud/tests/factories.py
index 5887320..2d0d177 100644
--- a/graphene_django_cud/tests/factories.py
+++ b/graphene_django_cud/tests/factories.py
@@ -3,11 +3,12 @@
 import factory
 from django.contrib.auth.models import Permission
 from django.db import models
+from factory.django import DjangoModelFactory
 
 from graphene_django_cud.tests.models import User, Cat, Dog, Mouse, DogRegistration
 
 
-class UserFactory(factory.DjangoModelFactory):
+class UserFactory(DjangoModelFactory):
     class Meta:
         model = User
 
@@ -17,7 +18,7 @@ class Meta:
     email = factory.Faker("email")
 
 
-class UserAdminFactory(factory.DjangoModelFactory):
+class UserAdminFactory(DjangoModelFactory):
     class Meta:
         model = User
 
@@ -34,16 +35,14 @@ def _get_permission_from_string(string: str) -> Optional[Permission]:
         if "." in string:
             app_label, codename = string.split(".")
 
-            return Permission.objects.get(
-                content_type__app_label=app_label, codename=codename
-            )
+            return Permission.objects.get(content_type__app_label=app_label, codename=codename)
         else:
             return Permission.objects.get(codename=string)
     except models.ObjectDoesNotExist:
         return None
 
 
-class UserWithPermissionsFactory(factory.DjangoModelFactory):
+class UserWithPermissionsFactory(DjangoModelFactory):
     class Meta:
         model = User
 
@@ -70,12 +69,10 @@ def permissions(self, create, extracted, **kwargs):
                 if permission is not None:
                     self.user_permissions.add(permission)
         else:
-            raise ValueError(
-                "Invalid variable input for permissions, expected string or iterable"
-            )
+            raise ValueError("Invalid variable input for permissions, expected string or iterable")
 
 
-class CatFactory(factory.DjangoModelFactory):
+class CatFactory(DjangoModelFactory):
     class Meta:
         model = Cat
 
@@ -83,7 +80,7 @@ class Meta:
     name = "Cat"
 
 
-class DogFactory(factory.DjangoModelFactory):
+class DogFactory(DjangoModelFactory):
     class Meta:
         model = Dog
 
@@ -93,7 +90,7 @@ class Meta:
     breed = "HUSKY"
 
 
-class DogRegistrationFactory(factory.DjangoModelFactory):
+class DogRegistrationFactory(DjangoModelFactory):
     class Meta:
         model = DogRegistration
         django_get_or_create = ("dog",)
@@ -102,7 +99,7 @@ class Meta:
     registration_number = "RegNr."
 
 
-class MouseFactory(factory.DjangoModelFactory):
+class MouseFactory(DjangoModelFactory):
     class Meta:
         model = Mouse
 
diff --git a/graphene_django_cud/tests/models.py b/graphene_django_cud/tests/models.py
index 5a5af2b..5d5ca47 100644
--- a/graphene_django_cud/tests/models.py
+++ b/graphene_django_cud/tests/models.py
@@ -8,9 +8,7 @@ class User(AbstractUser):
 
 class Mouse(models.Model):
     name = models.TextField()
-    keeper = models.ForeignKey(
-        User, null=True, blank=True, on_delete=models.SET_NULL, related_name="mice"
-    )
+    keeper = models.ForeignKey(User, null=True, blank=True, on_delete=models.SET_NULL, related_name="mice")
 
 
 class Cat(models.Model):
@@ -18,9 +16,7 @@ class Cat(models.Model):
     name = models.TextField()
     targets = models.ManyToManyField(Mouse, blank=True, related_name="predators")
 
-    user_relations = models.ManyToManyField(
-        User, through="CatUserRelation", blank=True, related_name="related_to_cats"
-    )
+    user_relations = models.ManyToManyField(User, through="CatUserRelation", blank=True, related_name="related_to_cats")
 
 
 class Dog(models.Model):
@@ -40,7 +36,7 @@ class Dog(models.Model):
             ("BULLDOG", "BULLDOG"),
             ("FLATCOAT", "Flatcoat retriever"),
             ("MALAMUTE", "Alaskan Malamuate"),
-        )
+        ),
     )
 
     enemies = models.ManyToManyField(Cat, blank=True, related_name="enemies")
@@ -51,17 +47,13 @@ class Meta:
 
 
 class DogRegistration(models.Model):
-    dog = models.OneToOneField(
-        Dog, related_name="registration", on_delete=models.CASCADE
-    )
+    dog = models.OneToOneField(Dog, related_name="registration", on_delete=models.CASCADE)
     registration_number = models.CharField(max_length=32)
 
 
 class CatUserRelation(models.Model):
     cat = models.ForeignKey(Cat, on_delete=models.CASCADE, related_name="cat_user_relations")
-    user = models.ForeignKey(
-        User, on_delete=models.CASCADE, related_name="cat_user_relations"
-    )
+    user = models.ForeignKey(User, on_delete=models.CASCADE, related_name="cat_user_relations")
 
     friends = models.BooleanField(default=False)
 
diff --git a/graphene_django_cud/tests/schema.py b/graphene_django_cud/tests/schema.py
index 9291910..b3e0430 100644
--- a/graphene_django_cud/tests/schema.py
+++ b/graphene_django_cud/tests/schema.py
@@ -80,9 +80,7 @@ class Meta:
             "dogs": {
                 "add": {
                     "field_types": {"tag": graphene.Int()},
-                    "many_to_many_extras": {
-                        "friends": {"add": {"type": "CreateMouseInput"}}
-                    },
+                    "many_to_many_extras": {"friends": {"add": {"type": "CreateMouseInput"}}},
                 }
             },
         }
@@ -100,13 +98,7 @@ class Meta:
         model = User
         many_to_one_extras = {
             "cats": {"add": {"type": "auto"}, "update": {"type": "auto"}},
-            "dogs": {
-                "add": {
-                    "many_to_many_extras": {
-                        "friends": {"add": {"type": "CreateMouseInput"}}
-                    }
-                }
-            },
+            "dogs": {"add": {"many_to_many_extras": {"friends": {"add": {"type": "CreateMouseInput"}}}}},
         }
 
     @classmethod
@@ -149,9 +141,7 @@ class Meta:
             "enemies": {
                 "add": {
                     "type": "CreateDogInput",
-                    "many_to_many_extras": {
-                        "friends": {"add": {"type": "CreateMouseInput"}}
-                    },
+                    "many_to_many_extras": {"friends": {"add": {"type": "CreateMouseInput"}}},
                 },
                 "remove": True,
                 "exact": {"type": "ID"},
diff --git a/graphene_django_cud/tests/test_batch_delete_mutation.py b/graphene_django_cud/tests/test_batch_delete_mutation.py
index aa44e40..0b01fc7 100644
--- a/graphene_django_cud/tests/test_batch_delete_mutation.py
+++ b/graphene_django_cud/tests/test_batch_delete_mutation.py
@@ -15,8 +15,7 @@
 class TestBatchDeleteMutation(TestCase):
     def test__ids_exist__deletes_relevant_objects(self):
         # This registers the UserNode type
-        # noinspection PyUnresolvedReferences
-        from .schema import UserNode
+        from .schema import UserNode  # noqa: F401
 
         class BatchDeleteUserMutation(DjangoBatchDeleteMutation):
             class Meta:
@@ -40,7 +39,8 @@ class Mutations(graphene.ObjectType):
         """
 
         result = schema.execute(
-            mutation, variables={"ids": [user.id for user in users]},
+            mutation,
+            variables={"ids": [user.id for user in users]},
         )
         data = Dict(result.data)
         self.assertEqual(10, data.batchDeleteUser.deletionCount)
@@ -52,8 +52,7 @@ class Mutations(graphene.ObjectType):
 
     def test__ids_does_not_exist__only_deletes_relevant_objects(self):
         # This registers the UserNode type
-        # noinspection PyUnresolvedReferences
-        from .schema import UserNode
+        from .schema import UserNode  # noqa: F401
 
         class BatchDeleteUserMutation(DjangoBatchDeleteMutation):
             class Meta:
@@ -83,9 +82,9 @@ class Mutations(graphene.ObjectType):
         """
 
         result = schema.execute(
-            mutation, variables={"ids": ids_to_delete},
+            mutation,
+            variables={"ids": ids_to_delete},
         )
-        print(result)
         data = Dict(result.data)
         self.assertEqual(5, data.batchDeleteUser.deletionCount)
         self.assertListEqual(
diff --git a/graphene_django_cud/tests/test_batch_patch_mutation.py b/graphene_django_cud/tests/test_batch_patch_mutation.py
index 17aa7fd..56eccfd 100644
--- a/graphene_django_cud/tests/test_batch_patch_mutation.py
+++ b/graphene_django_cud/tests/test_batch_patch_mutation.py
@@ -13,8 +13,7 @@
 class TestBatchPatchMutation(TestCase):
     def test_mutate__objects_exists__updates(self):
         # This registers the UserNode type
-        # noinspection PyUnresolvedReferences
-        from .schema import UserNode
+        from .schema import UserNode  # noqa: F401
 
         class BatchPatchDogMutation(DjangoBatchPatchMutation):
             class Meta:
@@ -30,7 +29,7 @@ class Mutations(graphene.ObjectType):
         schema = Schema(query=DummyQuery, mutation=Mutations)
         mutation = """
             mutation BatchPatchDog(
-                $input: [BatchPatchDogInput]! 
+                $input: [BatchPatchDogInput]!
             ){
                 batchPatchDog(input: $input){
                     dogs {
@@ -55,7 +54,7 @@ class Mutations(graphene.ObjectType):
                     },
                 ]
             },
-            context=Dict(user=user)
+            context=Dict(user=user),
         )
         self.assertIsNone(result.errors)
 
@@ -74,8 +73,7 @@ class Mutations(graphene.ObjectType):
 class TestBatchPatchMutationRequiredFields(TestCase):
     def setUp(self):
         # This registers the UserNode type
-        # noinspection PyUnresolvedReferences
-        from .schema import UserNode
+        from .schema import UserNode  # noqa: F401
 
         class PatchDogMutation(DjangoBatchPatchMutation):
             class Meta:
@@ -122,8 +120,8 @@ def test_required_fields__when_set_and_not_provided__returns_error(self):
                     {
                         "id": self.dog2_id,
                         "name": "Richard",
-                    }
-                ]
+                    },
+                ],
             },
             context=self.context,
         )
@@ -143,7 +141,7 @@ def test_required_fields__when_set_and_provided__returns_no_error(self):
                         "id": self.dog2_id,
                         "name": "Richard",
                         "owner": self.user1_id,
-                    }
+                    },
                 ]
             },
             context=self.context,
diff --git a/graphene_django_cud/tests/test_batch_update_mutation.py b/graphene_django_cud/tests/test_batch_update_mutation.py
index ce48c8f..a40d508 100644
--- a/graphene_django_cud/tests/test_batch_update_mutation.py
+++ b/graphene_django_cud/tests/test_batch_update_mutation.py
@@ -13,8 +13,7 @@
 class TestBatchUpdateMutation(TestCase):
     def test_mutate__objects_exists__updates(self):
         # This registers the UserNode type
-        # noinspection PyUnresolvedReferences
-        from .schema import UserNode
+        from .schema import UserNode  # noqa: F401
 
         class BatchUpdateDogMutation(DjangoBatchUpdateMutation):
             class Meta:
@@ -30,7 +29,7 @@ class Mutations(graphene.ObjectType):
         schema = Schema(query=DummyQuery, mutation=Mutations)
         mutation = """
             mutation BatchUpdateDog(
-                $input: [BatchUpdateDogInput]! 
+                $input: [BatchUpdateDogInput]!
             ){
                 batchUpdateDog(input: $input){
                     dogs{
@@ -61,7 +60,7 @@ class Mutations(graphene.ObjectType):
                     },
                 ]
             },
-            context=Dict(user=user)
+            context=Dict(user=user),
         )
         self.assertIsNone(result.errors)
 
diff --git a/graphene_django_cud/tests/test_converter.py b/graphene_django_cud/tests/test_converter.py
index 4536037..5988f3f 100644
--- a/graphene_django_cud/tests/test_converter.py
+++ b/graphene_django_cud/tests/test_converter.py
@@ -3,7 +3,11 @@
 from django.test import TestCase
 from graphene_django.registry import get_global_registry
 
-from graphene_django_cud.converter import convert_choices_field, convert_django_field_with_choices, convert_django_field_to_input
+from graphene_django_cud.converter import (
+    convert_choices_field,
+    convert_django_field_with_choices,
+    convert_django_field_to_input,
+)
 
 
 class TestConvertChoicesField(TestCase):
@@ -15,14 +19,11 @@ class MockModel(models.Model):
                     ("A", "Choice a"),
                     ("B", "Choice b"),
                     ("C", "Choice c"),
-                )
+                ),
             )
 
         field = MockModel._meta.get_field("field_with_choices")
-        result = convert_choices_field(
-            field,
-            field.choices
-        )(required=True)
+        result = convert_choices_field(field, field.choices)(required=True)
 
         self.assertIsInstance(result, graphene.types.Enum)
         self.assertEqual(result.kwargs.get("required"), True)
@@ -54,7 +55,7 @@ class MockModel(models.Model):
                     ("B", "Choice b"),
                     ("C", "Choice c"),
                 ),
-                default="A"
+                default="A",
             )
 
         field = MockModel._meta.get_field("field_with_choices")
@@ -66,7 +67,9 @@ class MockModel(models.Model):
         self.assertEqual(result.kwargs.get("required"), False)
 
     # Exists to address: https://github.com/tOgg1/graphene-django-cud/issues/5
-    def test_choices_field__choice_field_in_different_locations__accepts_different_parameters(self):
+    def test_choices_field__choice_field_in_different_locations__accepts_different_parameters(
+        self,
+    ):
         class MockModel(models.Model):
             field_with_choices = models.CharField(
                 max_length=16,
@@ -74,53 +77,41 @@ class MockModel(models.Model):
                     ("A", "Choice a"),
                     ("B", "Choice b"),
                     ("C", "Choice c"),
-                )
+                ),
             )
 
         registry = get_global_registry()
         field = MockModel._meta.get_field("field_with_choices")
-        result = convert_django_field_with_choices(
-            field,
-            registry=registry
-        )
+        result = convert_django_field_with_choices(field, registry=registry)
 
         self.assertIsInstance(result, graphene.types.Enum)
         self.assertEqual(result.kwargs.get("required"), True)
 
-        result = convert_django_field_with_choices(
-            field,
-            registry,
-            required=False
-        )
+        result = convert_django_field_with_choices(field, registry, required=False)
 
         self.assertIsInstance(result, graphene.types.Enum)
         self.assertEqual(result.kwargs.get("required"), False)
 
     # Exists to adress: https://github.com/tOgg1/graphene-django-cud/issues/9
     def test__one_to_one_field__is_properly_converted(self):
-
         class MockSuperModel(models.Model):
             name = models.CharField(max_length=128, default="Heidi Klum")
 
         class MockModel(models.Model):
-            super_model = models.OneToOneField(MockSuperModel, on_delete=models.CASCADE, related_name='modelling')  # Model-ling... Get it? xD
+            super_model = models.OneToOneField(
+                MockSuperModel, on_delete=models.CASCADE, related_name="modelling"
+            )  # Model-ling... Get it? xD
 
         # Convert primary relation
         registry = get_global_registry()
         field = MockModel._meta.get_field("super_model")
-        result = convert_django_field_with_choices(
-            field,
-            registry=registry
-        )
+        result = convert_django_field_with_choices(field, registry=registry)
 
         self.assertIsInstance(result, graphene.types.ID)
         self.assertEqual(result.kwargs.get("required"), True)
 
         # Convert backward relation
         field = MockSuperModel._meta.get_field("modelling")
-        result = convert_django_field_with_choices(
-            field,
-            registry=registry
-        )
+        result = convert_django_field_with_choices(field, registry=registry)
 
         self.assertIsInstance(result, graphene.types.ID)
diff --git a/graphene_django_cud/tests/test_create_mutation.py b/graphene_django_cud/tests/test_create_mutation.py
index 8f373d7..6b42941 100644
--- a/graphene_django_cud/tests/test_create_mutation.py
+++ b/graphene_django_cud/tests/test_create_mutation.py
@@ -36,8 +36,7 @@ def test_many_to_one_extras__auto_calling_mutation_with_setting_field__does_noth
         self,
     ):
         # This registers the UserNode type
-        # noinspection PyUnresolvedReferences
-        from .schema import UserNode
+        from .schema import UserNode  # noqa: F401
 
         class CreateUserMutation(DjangoCreateMutation):
             class Meta:
@@ -53,7 +52,7 @@ class Mutations(graphene.ObjectType):
         schema = Schema(query=DummyQuery, mutation=Mutations)
         mutation = """
             mutation CreateUser(
-                $input: CreateUserInput! 
+                $input: CreateUserInput!
             ){
                 createUser(input: $input){
                     user{
@@ -83,8 +82,7 @@ class Mutations(graphene.ObjectType):
 
     def test_many_to_one_extras__set_exact_by_id__sets_by_id(self):
         # This registers the UserNode type
-        # noinspection PyUnresolvedReferences
-        from .schema import UserNode
+        from .schema import UserNode  # noqa: F401
 
         class CreateUserMutation(DjangoCreateMutation):
             class Meta:
@@ -101,7 +99,7 @@ class Mutations(graphene.ObjectType):
         schema = Schema(query=DummyQuery, mutation=Mutations)
         mutation = """
             mutation CreateUser(
-                $input: CreateUserInput! 
+                $input: CreateUserInput!
             ){
                 createUser(input: $input){
                     user{
@@ -132,8 +130,7 @@ class Mutations(graphene.ObjectType):
 
     def test_many_to_one_extras__add_by_id__adds_by_id(self):
         # This registers the UserNode type
-        # noinspection PyUnresolvedReferences
-        from .schema import UserNode
+        from .schema import UserNode  # noqa: F401
 
         class CreateUserMutation(DjangoCreateMutation):
             class Meta:
@@ -150,7 +147,7 @@ class Mutations(graphene.ObjectType):
         schema = Schema(query=DummyQuery, mutation=Mutations)
         mutation = """
             mutation CreateUser(
-                $input: CreateUserInput! 
+                $input: CreateUserInput!
             ){
                 createUser(input: $input){
                     user{
@@ -181,8 +178,7 @@ class Mutations(graphene.ObjectType):
 
     def test_many_to_one_extras__add_by_input__adds_by_input(self):
         # This registers the UserNode type
-        # noinspection PyUnresolvedReferences
-        from .schema import UserNode
+        from .schema import UserNode  # noqa: F401
 
         class CreateCatMutation(DjangoCreateMutation):
             class Meta:
@@ -203,7 +199,7 @@ class Mutations(graphene.ObjectType):
         schema = Schema(query=DummyQuery, mutation=Mutations)
         mutation = """
             mutation CreateUser(
-                $input: CreateUserInput! 
+                $input: CreateUserInput!
             ){
                 createUser(input: $input){
                     user{
@@ -237,8 +233,7 @@ class TestUpdateWithOneToOneField(TestCase):
     def test__one_to_one_relation_exists__updates_specified_fields(self):
 
         # This registers the UserNode type
-        # noinspection PyUnresolvedReferences
-        from .schema import UserNode
+        from .schema import UserNode  # noqa: F401
 
         class UpdateDogMutation(DjangoUpdateMutation):
             class Meta:
@@ -263,7 +258,7 @@ class Mutations(graphene.ObjectType):
                         id
                         registration{
                             id
-                            registrationNumber 
+                            registrationNumber
                         }
                     }
                 }
@@ -284,7 +279,6 @@ class Mutations(graphene.ObjectType):
             },
             context=Dict(user=user),
         )
-        print(result)
         self.assertIsNone(result.errors)
         data = Dict(result.data)
         self.assertIsNone(result.errors)
@@ -296,8 +290,7 @@ class Mutations(graphene.ObjectType):
 
     def test__reverse_one_to_one_exists__updates_specified_fields(self):
         # This registers the UserNode type
-        # noinspection PyUnresolvedReferences
-        from .schema import UserNode
+        from .schema import UserNode  # noqa: F401
 
         class UpdateDogRegistrationMutation(DjangoUpdateMutation):
             class Meta:
@@ -309,9 +302,7 @@ class Mutations(graphene.ObjectType):
 
         user = UserFactory.create()
         dog = DogFactory.create(breed="HUSKY")
-        dog_registration = DogRegistration.objects.create(
-            dog=dog, registration_number="1234"
-        )
+        dog_registration = DogRegistration.objects.create(dog=dog, registration_number="1234")
 
         schema = Schema(query=DummyQuery, mutation=Mutations)
         mutation = """
@@ -350,15 +341,11 @@ class Mutations(graphene.ObjectType):
         )
         self.assertIsNone(result.errors)
         data = Dict(result.data)
-        self.assertEqual(
-            "LABRADOR", data.updateDogRegistration.dogRegistration.dog.breed
-        )
+        self.assertEqual("LABRADOR", data.updateDogRegistration.dogRegistration.dog.breed)
 
-        print(dog.breed, type(dog.breed))
         # Load from database
         dog_registration.refresh_from_db()
         dog.refresh_from_db()
-        print(dog.breed, type(dog.breed))
 
         self.assertEqual(dog.breed, "LABRADOR")
 
@@ -366,8 +353,7 @@ class Mutations(graphene.ObjectType):
 class TestCreateWithOneToOneField(TestCase):
     def test__one_to_one_relation_exists__creates_specified_fields(self):
         # This registers the UserNode type
-        # noinspection PyUnresolvedReferences
-        from .schema import UserNode
+        from .schema import UserNode  # noqa: F401
 
         class CreateDogMutation(DjangoCreateMutation):
             class Meta:
@@ -389,7 +375,7 @@ class Mutations(graphene.ObjectType):
                         id
                         registration{
                             id
-                            registrationNumber 
+                            registrationNumber
                         }
                     }
                 }
@@ -422,8 +408,7 @@ class Mutations(graphene.ObjectType):
 
     def test__reverse_one_to_one_exists__updates_specified_fields(self):
         # This registers the UserNode type
-        # noinspection PyUnresolvedReferences
-        from .schema import UserNode
+        from .schema import UserNode  # noqa: F401
 
         class CreateDogRegistrationMutation(DjangoCreateMutation):
             class Meta:
@@ -482,9 +467,7 @@ class Mutations(graphene.ObjectType):
         self.assertEqual("12345", dog_registration.registrationNumber)
 
         # Load from database
-        dog_registration = DogRegistration.objects.get(
-            pk=disambiguate_id(dog_registration.id)
-        )
+        dog_registration = DogRegistration.objects.get(pk=disambiguate_id(dog_registration.id))
         dog = getattr(dog_registration, "dog", None)
         self.assertIsNotNone(dog)
         self.assertEqual(dog.name, "Sparky")
@@ -494,8 +477,7 @@ class Mutations(graphene.ObjectType):
 class TestCreateWithPlainManyToOneRelation(TestCase):
     def test__many_to_one_relation_exists__creates_specified_fields(self):
         # This registers the UserNode type
-        # noinspection PyUnresolvedReferences
-        from .schema import UserNode
+        from .schema import UserNode  # noqa: F401
 
         class CreateUserMutation(DjangoCreateMutation):
             class Meta:
@@ -523,7 +505,7 @@ class Mutations(graphene.ObjectType):
                                 }
                             }
                         }
-                    } 
+                    }
                 }
             }
         """
@@ -544,9 +526,7 @@ class Mutations(graphene.ObjectType):
         self.assertIsNone(result.errors)
         data = Dict(result.data)
         self.assertIsNone(result.errors)
-        self.assertEqual(
-            to_global_id("CatNode", cat.id), data.createUser.user.cats.edges[0].node.id
-        )
+        self.assertEqual(to_global_id("CatNode", cat.id), data.createUser.user.cats.edges[0].node.id)
 
         new_user = User.objects.get(pk=disambiguate_id(data.createUser.user.id))
 
@@ -558,8 +538,7 @@ class Mutations(graphene.ObjectType):
 class TestCreateWithPlainManyToManyRelation(TestCase):
     def test__many_to_one_relation_exists__creates_specified_fields(self):
         # This registers the UserNode type
-        # noinspection PyUnresolvedReferences
-        from .schema import UserNode
+        from .schema import UserNode  # noqa: F401
 
         class CreateDogMutation(DjangoCreateMutation):
             class Meta:
@@ -608,9 +587,7 @@ class Mutations(graphene.ObjectType):
         self.assertIsNone(result.errors)
         data = Dict(result.data)
         self.assertIsNone(result.errors)
-        self.assertEqual(
-            to_global_id("CatNode", cat.id), data.createDog.dog.enemies.edges[0].node.id
-        )
+        self.assertEqual(to_global_id("CatNode", cat.id), data.createDog.dog.enemies.edges[0].node.id)
 
         new_dog = Dog.objects.get(pk=disambiguate_id(data.createDog.dog.id))
 
@@ -624,8 +601,7 @@ def test_custom_field__separate_from_model_fields__adds_new_field_which_can_be_h
         self,
     ):
         # This registers the UserNode type
-        # noinspection PyUnresolvedReferences
-        from .schema import UserNode
+        from .schema import UserNode  # noqa: F401
 
         class CreateDogMutation(DjangoCreateMutation):
             class Meta:
@@ -647,7 +623,7 @@ class Mutations(graphene.ObjectType):
         schema = Schema(query=DummyQuery, mutation=Mutations)
         mutation = """
             mutation CreateDog(
-                $input: CreateDogInput! 
+                $input: CreateDogInput!
             ){
                 createDog(input: $input){
                     dog{
@@ -696,8 +672,7 @@ class Mutations(graphene.ObjectType):
 class TestCreateWithManyToManyThroughModel(TestCase):
     def test__creating_a_related_entity_with_a_through_model__works_as_intended(self):
         # This registers the UserNode type
-        # noinspection PyUnresolvedReferences
-        from .schema import UserNode
+        from .schema import UserNode  # noqa: F401
 
         class CreateCatMutation(DjangoCreateMutation):
             class Meta:
@@ -719,7 +694,7 @@ class Mutations(graphene.ObjectType):
         schema = Schema(query=DummyQuery, mutation=Mutations)
         mutation = """
             mutation CreateCat(
-                $input: CreateCatInput! 
+                $input: CreateCatInput!
             ){
                 createCat(input: $input){
                     cat{
diff --git a/graphene_django_cud/tests/test_delete_mutation.py b/graphene_django_cud/tests/test_delete_mutation.py
index f0760cb..ad5d04f 100644
--- a/graphene_django_cud/tests/test_delete_mutation.py
+++ b/graphene_django_cud/tests/test_delete_mutation.py
@@ -18,8 +18,7 @@
 class TestDeleteMutation(TestCase):
     def test_mutate__object_exists__deletes_object(self):
         # This registers the UserNode type
-        # noinspection PyUnresolvedReferences
-        from .schema import UserNode
+        from .schema import UserNode  # noqa: F401
 
         class DeleteCatMutation(DjangoDeleteMutation):
             class Meta:
@@ -46,7 +45,9 @@ class Mutations(graphene.ObjectType):
         """
         result = schema.execute(
             mutation,
-            variables={"id": to_global_id("CatNode", cat.id),},
+            variables={
+                "id": to_global_id("CatNode", cat.id),
+            },
             context=Dict(user=user),
         )
         self.assertIsNone(result.errors)
@@ -57,8 +58,7 @@ class Mutations(graphene.ObjectType):
 
     def test_mutate__object_does_not_exist__returns_found_false_and_null_id(self):
         # This registers the UserNode type
-        # noinspection PyUnresolvedReferences
-        from .schema import UserNode
+        from .schema import UserNode  # noqa: F401
 
         class DeleteCatMutation(DjangoDeleteMutation):
             class Meta:
@@ -82,7 +82,9 @@ class Mutations(graphene.ObjectType):
         """
         result = schema.execute(
             mutation,
-            variables={"id": to_global_id("CatNode", 1),},
+            variables={
+                "id": to_global_id("CatNode", 1),
+            },
             context=Dict(user=user),
         )
         self.assertIsNone(result.errors)
@@ -92,8 +94,7 @@ class Mutations(graphene.ObjectType):
 
     def test_muate__user_misses_permission__fails(self):
         # This registers the UserNode type
-        # noinspection PyUnresolvedReferences
-        from .schema import UserNode
+        from .schema import UserNode  # noqa: F401
 
         class DeleteCatMutation(DjangoDeleteMutation):
             class Meta:
diff --git a/graphene_django_cud/tests/test_filter_update_mutation.py b/graphene_django_cud/tests/test_filter_update_mutation.py
index c22b5a7..d36939f 100644
--- a/graphene_django_cud/tests/test_filter_update_mutation.py
+++ b/graphene_django_cud/tests/test_filter_update_mutation.py
@@ -12,8 +12,7 @@
 class TestFilterUpdateMutation(TestCase):
     def test__filter_update__updates(self):
         # This registers the UserNode type
-        # noinspection PyUnresolvedReferences
-        from .schema import UserNode
+        from .schema import UserNode  # noqa: F401
 
         class FilterUpdateDogMutation(DjangoFilterUpdateMutation):
             class Meta:
@@ -30,7 +29,7 @@ class Mutations(graphene.ObjectType):
         mutation = """
             mutation FilterUpdateDog(
                 $filter: FilterUpdateDogFilterInput!,
-                $data: FilterUpdateDogDataInput! 
+                $data: FilterUpdateDogDataInput!
             ){
                 filterUpdateDogs(filter: $filter, data: $data){
                     updatedCount
diff --git a/graphene_django_cud/tests/test_patch_mutation.py b/graphene_django_cud/tests/test_patch_mutation.py
index 9e26ba0..b4960bb 100644
--- a/graphene_django_cud/tests/test_patch_mutation.py
+++ b/graphene_django_cud/tests/test_patch_mutation.py
@@ -35,8 +35,7 @@ def mock_info(context=None):
 class TestPatchMutation(TestCase):
     def test__model_registered__does_not_raise_error(self):
         # This registers the UserNode type
-        # noinspection PyUnresolvedReferences
-        from .schema import UserNode
+        from .schema import UserNode  # noqa: F401
 
         class PatchMutation(DjangoPatchMutation):
             class Meta:
@@ -44,8 +43,7 @@ class Meta:
 
     def test_mutate__only_supply_some_fields__changes_relevant_fields(self):
         # This registers the UserNode type
-        # noinspection PyUnresolvedReferences
-        from .schema import UserNode
+        from .schema import UserNode  # noqa: F401
 
         class PatchCatMutation(DjangoPatchMutation):
             class Meta:
@@ -61,7 +59,7 @@ class Mutations(graphene.ObjectType):
         mutation = """
             mutation PatchCat(
                 $id: ID!,
-                $input: PatchCatInput! 
+                $input: PatchCatInput!
             ){
                 patchCat(id: $id, input: $input){
                     cat{
@@ -86,8 +84,7 @@ class Mutations(graphene.ObjectType):
 
     def test_permissions__user_has_no_permission__returns_error(self):
         # This registers the UserNode type
-        # noinspection PyUnresolvedReferences
-        from .schema import UserNode
+        from .schema import UserNode  # noqa: F401
 
         class PatchCatMutation(DjangoPatchMutation):
             class Meta:
@@ -124,8 +121,7 @@ class Mutations(graphene.ObjectType):
 
     def test_permissions__user_has_permission__does_not_return_error(self):
         # This registers the UserNode type
-        # noinspection PyUnresolvedReferences
-        from .schema import UserNode
+        from .schema import UserNode  # noqa: F401
 
         class PatchCatMutation(DjangoPatchMutation):
             class Meta:
@@ -141,7 +137,7 @@ class Mutations(graphene.ObjectType):
         mutation = """
             mutation PatchCat(
                 $id: ID!,
-                $input: PatchCatInput! 
+                $input: PatchCatInput!
             ){
                 patchCat(id: $id, input: $input){
                     cat{
@@ -162,8 +158,7 @@ class Mutations(graphene.ObjectType):
 
     def test_get_permissions__empty_list__overrides_and_grants_access(self):
         # This registers the UserNode type
-        # noinspection PyUnresolvedReferences
-        from .schema import UserNode
+        from .schema import UserNode  # noqa: F401
 
         class PatchCatMutation(DjangoPatchMutation):
             class Meta:
@@ -184,7 +179,7 @@ class Mutations(graphene.ObjectType):
         mutation = """
             mutation PatchCat(
                 $id: ID!,
-                $input: PatchCatInput! 
+                $input: PatchCatInput!
             ){
                 patchCat(id: $id, input: $input){
                     cat{
@@ -204,11 +199,10 @@ class Mutations(graphene.ObjectType):
         self.assertIsNone(result.errors)
 
     def test_get_permissions__list_with_permissions__requires_returned_permissions(
-            self,
+        self,
     ):
         # This registers the UserNode type
-        # noinspection PyUnresolvedReferences
-        from .schema import UserNode
+        from .schema import UserNode  # noqa: F401
 
         class PatchCatMutation(DjangoPatchMutation):
             class Meta:
@@ -222,15 +216,13 @@ class Mutations(graphene.ObjectType):
             patch_cat = PatchCatMutation.Field()
 
         user = UserFactory.create()
-        user_with_permissions = UserWithPermissionsFactory.create(
-            permissions=["tests.change_cat"]
-        )
+        user_with_permissions = UserWithPermissionsFactory.create(permissions=["tests.change_cat"])
         cat = CatFactory.create()
         schema = Schema(query=DummyQuery, mutation=Mutations)
         mutation = """
             mutation PatchCat(
                 $id: ID!,
-                $input: PatchCatInput! 
+                $input: PatchCatInput!
             ){
                 patchCat(id: $id, input: $input){
                     cat{
@@ -261,8 +253,7 @@ class Mutations(graphene.ObjectType):
 
     def test_get_permissions__conditional_list__requires_returned_permissions(self):
         # This registers the UserNode type
-        # noinspection PyUnresolvedReferences
-        from .schema import UserNode
+        from .schema import UserNode  # noqa: F401
 
         class PatchCatMutation(DjangoPatchMutation):
             class Meta:
@@ -286,7 +277,7 @@ class Mutations(graphene.ObjectType):
         mutation = """
             mutation PatchCat(
                 $id: ID!,
-                $input: PatchCatInput! 
+                $input: PatchCatInput!
             ){
                 patchCat(id: $id, input: $input){
                     cat{
@@ -322,11 +313,10 @@ class Mutations(graphene.ObjectType):
         self.assertIsNone(result.errors)
 
     def test_check_permissions__override__uses_new_check_permissions_to_grant_access(
-            self,
+        self,
     ):
         # This registers the UserNode type
-        # noinspection PyUnresolvedReferences
-        from .schema import UserNode
+        from .schema import UserNode  # noqa: F401
 
         class PatchCatMutation(DjangoPatchMutation):
             class Meta:
@@ -345,12 +335,12 @@ class Mutations(graphene.ObjectType):
             patch_cat = PatchCatMutation.Field()
 
         user = UserFactory.create()
-        cat = CatFactory.create()
+        CatFactory.create()
         schema = Schema(query=DummyQuery, mutation=Mutations)
         mutation = """
             mutation PatchCat(
                 $id: ID!,
-                $input: PatchCatInput! 
+                $input: PatchCatInput!
             ){
                 patchCat(id: $id, input: $input){
                     cat{
@@ -380,8 +370,7 @@ class Mutations(graphene.ObjectType):
 
     def test_validate__validate_field_does_nothing__passes(self):
         # This registers the UserNode type
-        # noinspection PyUnresolvedReferences
-        from .schema import UserNode
+        from .schema import UserNode  # noqa: F401
 
         class PatchCatMutation(DjangoPatchMutation):
             class Meta:
@@ -400,7 +389,7 @@ class Mutations(graphene.ObjectType):
         mutation = """
             mutation PatchCat(
                 $id: ID!,
-                $input: PatchCatInput! 
+                $input: PatchCatInput!
             ){
                 patchCat(id: $id, input: $input){
                     cat{
@@ -421,8 +410,7 @@ class Mutations(graphene.ObjectType):
 
     def test_validate__validate_field_raises__returns_error(self):
         # This registers the UserNode type
-        # noinspection PyUnresolvedReferences
-        from .schema import UserNode
+        from .schema import UserNode  # noqa: F401
 
         class PatchCatMutation(DjangoPatchMutation):
             class Meta:
@@ -443,7 +431,7 @@ class Mutations(graphene.ObjectType):
         mutation = """
             mutation PatchCat(
                 $id: ID!,
-                $input: PatchCatInput! 
+                $input: PatchCatInput!
             ){
                 patchCat(id: $id, input: $input){
                     cat{
@@ -477,8 +465,7 @@ class Mutations(graphene.ObjectType):
 
     def test_field_types__specified__overrides_field_type(self):
         # This registers the UserNode type
-        # noinspection PyUnresolvedReferences
-        from .schema import UserNode
+        from .schema import UserNode  # noqa: F401
 
         class PatchDogMutation(DjangoPatchMutation):
             class Meta:
@@ -498,7 +485,7 @@ class Mutations(graphene.ObjectType):
         mutation = """
             mutation PatchDog(
                 $id: ID!,
-                $input: PatchDogInput! 
+                $input: PatchDogInput!
             ){
                 patchDog(id: $id, input: $input){
                     dog{
@@ -542,8 +529,7 @@ class Mutations(graphene.ObjectType):
 class TestPatchMutationManyToManyOnReverseField(TestCase):
     def test_default_setup__adding_resource_by_id__adds_resource(self):
         # This registers the UserNode type
-        # noinspection PyUnresolvedReferences
-        from .schema import UserNode
+        from .schema import UserNode  # noqa: F401
 
         class PatchCatMutation(DjangoPatchMutation):
             class Meta:
@@ -560,7 +546,7 @@ class Mutations(graphene.ObjectType):
         mutation = """
             mutation PatchCat(
                 $id: ID!,
-                $input: PatchCatInput! 
+                $input: PatchCatInput!
             ){
                 patchCat(id: $id, input: $input){
                     cat{
@@ -589,8 +575,7 @@ class Mutations(graphene.ObjectType):
 
     def test_default_setup__calling_with_empty_list__resets_relation(self):
         # This registers the UserNode type
-        # noinspection PyUnresolvedReferences
-        from .schema import UserNode
+        from .schema import UserNode  # noqa: F401
 
         class PatchCatMutation(DjangoPatchMutation):
             class Meta:
@@ -611,7 +596,7 @@ class Mutations(graphene.ObjectType):
         mutation = """
             mutation PatchCat(
                 $id: ID!,
-                $input: PatchCatInput! 
+                $input: PatchCatInput!
             ){
                 patchCat(id: $id, input: $input){
                     cat{
@@ -640,8 +625,7 @@ class Mutations(graphene.ObjectType):
 
     def test_many_to_many_extras__calling_exact_with_empty_list__resets_relation(self):
         # This registers the UserNode type
-        # noinspection PyUnresolvedReferences
-        from .schema import UserNode
+        from .schema import UserNode  # noqa: F401
 
         class PatchCatMutation(DjangoPatchMutation):
             class Meta:
@@ -663,7 +647,7 @@ class Mutations(graphene.ObjectType):
         mutation = """
             mutation PatchCat(
                 $id: ID!,
-                $input: PatchCatInput! 
+                $input: PatchCatInput!
             ){
                 patchCat(id: $id, input: $input){
                     cat{
@@ -692,8 +676,7 @@ class Mutations(graphene.ObjectType):
 
     def test_many_to_many_extras__add_extra_by_id__adds_by_id(self):
         # This registers the UserNode type
-        # noinspection PyUnresolvedReferences
-        from .schema import UserNode
+        from .schema import UserNode  # noqa: F401
 
         class PatchCatMutation(DjangoPatchMutation):
             class Meta:
@@ -714,7 +697,7 @@ class Mutations(graphene.ObjectType):
         mutation = """
             mutation PatchCat(
                 $id: ID!,
-                $input: PatchCatInput! 
+                $input: PatchCatInput!
             ){
                 patchCat(id: $id, input: $input){
                     cat{
@@ -743,8 +726,7 @@ class Mutations(graphene.ObjectType):
 
     def test_many_to_many_extras__add_extra_by_input__adds_by_input(self):
         # This registers the UserNode type
-        # noinspection PyUnresolvedReferences
-        from .schema import UserNode
+        from .schema import UserNode  # noqa: F401
 
         class CreateDogMutation(DjangoCreateMutation):
             class Meta:
@@ -770,7 +752,7 @@ class Mutations(graphene.ObjectType):
         mutation = """
             mutation PatchCat(
                 $id: ID!,
-                $input: PatchCatInput! 
+                $input: PatchCatInput!
             ){
                 patchCat(id: $id, input: $input){
                     cat{
@@ -800,7 +782,6 @@ class Mutations(graphene.ObjectType):
             },
             context=Dict(user=user),
         )
-        print([dog.tag for dog in dogs])
         self.assertIsNone(result.errors)
 
         cat.refresh_from_db()
@@ -808,8 +789,7 @@ class Mutations(graphene.ObjectType):
 
     def test_many_to_many_extras__remove_extra_by_id__removes_by_id(self):
         # This registers the UserNode type
-        # noinspection PyUnresolvedReferences
-        from .schema import UserNode
+        from .schema import UserNode  # noqa: F401
 
         class PatchCatMutation(DjangoPatchMutation):
             class Meta:
@@ -831,7 +811,7 @@ class Mutations(graphene.ObjectType):
         mutation = """
             mutation PatchCat(
                 $id: ID!,
-                $input: PatchCatInput! 
+                $input: PatchCatInput!
             ){
                 patchCat(id: $id, input: $input){
                     cat{
@@ -862,8 +842,7 @@ class Mutations(graphene.ObjectType):
 class TestPatchMutationManyToManyExtras(TestCase):
     def test_many_to_many_extras__calling_exact_with_empty_list__resets_relation(self):
         # This registers the UserNode type
-        # noinspection PyUnresolvedReferences
-        from .schema import UserNode
+        from .schema import UserNode  # noqa: F401
 
         class PatchDogMutation(DjangoPatchMutation):
             class Meta:
@@ -885,7 +864,7 @@ class Mutations(graphene.ObjectType):
         mutation = """
             mutation PatchDog(
                 $id: ID!,
-                $input: PatchDogInput! 
+                $input: PatchDogInput!
             ){
                 patchDog(id: $id, input: $input){
                     dog{
@@ -916,8 +895,7 @@ class Mutations(graphene.ObjectType):
 
     def test_many_to_many_extras__add_extra_by_id__adds_by_id(self):
         # This registers the UserNode type
-        # noinspection PyUnresolvedReferences
-        from .schema import UserNode
+        from .schema import UserNode  # noqa: F401
 
         class PatchDogMutation(DjangoPatchMutation):
             class Meta:
@@ -938,7 +916,7 @@ class Mutations(graphene.ObjectType):
         mutation = """
             mutation PatchDog(
                 $id: ID!,
-                $input: PatchDogInput! 
+                $input: PatchDogInput!
             ){
                 patchDog(id: $id, input: $input){
                     dog{
@@ -969,8 +947,7 @@ class Mutations(graphene.ObjectType):
 
     def test_many_to_many_extras__add_extra_by_input__adds_by_input(self):
         # This registers the UserNode type
-        # noinspection PyUnresolvedReferences
-        from .schema import UserNode
+        from .schema import UserNode  # noqa: F401
 
         class CreateCatMutation(DjangoCreateMutation):
             class Meta:
@@ -996,7 +973,7 @@ class Mutations(graphene.ObjectType):
         mutation = """
             mutation PatchDog(
                 $id: ID!,
-                $input: PatchDogInput! 
+                $input: PatchDogInput!
             ){
                 patchDog(id: $id, input: $input){
                     dog{
@@ -1015,9 +992,7 @@ class Mutations(graphene.ObjectType):
                     "tag": "tag",
                     "breed": "HUSKY",
                     "owner": to_global_id("UserNode", user.id),
-                    "enemies": [
-                        {"name": cat.name, "owner": cat.owner.id} for cat in cats
-                    ],
+                    "enemies": [{"name": cat.name, "owner": cat.owner.id} for cat in cats],
                 },
             },
             context=Dict(user=user),
@@ -1029,8 +1004,7 @@ class Mutations(graphene.ObjectType):
 
     def test_many_to_many_extras__remove_extra_by_id__removes_by_id(self):
         # This registers the UserNode type
-        # noinspection PyUnresolvedReferences
-        from .schema import UserNode
+        from .schema import UserNode  # noqa: F401
 
         class PatchDogMutation(DjangoPatchMutation):
             class Meta:
@@ -1052,7 +1026,7 @@ class Mutations(graphene.ObjectType):
         mutation = """
             mutation PatchDog(
                 $id: ID!,
-                $input: PatchDogInput! 
+                $input: PatchDogInput!
             ){
                 patchDog(id: $id, input: $input){
                     dog{
@@ -1084,11 +1058,10 @@ class Mutations(graphene.ObjectType):
 
 class TestPatchMutationManyToOneExtras(TestCase):
     def test_many_to_one_extras__auto_calling_mutation_with_setting_field__does_nothing(
-            self,
+        self,
     ):
         # This registers the UserNode type
-        # noinspection PyUnresolvedReferences
-        from .schema import UserNode
+        from .schema import UserNode  # noqa: F401
 
         class PatchUserMutation(DjangoPatchMutation):
             class Meta:
@@ -1107,7 +1080,7 @@ class Mutations(graphene.ObjectType):
         mutation = """
             mutation PatchUser(
                 $id: ID!,
-                $input: PatchUserInput! 
+                $input: PatchUserInput!
             ){
                 patchUser(id: $id, input: $input){
                     user{
@@ -1137,8 +1110,7 @@ class Mutations(graphene.ObjectType):
 
     def test_many_to_one_extras__calling_exact_with_empty_list__resets_relation(self):
         # This registers the UserNode type
-        # noinspection PyUnresolvedReferences
-        from .schema import UserNode
+        from .schema import UserNode  # noqa: F401
 
         class PatchUserMutation(DjangoPatchMutation):
             class Meta:
@@ -1152,14 +1124,14 @@ class Mutations(graphene.ObjectType):
         user = UserFactory.create()
 
         # Create some enemies
-        cats = CatFactory.create_batch(5, owner=user)
+        CatFactory.create_batch(5, owner=user)
         self.assertEqual(user.cats.all().count(), 5)
 
         schema = Schema(query=DummyQuery, mutation=Mutations)
         mutation = """
             mutation PatchUser(
                 $id: ID!,
-                $input: PatchUserInput! 
+                $input: PatchUserInput!
             ){
                 patchUser(id: $id, input: $input){
                     user{
@@ -1190,8 +1162,7 @@ class Mutations(graphene.ObjectType):
 
     def test_many_to_one_extras__set_exact_by_id__sets_by_id(self):
         # This registers the UserNode type
-        # noinspection PyUnresolvedReferences
-        from .schema import UserNode
+        from .schema import UserNode  # noqa: F401
 
         class PatchUserMutation(DjangoPatchMutation):
             class Meta:
@@ -1212,7 +1183,7 @@ class Mutations(graphene.ObjectType):
         mutation = """
             mutation PatchUser(
                 $id: ID!,
-                $input: PatchUserInput! 
+                $input: PatchUserInput!
             ){
                 patchUser(id: $id, input: $input){
                     user{
@@ -1243,8 +1214,7 @@ class Mutations(graphene.ObjectType):
 
     def test_many_to_one_extras__add_by_id__adds_by_id(self):
         # This registers the UserNode type
-        # noinspection PyUnresolvedReferences
-        from .schema import UserNode
+        from .schema import UserNode  # noqa: F401
 
         class PatchUserMutation(DjangoPatchMutation):
             class Meta:
@@ -1258,7 +1228,7 @@ class Mutations(graphene.ObjectType):
         user = UserFactory.create()
 
         # Create some enemies
-        cats = CatFactory.create_batch(5, owner=user)
+        CatFactory.create_batch(5, owner=user)
         other_cats = CatFactory.create_batch(5)
         self.assertEqual(user.cats.all().count(), 5)
 
@@ -1266,7 +1236,7 @@ class Mutations(graphene.ObjectType):
         mutation = """
             mutation PatchUser(
                 $id: ID!,
-                $input: PatchUserInput! 
+                $input: PatchUserInput!
             ){
                 patchUser(id: $id, input: $input){
                     user{
@@ -1297,8 +1267,7 @@ class Mutations(graphene.ObjectType):
 
     def test_many_to_one_extras__add_by_input__adds_by_input(self):
         # This registers the UserNode type
-        # noinspection PyUnresolvedReferences
-        from .schema import UserNode
+        from .schema import UserNode  # noqa: F401
 
         class CreateCatMutation(DjangoCreateMutation):
             class Meta:
@@ -1323,7 +1292,7 @@ class Mutations(graphene.ObjectType):
         mutation = """
             mutation PatchUser(
                 $id: ID!,
-                $input: PatchUserInput! 
+                $input: PatchUserInput!
             ){
                 patchUser(id: $id, input: $input){
                     user{
@@ -1354,8 +1323,7 @@ class Mutations(graphene.ObjectType):
 
     def test_many_to_one_extras__remove_extra_by_id__removes_by_id(self):
         # This registers the UserNode type
-        # noinspection PyUnresolvedReferences
-        from .schema import UserNode
+        from .schema import UserNode  # noqa: F401
 
         class PatchUserMutation(DjangoPatchMutation):
             class Meta:
@@ -1377,7 +1345,7 @@ class Mutations(graphene.ObjectType):
         mutation = """
             mutation PatchUser(
                 $id: ID!,
-                $input: PatchUserInput! 
+                $input: PatchUserInput!
             ){
                 patchUser(id: $id, input: $input){
                     user{
@@ -1408,8 +1376,7 @@ class Mutations(graphene.ObjectType):
 
     def test_many_to_one_extras__remove_nullable_field__removes_by_id(self):
         # This registers the UserNode type
-        # noinspection PyUnresolvedReferences
-        from .schema import UserNode
+        from .schema import UserNode  # noqa: F401
 
         class PatchUserMutation(DjangoPatchMutation):
             class Meta:
@@ -1431,7 +1398,7 @@ class Mutations(graphene.ObjectType):
         mutation = """
             mutation PatchUser(
                 $id: ID!,
-                $input: PatchUserInput! 
+                $input: PatchUserInput!
             ){
                 patchUser(id: $id, input: $input){
                     user{
@@ -1464,15 +1431,12 @@ class Mutations(graphene.ObjectType):
 class TestPatchMutationForeignKeyExtras(TestCase):
     def test_auto_type__with_proper_setup__generates_new_auto_type(self):
         # This registers the UserNode type
-        # noinspection PyUnresolvedReferences
-        from .schema import UserNode
+        from .schema import UserNode  # noqa: F401
 
         class PatchDogMutation(DjangoPatchMutation):
             class Meta:
                 model = Dog
-                foreign_key_extras = {
-                    "owner": {"type": "auto", "exclude": ["password"]}
-                }
+                foreign_key_extras = {"owner": {"type": "auto", "exclude": ["password"]}}
 
         class Mutations(graphene.ObjectType):
             patch_dog = PatchDogMutation.Field()
@@ -1484,7 +1448,7 @@ class Mutations(graphene.ObjectType):
         mutation = """
             mutation PatchDog(
                 $id: ID!,
-                $input: PatchDogInput! 
+                $input: PatchDogInput!
             ){
                 patchDog(id: $id, input: $input){
                     dog{
@@ -1519,17 +1483,16 @@ class Mutations(graphene.ObjectType):
 
 
 class TestPatchMutationCustomFields(TestCase):
-    def test_custom_field__separate_from_model_fields__adds_new_field_which_can_be_handled(self):
+    def test_custom_field__separate_from_model_fields__adds_new_field_which_can_be_handled(
+        self,
+    ):
         # This registers the UserNode type
-        # noinspection PyUnresolvedReferences
-        from .schema import UserNode
+        from .schema import UserNode  # noqa: F401
 
         class PatchDogMutation(DjangoPatchMutation):
             class Meta:
                 model = Dog
-                custom_fields = {
-                    "bark": graphene.Boolean()
-                }
+                custom_fields = {"bark": graphene.Boolean()}
 
             @classmethod
             def before_save(cls, root, info, input, id, obj: Dog):
@@ -1547,7 +1510,7 @@ class Mutations(graphene.ObjectType):
         mutation = """
             mutation PatchDog(
                 $id: ID!,
-                $input: PatchDogInput! 
+                $input: PatchDogInput!
             ){
                 patchDog(id: $id, input: $input){
                     dog{
@@ -1567,7 +1530,7 @@ class Mutations(graphene.ObjectType):
                     "tag": "tag",
                     "breed": "HUSKY",
                     "bark": True,
-                    "owner": to_global_id("UserNode", user.id)
+                    "owner": to_global_id("UserNode", user.id),
                 },
             },
             context=Dict(user=user),
@@ -1585,7 +1548,7 @@ class Mutations(graphene.ObjectType):
                     "name": "Sparky",
                     "tag": "tag",
                     "breed": "HUSKY",
-                    "owner": to_global_id("UserNode", user.id)
+                    "owner": to_global_id("UserNode", user.id),
                 },
             },
             context=Dict(user=user),
@@ -1599,8 +1562,7 @@ class Mutations(graphene.ObjectType):
 class TestPatchMutationRequiredFields(TestCase):
     def setUp(self):
         # This registers the UserNode type
-        # noinspection PyUnresolvedReferences
-        from .schema import UserNode
+        from .schema import UserNode  # noqa: F401
 
         class PatchDogMutation(DjangoPatchMutation):
             class Meta:
@@ -1622,7 +1584,7 @@ class Mutations(graphene.ObjectType):
         self.mutation = """
             mutation PatchDog(
                 $id: ID!,
-                $input: PatchDogInput! 
+                $input: PatchDogInput!
             ){
                 patchDog(id: $id, input: $input){
                     dog {
@@ -1640,7 +1602,7 @@ def test_required_fields__when_set_and_not_provided__returns_error(self):
                 "id": self.dog_id,
                 "input": {
                     "name": "Lassie",
-                }
+                },
             },
             context=self.context,
         )
@@ -1651,10 +1613,7 @@ def test_required_fields__when_set_and_provided__returns_no_error(self):
             self.mutation,
             variables={
                 "id": self.dog_id,
-                "input": {
-                    "name": "Lassie",
-                    "owner": self.user2_id
-                }
+                "input": {"name": "Lassie", "owner": self.user2_id},
             },
             context=self.context,
         )
diff --git a/graphene_django_cud/tests/test_update_mutation.py b/graphene_django_cud/tests/test_update_mutation.py
index de99d5b..9c599d7 100644
--- a/graphene_django_cud/tests/test_update_mutation.py
+++ b/graphene_django_cud/tests/test_update_mutation.py
@@ -35,8 +35,7 @@ def mock_info(context=None):
 class TestUpdateMutation(TestCase):
     def test__model_registered__does_not_raise_error(self):
         # This registers the UserNode type
-        # noinspection PyUnresolvedReferences
-        from .schema import UserNode
+        from .schema import UserNode  # noqa: F401
 
         class UpdateMutation(DjangoUpdateMutation):
             class Meta:
@@ -44,8 +43,7 @@ class Meta:
 
     def test_permissions__user_has_no_permission__returns_error(self):
         # This registers the UserNode type
-        # noinspection PyUnresolvedReferences
-        from .schema import UserNode
+        from .schema import UserNode  # noqa: F401
 
         class UpdateCatMutation(DjangoUpdateMutation):
             class Meta:
@@ -82,8 +80,7 @@ class Mutations(graphene.ObjectType):
 
     def test_permissions__user_has_permission__does_not_return_error(self):
         # This registers the UserNode type
-        # noinspection PyUnresolvedReferences
-        from .schema import UserNode
+        from .schema import UserNode  # noqa: F401
 
         class UpdateCatMutation(DjangoUpdateMutation):
             class Meta:
@@ -99,7 +96,7 @@ class Mutations(graphene.ObjectType):
         mutation = """
             mutation UpdateCat(
                 $id: ID!,
-                $input: UpdateCatInput! 
+                $input: UpdateCatInput!
             ){
                 updateCat(id: $id, input: $input){
                     cat{
@@ -120,8 +117,7 @@ class Mutations(graphene.ObjectType):
 
     def test_get_permissions__empty_list__overrides_and_grants_access(self):
         # This registers the UserNode type
-        # noinspection PyUnresolvedReferences
-        from .schema import UserNode
+        from .schema import UserNode  # noqa: F401
 
         class UpdateCatMutation(DjangoUpdateMutation):
             class Meta:
@@ -142,7 +138,7 @@ class Mutations(graphene.ObjectType):
         mutation = """
             mutation UpdateCat(
                 $id: ID!,
-                $input: UpdateCatInput! 
+                $input: UpdateCatInput!
             ){
                 updateCat(id: $id, input: $input){
                     cat{
@@ -165,8 +161,7 @@ def test_get_permissions__list_with_permissions__requires_returned_permissions(
         self,
     ):
         # This registers the UserNode type
-        # noinspection PyUnresolvedReferences
-        from .schema import UserNode
+        from .schema import UserNode  # noqa: F401
 
         class UpdateCatMutation(DjangoUpdateMutation):
             class Meta:
@@ -180,15 +175,13 @@ class Mutations(graphene.ObjectType):
             update_cat = UpdateCatMutation.Field()
 
         user = UserFactory.create()
-        user_with_permissions = UserWithPermissionsFactory.create(
-            permissions=["tests.change_cat"]
-        )
+        user_with_permissions = UserWithPermissionsFactory.create(permissions=["tests.change_cat"])
         cat = CatFactory.create()
         schema = Schema(query=DummyQuery, mutation=Mutations)
         mutation = """
             mutation UpdateCat(
                 $id: ID!,
-                $input: UpdateCatInput! 
+                $input: UpdateCatInput!
             ){
                 updateCat(id: $id, input: $input){
                     cat{
@@ -219,8 +212,7 @@ class Mutations(graphene.ObjectType):
 
     def test_get_permissions__conditional_list__requires_returned_permissions(self):
         # This registers the UserNode type
-        # noinspection PyUnresolvedReferences
-        from .schema import UserNode
+        from .schema import UserNode  # noqa: F401
 
         class UpdateCatMutation(DjangoUpdateMutation):
             class Meta:
@@ -244,7 +236,7 @@ class Mutations(graphene.ObjectType):
         mutation = """
             mutation UpdateCat(
                 $id: ID!,
-                $input: UpdateCatInput! 
+                $input: UpdateCatInput!
             ){
                 updateCat(id: $id, input: $input){
                     cat{
@@ -283,8 +275,7 @@ def test_check_permissions__override__uses_new_check_permissions_to_grant_access
         self,
     ):
         # This registers the UserNode type
-        # noinspection PyUnresolvedReferences
-        from .schema import UserNode
+        from .schema import UserNode  # noqa: F401
 
         class UpdateCatMutation(DjangoUpdateMutation):
             class Meta:
@@ -303,12 +294,12 @@ class Mutations(graphene.ObjectType):
             update_cat = UpdateCatMutation.Field()
 
         user = UserFactory.create()
-        cat = CatFactory.create()
+        CatFactory.create()
         schema = Schema(query=DummyQuery, mutation=Mutations)
         mutation = """
             mutation UpdateCat(
                 $id: ID!,
-                $input: UpdateCatInput! 
+                $input: UpdateCatInput!
             ){
                 updateCat(id: $id, input: $input){
                     cat{
@@ -338,8 +329,7 @@ class Mutations(graphene.ObjectType):
 
     def test_validate__validate_field_does_nothing__passes(self):
         # This registers the UserNode type
-        # noinspection PyUnresolvedReferences
-        from .schema import UserNode
+        from .schema import UserNode  # noqa: F401
 
         class UpdateCatMutation(DjangoUpdateMutation):
             class Meta:
@@ -353,12 +343,12 @@ class Mutations(graphene.ObjectType):
             update_cat = UpdateCatMutation.Field()
 
         user = UserFactory.create()
-        cat = CatFactory.create()
+        CatFactory.create()
         schema = Schema(query=DummyQuery, mutation=Mutations)
         mutation = """
             mutation UpdateCat(
                 $id: ID!,
-                $input: UpdateCatInput! 
+                $input: UpdateCatInput!
             ){
                 updateCat(id: $id, input: $input){
                     cat{
@@ -379,8 +369,7 @@ class Mutations(graphene.ObjectType):
 
     def test_validate__validate_field_raises__returns_error(self):
         # This registers the UserNode type
-        # noinspection PyUnresolvedReferences
-        from .schema import UserNode
+        from .schema import UserNode  # noqa: F401
 
         class UpdateCatMutation(DjangoUpdateMutation):
             class Meta:
@@ -396,12 +385,12 @@ class Mutations(graphene.ObjectType):
             update_cat = UpdateCatMutation.Field()
 
         user = UserFactory.create(first_name="John", last_name="Doe")
-        cat = CatFactory.create()
+        CatFactory.create()
         schema = Schema(query=DummyQuery, mutation=Mutations)
         mutation = """
             mutation UpdateCat(
                 $id: ID!,
-                $input: UpdateCatInput! 
+                $input: UpdateCatInput!
             ){
                 updateCat(id: $id, input: $input){
                     cat{
@@ -435,8 +424,7 @@ class Mutations(graphene.ObjectType):
 
     def test_field_types__specified__overrides_field_type(self):
         # This registers the UserNode type
-        # noinspection PyUnresolvedReferences
-        from .schema import UserNode
+        from .schema import UserNode  # noqa: F401
 
         class UpdateDogMutation(DjangoUpdateMutation):
             class Meta:
@@ -456,7 +444,7 @@ class Mutations(graphene.ObjectType):
         mutation = """
             mutation UpdateDog(
                 $id: ID!,
-                $input: UpdateDogInput! 
+                $input: UpdateDogInput!
             ){
                 updateDog(id: $id, input: $input){
                     dog{
@@ -500,8 +488,7 @@ class Mutations(graphene.ObjectType):
 class TestUpdateMutationManyToManyOnReverseField(TestCase):
     def test_default_setup__adding_resource_by_id__adds_resource(self):
         # This registers the UserNode type
-        # noinspection PyUnresolvedReferences
-        from .schema import UserNode
+        from .schema import UserNode  # noqa: F401
 
         class UpdateCatMutation(DjangoUpdateMutation):
             class Meta:
@@ -518,7 +505,7 @@ class Mutations(graphene.ObjectType):
         mutation = """
             mutation UpdateCat(
                 $id: ID!,
-                $input: UpdateCatInput! 
+                $input: UpdateCatInput!
             ){
                 updateCat(id: $id, input: $input){
                     cat{
@@ -547,8 +534,7 @@ class Mutations(graphene.ObjectType):
 
     def test_default_setup__calling_with_empty_list__resets_relation(self):
         # This registers the UserNode type
-        # noinspection PyUnresolvedReferences
-        from .schema import UserNode
+        from .schema import UserNode  # noqa: F401
 
         class UpdateCatMutation(DjangoUpdateMutation):
             class Meta:
@@ -569,7 +555,7 @@ class Mutations(graphene.ObjectType):
         mutation = """
             mutation UpdateCat(
                 $id: ID!,
-                $input: UpdateCatInput! 
+                $input: UpdateCatInput!
             ){
                 updateCat(id: $id, input: $input){
                     cat{
@@ -598,8 +584,7 @@ class Mutations(graphene.ObjectType):
 
     def test_many_to_many_extras__calling_exact_with_empty_list__resets_relation(self):
         # This registers the UserNode type
-        # noinspection PyUnresolvedReferences
-        from .schema import UserNode
+        from .schema import UserNode  # noqa: F401
 
         class UpdateCatMutation(DjangoUpdateMutation):
             class Meta:
@@ -621,7 +606,7 @@ class Mutations(graphene.ObjectType):
         mutation = """
             mutation UpdateCat(
                 $id: ID!,
-                $input: UpdateCatInput! 
+                $input: UpdateCatInput!
             ){
                 updateCat(id: $id, input: $input){
                     cat{
@@ -650,8 +635,7 @@ class Mutations(graphene.ObjectType):
 
     def test_many_to_many_extras__add_extra_by_id__adds_by_id(self):
         # This registers the UserNode type
-        # noinspection PyUnresolvedReferences
-        from .schema import UserNode
+        from .schema import UserNode  # noqa: F401
 
         class UpdateCatMutation(DjangoUpdateMutation):
             class Meta:
@@ -672,7 +656,7 @@ class Mutations(graphene.ObjectType):
         mutation = """
             mutation UpdateCat(
                 $id: ID!,
-                $input: UpdateCatInput! 
+                $input: UpdateCatInput!
             ){
                 updateCat(id: $id, input: $input){
                     cat{
@@ -701,8 +685,7 @@ class Mutations(graphene.ObjectType):
 
     def test_many_to_many_extras__add_extra_by_input__adds_by_input(self):
         # This registers the UserNode type
-        # noinspection PyUnresolvedReferences
-        from .schema import UserNode
+        from .schema import UserNode  # noqa: F401
 
         class CreateDogMutation(DjangoCreateMutation):
             class Meta:
@@ -728,7 +711,7 @@ class Mutations(graphene.ObjectType):
         mutation = """
             mutation UpdateCat(
                 $id: ID!,
-                $input: UpdateCatInput! 
+                $input: UpdateCatInput!
             ){
                 updateCat(id: $id, input: $input){
                     cat{
@@ -765,8 +748,7 @@ class Mutations(graphene.ObjectType):
 
     def test_many_to_many_extras__remove_extra_by_id__removes_by_id(self):
         # This registers the UserNode type
-        # noinspection PyUnresolvedReferences
-        from .schema import UserNode
+        from .schema import UserNode  # noqa: F401
 
         class UpdateCatMutation(DjangoUpdateMutation):
             class Meta:
@@ -788,7 +770,7 @@ class Mutations(graphene.ObjectType):
         mutation = """
             mutation UpdateCat(
                 $id: ID!,
-                $input: UpdateCatInput! 
+                $input: UpdateCatInput!
             ){
                 updateCat(id: $id, input: $input){
                     cat{
@@ -819,8 +801,7 @@ class Mutations(graphene.ObjectType):
 class TestUpdateMutationManyToManyExtras(TestCase):
     def test_many_to_many_extras__calling_exact_with_empty_list__resets_relation(self):
         # This registers the UserNode type
-        # noinspection PyUnresolvedReferences
-        from .schema import UserNode
+        from .schema import UserNode  # noqa: F401
 
         class UpdateDogMutation(DjangoUpdateMutation):
             class Meta:
@@ -842,7 +823,7 @@ class Mutations(graphene.ObjectType):
         mutation = """
             mutation UpdateDog(
                 $id: ID!,
-                $input: UpdateDogInput! 
+                $input: UpdateDogInput!
             ){
                 updateDog(id: $id, input: $input){
                     dog{
@@ -873,8 +854,7 @@ class Mutations(graphene.ObjectType):
 
     def test_many_to_many_extras__add_extra_by_id__adds_by_id(self):
         # This registers the UserNode type
-        # noinspection PyUnresolvedReferences
-        from .schema import UserNode
+        from .schema import UserNode  # noqa: F401
 
         class UpdateDogMutation(DjangoUpdateMutation):
             class Meta:
@@ -895,7 +875,7 @@ class Mutations(graphene.ObjectType):
         mutation = """
             mutation UpdateDog(
                 $id: ID!,
-                $input: UpdateDogInput! 
+                $input: UpdateDogInput!
             ){
                 updateDog(id: $id, input: $input){
                     dog{
@@ -926,8 +906,7 @@ class Mutations(graphene.ObjectType):
 
     def test_many_to_many_extras__add_extra_by_input__adds_by_input(self):
         # This registers the UserNode type
-        # noinspection PyUnresolvedReferences
-        from .schema import UserNode
+        from .schema import UserNode  # noqa: F401
 
         class CreateCatMutation(DjangoCreateMutation):
             class Meta:
@@ -953,7 +932,7 @@ class Mutations(graphene.ObjectType):
         mutation = """
             mutation UpdateDog(
                 $id: ID!,
-                $input: UpdateDogInput! 
+                $input: UpdateDogInput!
             ){
                 updateDog(id: $id, input: $input){
                     dog{
@@ -972,9 +951,7 @@ class Mutations(graphene.ObjectType):
                     "tag": "tag",
                     "breed": "HUSKY",
                     "owner": to_global_id("UserNode", user.id),
-                    "enemies": [
-                        {"name": cat.name, "owner": cat.owner.id} for cat in cats
-                    ],
+                    "enemies": [{"name": cat.name, "owner": cat.owner.id} for cat in cats],
                 },
             },
             context=Dict(user=user),
@@ -986,8 +963,7 @@ class Mutations(graphene.ObjectType):
 
     def test_many_to_many_extras__remove_extra_by_id__removes_by_id(self):
         # This registers the UserNode type
-        # noinspection PyUnresolvedReferences
-        from .schema import UserNode
+        from .schema import UserNode  # noqa: F401
 
         class UpdateDogMutation(DjangoUpdateMutation):
             class Meta:
@@ -1009,7 +985,7 @@ class Mutations(graphene.ObjectType):
         mutation = """
             mutation UpdateDog(
                 $id: ID!,
-                $input: UpdateDogInput! 
+                $input: UpdateDogInput!
             ){
                 updateDog(id: $id, input: $input){
                     dog{
@@ -1042,8 +1018,7 @@ def test_many_to_many_extras__type_auto__makes_it_possible_to_add_new_full_objec
         self,
     ):
         # This registers the UserNode type
-        # noinspection PyUnresolvedReferences
-        from .schema import UserNode
+        from .schema import UserNode  # noqa: F401
 
         class UpdateDogMutation(DjangoUpdateMutation):
             class Meta:
@@ -1062,7 +1037,7 @@ class Mutations(graphene.ObjectType):
         mutation = """
             mutation UpdateDog(
                 $id: ID!,
-                $input: UpdateDogInput! 
+                $input: UpdateDogInput!
             ){
                 updateDog(id: $id, input: $input){
                     dog{
@@ -1102,8 +1077,7 @@ def test_many_to_one_extras__auto_calling_mutation_with_setting_field__does_noth
         self,
     ):
         # This registers the UserNode type
-        # noinspection PyUnresolvedReferences
-        from .schema import UserNode
+        from .schema import UserNode  # noqa: F401
 
         class UpdateUserMutation(DjangoUpdateMutation):
             class Meta:
@@ -1122,7 +1096,7 @@ class Mutations(graphene.ObjectType):
         mutation = """
             mutation UpdateUser(
                 $id: ID!,
-                $input: UpdateUserInput! 
+                $input: UpdateUserInput!
             ){
                 updateUser(id: $id, input: $input){
                     user{
@@ -1152,8 +1126,7 @@ class Mutations(graphene.ObjectType):
 
     def test_many_to_one_extras__calling_exact_with_empty_list__resets_relation(self):
         # This registers the UserNode type
-        # noinspection PyUnresolvedReferences
-        from .schema import UserNode
+        from .schema import UserNode  # noqa: F401
 
         class UpdateUserMutation(DjangoUpdateMutation):
             class Meta:
@@ -1167,14 +1140,14 @@ class Mutations(graphene.ObjectType):
         user = UserFactory.create()
 
         # Create some enemies
-        cats = CatFactory.create_batch(5, owner=user)
+        CatFactory.create_batch(5, owner=user)
         self.assertEqual(user.cats.all().count(), 5)
 
         schema = Schema(query=DummyQuery, mutation=Mutations)
         mutation = """
             mutation UpdateUser(
                 $id: ID!,
-                $input: UpdateUserInput! 
+                $input: UpdateUserInput!
             ){
                 updateUser(id: $id, input: $input){
                     user{
@@ -1205,8 +1178,7 @@ class Mutations(graphene.ObjectType):
 
     def test_many_to_one_extras__set_exact_by_id__sets_by_id(self):
         # This registers the UserNode type
-        # noinspection PyUnresolvedReferences
-        from .schema import UserNode
+        from .schema import UserNode  # noqa: F401
 
         class UpdateUserMutation(DjangoUpdateMutation):
             class Meta:
@@ -1227,7 +1199,7 @@ class Mutations(graphene.ObjectType):
         mutation = """
             mutation UpdateUser(
                 $id: ID!,
-                $input: UpdateUserInput! 
+                $input: UpdateUserInput!
             ){
                 updateUser(id: $id, input: $input){
                     user{
@@ -1258,8 +1230,7 @@ class Mutations(graphene.ObjectType):
 
     def test_many_to_one_extras__add_by_id__adds_by_id(self):
         # This registers the UserNode type
-        # noinspection PyUnresolvedReferences
-        from .schema import UserNode
+        from .schema import UserNode  # noqa: F401
 
         class UpdateUserMutation(DjangoUpdateMutation):
             class Meta:
@@ -1273,7 +1244,7 @@ class Mutations(graphene.ObjectType):
         user = UserFactory.create()
 
         # Create some enemies
-        cats = CatFactory.create_batch(5, owner=user)
+        CatFactory.create_batch(5, owner=user)
         other_cats = CatFactory.create_batch(5)
         self.assertEqual(user.cats.all().count(), 5)
 
@@ -1281,7 +1252,7 @@ class Mutations(graphene.ObjectType):
         mutation = """
             mutation UpdateUser(
                 $id: ID!,
-                $input: UpdateUserInput! 
+                $input: UpdateUserInput!
             ){
                 updateUser(id: $id, input: $input){
                     user{
@@ -1312,8 +1283,7 @@ class Mutations(graphene.ObjectType):
 
     def test_many_to_one_extras__add_by_input__adds_by_input(self):
         # This registers the UserNode type
-        # noinspection PyUnresolvedReferences
-        from .schema import UserNode
+        from .schema import UserNode  # noqa: F401
 
         class CreateCatMutation(DjangoCreateMutation):
             class Meta:
@@ -1338,7 +1308,7 @@ class Mutations(graphene.ObjectType):
         mutation = """
             mutation UpdateUser(
                 $id: ID!,
-                $input: UpdateUserInput! 
+                $input: UpdateUserInput!
             ){
                 updateUser(id: $id, input: $input){
                     user{
@@ -1369,8 +1339,7 @@ class Mutations(graphene.ObjectType):
 
     def test_many_to_one_extras__remove_extra_by_id__removes_by_id(self):
         # This registers the UserNode type
-        # noinspection PyUnresolvedReferences
-        from .schema import UserNode
+        from .schema import UserNode  # noqa: F401
 
         class UpdateUserMutation(DjangoUpdateMutation):
             class Meta:
@@ -1392,7 +1361,7 @@ class Mutations(graphene.ObjectType):
         mutation = """
             mutation UpdateUser(
                 $id: ID!,
-                $input: UpdateUserInput! 
+                $input: UpdateUserInput!
             ){
                 updateUser(id: $id, input: $input){
                     user{
@@ -1423,8 +1392,7 @@ class Mutations(graphene.ObjectType):
 
     def test_many_to_one_extras__remove_nullable_field__removes_by_id(self):
         # This registers the UserNode type
-        # noinspection PyUnresolvedReferences
-        from .schema import UserNode
+        from .schema import UserNode  # noqa: F401
 
         class UpdateUserMutation(DjangoUpdateMutation):
             class Meta:
@@ -1446,7 +1414,7 @@ class Mutations(graphene.ObjectType):
         mutation = """
             mutation UpdateUser(
                 $id: ID!,
-                $input: UpdateUserInput! 
+                $input: UpdateUserInput!
             ){
                 updateUser(id: $id, input: $input){
                     user{
@@ -1479,15 +1447,12 @@ class Mutations(graphene.ObjectType):
 class TestUpdateMutationForeignKeyExtras(TestCase):
     def test_auto_type__with_proper_setup__generates_new_auto_type(self):
         # This registers the UserNode type
-        # noinspection PyUnresolvedReferences
-        from .schema import UserNode
+        from .schema import UserNode  # noqa: F401
 
         class UpdateDogMutation(DjangoUpdateMutation):
             class Meta:
                 model = Dog
-                foreign_key_extras = {
-                    "owner": {"type": "auto", "exclude": ["password"]}
-                }
+                foreign_key_extras = {"owner": {"type": "auto", "exclude": ["password"]}}
 
         class Mutations(graphene.ObjectType):
             update_dog = UpdateDogMutation.Field()
@@ -1499,7 +1464,7 @@ class Mutations(graphene.ObjectType):
         mutation = """
             mutation UpdateDog(
                 $id: ID!,
-                $input: UpdateDogInput! 
+                $input: UpdateDogInput!
             ){
                 updateDog(id: $id, input: $input){
                     dog{
@@ -1538,8 +1503,7 @@ def test_custom_field__separate_from_model_fields__adds_new_field_which_can_be_h
         self,
     ):
         # This registers the UserNode type
-        # noinspection PyUnresolvedReferences
-        from .schema import UserNode
+        from .schema import UserNode  # noqa: F401
 
         class UpdateDogMutation(DjangoUpdateMutation):
             class Meta:
@@ -1562,7 +1526,7 @@ class Mutations(graphene.ObjectType):
         mutation = """
             mutation UpdateDog(
                 $id: ID!,
-                $input: UpdateDogInput! 
+                $input: UpdateDogInput!
             ){
                 updateDog(id: $id, input: $input){
                     dog{
diff --git a/graphene_django_cud/tests/urls.py b/graphene_django_cud/tests/urls.py
index a4a343f..d68bd85 100644
--- a/graphene_django_cud/tests/urls.py
+++ b/graphene_django_cud/tests/urls.py
@@ -1,6 +1,4 @@
 from django.urls import re_path
 from graphene_file_upload.django import FileUploadGraphQLView
 
-urlpatterns = [
-    re_path(r'^graphql', FileUploadGraphQLView.as_view(graphiql=True))
-]
+urlpatterns = [re_path(r"^graphql", FileUploadGraphQLView.as_view(graphiql=True))]
diff --git a/test_settings.py b/test_settings.py
index 72aaf9d..d00fb81 100644
--- a/test_settings.py
+++ b/test_settings.py
@@ -12,7 +12,6 @@
     "django.contrib.sessions",
     "django.contrib.messages",
     "django.contrib.staticfiles",
-
     "graphene_django_cud",
     "graphene_django_cud.tests",
     "graphene_django",
@@ -28,9 +27,7 @@
     "django.middleware.clickjacking.XFrameOptionsMiddleware",
 ]
 
-DATABASES = {
-    "default": {"ENGINE": "django.db.backends.sqlite3", "NAME": "django_test.sqlite"}
-}
+DATABASES = {"default": {"ENGINE": "django.db.backends.sqlite3", "NAME": "django_test.sqlite"}}
 
 TEMPLATES = [
     {