2

I'm using Django, and I like to separate my models, views, and tests into subdirectories.

But, this means that I need to maintain an __init__.py in each subdirectory that imports every module in that directory.

I'd rather just put some call in that says:

from some_library import import_everything
import_everything() 

That would have the same effect as iterating over the current directory and importing every .py file in that directory.

What's the best/easiest way to implement this?

Here are what my django application directories (essentially) look like:

some_django_app/
    models/
        __init__.py
        create.py
        read.py
        update.py 
        delete.py
    views/
        __init__.py
        create.py
        read.py
        update.py
        delete.py
    forms/ 
        __init__.py
        create.py
        update.py
    tests/
        __init__.py
        create.py
        read.py
        update.py
        delete.py

So, you can see that to make a "proper" Django app, all my init.py files need to import all the other .py files in each directory. I'd rather just have some simple boilerplate there.

S.Lott
  • 384,516
  • 81
  • 508
  • 779
slacy
  • 11,397
  • 8
  • 56
  • 61

2 Answers2

4

Within your app/models/__init__.py add these lines:

    from app.models.create import *
    from app.models.read import *
    from app.models.update import *
    from app.models.delete import *

This'll be your best bet for conciseness and readability. from app.models import * will now load all classes/etc from within each of the other files. Likewise, from app.models import foo will load foo no matter which of these files it's defined in.

Izkata
  • 8,961
  • 2
  • 40
  • 50
  • Yes, that's exactly what I'm doing now and I find it burdensome. For every new test case or form, I need to keep updating __init__.py. For most cases (models, views) this is OK but for tests it's the worst, since I like to have lots of files there instead of one giant tests.py and __init__.py is getting dozens of lines in it. – slacy Jan 30 '12 at 20:10
  • @slacy That sounds like a bad way to organize it. Why not split your tests into logical groupings - model_tests.py, view_tests.py, and so on? (Or some other grouping that makes sense for that app, like user_tests, guest_tests, or whatever) – Izkata Jan 30 '12 at 21:04
  • Yeah, actually, we do have model_tests.py and view_tests, but even those files get >1000 lines and we end up splitting them out. :) – slacy Jan 30 '12 at 22:28
1

Using the information given in synthesizerpatel's answer, you could implement import_everything this way:

import os
import sys

def import_everything(path):
    # Insert near the beginning so path will be the item removed with sys.path.remove(path) below
    # (The case when sys.path[0] == path works fine too).
    # Do not insert at index 0 since sys.path[0] may have a special meaning
    sys.path.insert(1,path)
    for filename in os.listdir(path):
        if filename.endswith('.py'):
            modname = filename.replace('.py', '')
            module = __import__(modname, fromlist = [True])
            attrs = getattr(module, '__all__',
                            (attr for attr in dir(module) if not attr.startswith('_')))
            for attr in attrs:
                # print('Adding {a}'.format(a = attr))
                globals()[attr] = getattr(module, attr)
    sys.path.remove(path)

and could be used like this:

print(globals().keys())
# ['import_everything', '__builtins__', '__file__', '__package__', 'sys', '__name__', 'os', '__doc__']

import_everything(os.path.expanduser('~/test'))

print(globals().keys())
# ['hashlib', 'pythonrc', 'import_everything', '__builtins__', 'get_input', '__file__', '__package__', 'sys', 'mp', 'time', 'home', '__name__', 'main', 'os', '__doc__', 'user']
Community
  • 1
  • 1
unutbu
  • 842,883
  • 184
  • 1,785
  • 1,677