47

I'm implementing a graphql solution using python, graphene and django and I'm getting the following import error:

Result: Failure Exception: ImportError: cannot import name 'force_text' from 'django.utils.encoding'

"/home/site/wwwroot/.python_packages/lib/site-packages/graphene_django/utils/utils.py", line 6, in <module> from django.utils.encoding import force_text

I'm not sure about the versions and whether I need to import an additional module. My requirements.txt is like:

graphene>=2.1,<3
graphene-django>=2.1,<3
graphql-core>=2.1,<3
graphql-relay==2.0.1
django-filter>=2

Has someone had a similar problem and can look at the versions that I use? Thanks

Super Kai - Kazuya Ito
  • 22,221
  • 10
  • 124
  • 129
Gerd
  • 777
  • 1
  • 7
  • 12
  • This post will help you https://stackoverflow.com/a/25178353/14457833 – Ankit Tiwari Dec 16 '21 at 16:05
  • What django version you are using? – Luiz Dec 16 '21 at 16:11
  • thanks I have seen this post as well. However its not fully clear to me. Mainly I need graphene_django. Do I need to downgrade the django core? – Gerd Dec 16 '21 at 16:13
  • in graphene_django.utils.utils.py the line 6 is the problem: from django.utils.encoding import force_text as django is not in my requirements.txt it is not clear to me, which version can avoid this error. print(django.__version__) returns 4.0 – Gerd Dec 16 '21 at 19:41
  • Exact same error when I ignored package version numbers doing the tutorial from https://www.howtographql.com/ . +1 thanks for asking before me :) – Jeffery Dec 22 '21 at 22:52

7 Answers7

76

in django 4.0 we dont have force_text

https://docs.djangoproject.com/en/4.0/ref/utils/#module-django.utils.encoding

instead change force_text to force_str

linux:

YOUR_VENV/lib/PYTHON_VERSION/site-packages/graphene_django/utils/utils.py

windows:

YOUR_VENV/lib/site-packages/graphene_django/utils/utils.py

from django.utils.encoding import force_text

to

from django.utils.encoding import force_str

and

def _camelize_django_str(s):
    if isinstance(s, Promise):
        s = force_text(s)
    return to_camel_case(s) if isinstance(s, six.string_types) else s

to

def _camelize_django_str(s):
    if isinstance(s, Promise):
        s = force_str(s)
    return to_camel_case(s) if isinstance(s, six.string_types) else s
Osman
  • 902
  • 6
  • 10
  • 8
    thanks for your answer. I can change it locally in the venv, however this is not a valid solution as I'm deploying to the cloud and the venv will be created on the target. – Gerd Dec 17 '21 at 08:56
  • you can also edit on remote server – Osman Dec 17 '21 at 10:48
31

Based on answer given by @Osman.

The problem seems to be occuring with Django-4. Till the PR gets merged, probably this monkeypatching might work (not tested in prod):

import django
from django.utils.encoding import force_str
django.utils.encoding.force_text = force_str

Put this in entryfile. I kept it in settings.py for time being.

Blaze
  • 1,642
  • 2
  • 22
  • 20
  • what is this entryfile file? – Ankit Kumar Jan 26 '22 at 17:01
  • 2
    entryfile (entrypoint) could be anything which invokes first in order to spun the entire application. In my case, I used settings.py. Idea is to change the imported object before it's called by anything else. – Blaze Jan 27 '22 at 10:27
  • 2
    This is a hacky but cleaner workaround! Cleaner because upgrading `graphene_django` will not need any subsequent change. Hacky because changing class attributes at run-time is considered a hack. – manisar Feb 09 '22 at 06:24
  • this works well, i used those lines in settings.py – EDMOND GIHOZO Aug 17 '22 at 18:52
  • 1
    today this hack didn't work anymore. I had to replace all `force_text` by `force_str` – Damien Romito May 03 '23 at 15:10
14

In Django version 4> just paste this snippet to your settinsg.py. Preferably on the top

    import django
    from django.utils.encoding import force_str
    django.utils.encoding.force_text = force_str
zeph
  • 141
  • 1
  • 2
12

force_text is removed from Django 4.0 but the old version of graphene_django still uses force_text in utils.py. *You can see Features removed in 4.0.

So, upgrading graphene-django will solve the error easily:

pip install graphene-django --upgrade

Or, replace force_text with force_str as shown below:

# "utils.py"

# from django.utils.encoding import force_text # Line 6
from django.utils.encoding import force_str # Line 6

# s = force_text(s) # Line 29
s = force_str(s) # Line 29

These are the paths to utils.py for Linux and Windows:

Linux:

<your_venv>/lib/<python_version>/site-packages/graphene_django/utils/utils.py

Windows:

<your_venv>/lib/site-packages/graphene_django/utils/utils.py

Super Kai - Kazuya Ito
  • 22,221
  • 10
  • 124
  • 129
3

adding the following to the requirements.txt solved it:

django<=3
Gerd
  • 777
  • 1
  • 7
  • 12
  • 2
    Careful if you are using this method because you might not get the latest version of Django 3. You might get the 3.0 version which has many vulnerabilities. Instead, create a file `requirements.in` with `Django<4` for example. Then do `pip install pip-compile` and then `pip-compile`. This will regenerated requirements.txt with dependencies, and finally `pip-compile --upgrade` to get the latest versions of packages. – aks May 26 '22 at 16:49
0

You can install graphene-django version 3.0.0b7 run the following command in your terminal:

pip install graphene-django==3.0.0b7 

It's beta version, but i don't know why graphene-django 2.15 does'nt work, when patch note said they fixed issue since 2.8.1 version.

Thank's to @Behoston from this Github issue for this solution

yoles
  • 21
  • 1
0

I have been running into a similar issue whereby including "graphql_jwt.refresh_token.apps.RefreshTokenConfig" in INSTALLED_APPS leads to the following import error:

ImportError: cannot import name 'force_text' from 'django.utils.encoding'

I added this at the top of settings.py:

import django
from django.utils.encoding import force_str
django.utils.encoding.force_text = force_str

And was greeted with this error:

ImportError: cannot import name 'ugettext' from 'django.utils.translation'

Where I then added the following to the top of settings.py:

from django.utils.translation import gettext, gettext_lazy
django.utils.translation.ugettext = gettext
django.utils.translation.ugettext_lazy = gettext_lazy

And delightfully resolved this error:

TypeError: __init__() got an unexpected keyword argument 'providing_args'

Django version 4.2.