[Fixed]-How does django convert string to modules?

15👍

Since Django 1.7 there is a simple function for this. For example:

from django.utils.module_loading import import_string
my_module = import_string('path.to.my_module')

You can also get classes from the module:

MyClass = import_string('path.to.my_module.MyClass')

8👍

Take a look in django.conf.__init__.py, but basically it uses importlib like so:

try:
    mod = importlib.import_module(self.SETTINGS_MODULE)
except ImportError, e:
    raise ImportError("Could not import settings '%s' 
               (Is it on sys.path? Does it have syntax errors?):
                %s" % (self.SETTINGS_MODULE, e))

# Settings that should be converted into tuples if they're mistakenly entered
# as strings.
tuple_settings = ("INSTALLED_APPS", "TEMPLATE_DIRS")

Edit: At the request of the OP I’ve expanded the example and contributed some more below.

Now, suppose you had a list of functions in this module, defined in for example FUNCTIONS TO CALL, a list of functions. Then, you could call each like this:

ARGUMENTS = '()'

for FUNCTION in FUNCTIONS_TO_CALL:
    function_string = FUNCTION + ARGUMENTS
    exec(function_string)

This assumes each function has the same set of defined arguments. You could use an if statement to detect the function name listed by the user and supply custom arguments depending on what this is. You could also evaluate from reading the python file what the arguments should be.

You could also check the module object to (I assume this is possible, I don’t know) see if that function exists before calling exec() or eval(). I don’t know, again, if one can evaluate from the function object what arguments it takes. I suspect so, but this is a separate (possibly already answered?) question.

0👍

You can use import_string() to import a model with a dotted module path as the doc says below:

Imports a dotted module path and returns the attribute/class
designated by the last name in the path. Raises ImportError if the
import failed.

For example, you have Person model in my_app/models.py as shown below:

# "my_app/models.py"

class Person(models.Model):
    name = models.CharField(max_length=20)

Then, you can import Person model with import_string() in my_app/views.py as shown below:

# "my_app/views.py"

from django.http import HttpResponse
from django.utils.module_loading import import_string

def test(request): # ↓ Imports "Person" model ↓
    Person = import_string('my_app.models.Person')
    print(Person.objects.all())
    return HttpResponse("Test")

And, the code above is same as the code below:

# "my_app/views.py"

from django.http import HttpResponse
from .models import Person # Imports "Person" model

def test(request):
    print(Person.objects.all())
    return HttpResponse("Test")

Then, the outputs on console is the same:

<QuerySet [<Person: Person object (1)>, <Person: Person object (2)>]>

Leave a comment