How to import models from outside Django BASE_DIR - python

I am working on a Django app in which I want to import some class/function from generator.py into my views.py to process an user-submitted input. My folder structure looks like this:
project/
models/
__init__.py
generator.py
web/
django/
__init__.py
settings.py
urls.py
wsgi.py
django_app
__init__.py
views.py
etc.
Inside views.py, I have
from ...models.generator import Generator
When I try to run server, what I get is:
ValueError: attempted relative import beyond top-level package
I've seen many answers, but most are about manipulating sys.path or changing PYTHONPATH. I'm not sure how and where to do either cause I'm rather new to Django.
Can someone tell me exactly which commands to run to allow the import to be done?

Import of python is based on sys.path and cannot be outside the top-level dir. More information.
That's mean, if you append top of BASE_DIR path in sys.path you can import. But it's a tricky way.
def import_function():
import sys
sys.path.append(os.path.dirname(BASE_DIR))
module = __import__('models.generator') # import code
sys.path.pop()
return module
g_module = import_function()
g_module.Generator

Related

Can't import modules

I've searched for this problem and tried different solutions but can't fix it.
In my Django project I have different apps and a non-app directory called 'testing_utils' with modules which serve for a testing purposes. In particular I want to import all available models to file dummy_factory.py. However when I simply import modules from my apps like so:
from abc import ABC
from datetime import date
from users.models import User
I get the error message
ModuleNotFoundError: No module named 'users'
Which is strange since I definetley can import models to some_app.views.py and access them.
Here's an example of my project's directory:
/home/user/dev/project/
▸ project/
▾ testing_utils/
dummy_factory.py
▾ users/
▸ __pycache__/
▸ migrations/
▸ templates/
▸ tests/
__init__.py
admin.py
apps.py
models.py
views.py
manage.py*
/home/user/dev/project/ needs to be in your PYTHONPATH to be able to be imported.
If your testing_utils is meant to be local only, the easiest way to accomplish this is to add:
import sys
sys.path.append('/home/user/dev/project/')
... in dummy_factory.py before importing the module.
Solutions that would be more proper would be to install users (how exactly you'd make your package installable depends on your system and what version of Python and Pip you need to support), or to use a virtualenv that automatically adds the right directories to PYTHONPATH.

How to import from project level package in Django without conflicting with app level module with same name?

I have a Django project (Python 2.7.15) with the following structure:
mysite/
manage.py
mysite/
__init__.py
settings.py
urls.py
wsgi.py
polls/
__init__.py
admin.py
apps.py
migrations/
__init__.py
models.py
tests.py
views.py
utils.py
utils/
__init__.py
filters.py
In my utils/filters.py file I have a class MyFilter. From polls/admin.py, however, when I try to run from utils.filters import MyFilter, I get ImportError: No module named filters. How can I import my custom filter inside the polls app without renaming the polls/utils.py module or the utils package?
NOTE: This it's not a circular import problem. This happens even if I don't import anything from utils/filters.py. It's a name conflict between utils/ and polls/utils.py. Python tries to find filters.MyFilter inside polls/utils.py and it doesn't find it so it throws the error. I just want to figure out a way to bypass this conflict and force python to look for filters.MyFilter inside the utils/ package in the project root.
In Python 2, import utils is ambiguous because it can be a relative or an absolute import.
If you enable the Python 3 behaviour by adding the following import to the top of your module,
from __future__ import absolute_import
then from utils.filters import MyFilter will be treated as an absolute import and will work.
Once you have added the future import, you would need to use an explicit relative import import .utils if you wanted to import polls/utils.py from polls/admin.py.

Python relative import error?

ı have a django project and i need to access some of models in my folder that under the django main project folder.Let me illustrate this.
src\
main\
urls.py
models.py
view.py
lib\
__init__.py
helper.py
This is the example folder structure and i need to import some class of main app's models inside the helper.py.I tried these:
from main.models import exampleClass
from ..main.models import exampleClass
And i also tried adding a __init__.py file in the main project folder:
src\
...
main\
lib\
__init__.py
Always errors 2 kind :
1)ValueError : relative import error
2) no module name..
I need the solution and need good explanation why i failed always.Thank you so much guys.
Add __init__.py in main folder instead of src folder. Then try to import using from main.models import exampleClass. It should be working.
You don't need .. if main and lib are both django's apps, and you have registered them in INSTALLED_APPS settings.
If main and lib are in the same level that manage.py:
src/
main/
...
lib/
...
manage.py
...
You just need:
from main.models import exampleClass
How did you set $PYTHONPATH variable ? The search paths are relative to this environment variable.
So if you want to specify a path like main.models, it should contain the src directory.
Note that you can also manage it with the sys.path array.
Django normally add all the applications to sys.path. You may try to print it inside the settings.py file to have an idea.
To add a path from the settings.py file of the project, you could do something like:
import os.path
BASE_DIR = os.path.dirname(os.path.dirname(__file__))
sys.path.append(os.path.join(BASE_DIR, "../lib"))
If for example you have a lib directory at the same level as the directory that contains the settings.py file.

Importing a module into a custom command

Suppose I have the following Django project:
/ # Project dir
/myapp # App dir
/myapp/views.py # views file
/myapp/mymodule.py # a Python module
/myapp/management/commands/mycommand.py # command file
In the views file, I can import mymodule.py by simply writing import mymodule in views.py. However, if I do the same in mycommand.py, I get the error: ImportError: no module named mymodule. I know that to import a model, I can write from myapp.models import mymodel, but mymodule is not a model, it is a separate Python module. So, how do I import this moduel into my command file?
Thats because of where mymodule is in relation to all of your other files.
If you type
from myapp import mymodule
In mycommand.py as long as you have set up your __init__.py files correctly in myapp and are using a setup.py file you should be fine. The modules documentation has more information on this
The fact that you are unable to do this means your myapp folder is not in the python's sys.path. The reason it worked in views.py is because mymodule.py is in the current directory of views.py
Assuming your Project dir (/) is in the python's sys.path:
Add a file __init__.py in myapp directory. This file can be blank.
Then you can do import myapp.mymodule or from myapp import mymodule
The same logic applies for n levels deep. If you have myapp/myappdir1/myappdir2/myfile.py you can do import myapp.myappdir1.myappdir2.myfile assuming each of these have __init__.py file in them.
Check https://docs.python.org/2/tutorial/modules.html#the-module-search-path for python's module search path

import python class into another folder in a package

I'm trying to import a python class from another folder of my python package but I this error "No module named models".
It's a Flask project.
-app
|-run.py
|-myapp
|- libs
|- updateto
|- __init__.py (empty)
|- connection.py
|- removeto
|- __init__.py (empty)
|- static
|- templates
|- __init__.py (NOT empty)
|- routes.py
|- models.py
My init.py:
from flask import Flask
app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///maindb.db'
from models import db
db.init_app(app)
import myapp.routes
In my models.py I've a class named: application
And in connection.py I want import my class "application".
I've try with "from models import application" but I've this error "no modules named models".
I think it's possible to reach this goal with the modification of the init.py in the "updateto" folder but I'm no sure because I don't clearly understand the functioning of the init.py file...
Thanks
EDIT:
Which is weird, it's if under connection.py I add "import myapp" and "print(help(myapp))", I've this output:
Help on package myapp:
NAME
myapp
FILE
c:\app\myapp\__init__.py
PACKAGE CONTENTS
libs (package)
models
routes
DATA
app = <Flask 'myapp'>
But if I try "from myapp import models" I've this error "ImportError: cannot import name models"
EDIT2:
If I try to add in connection.py "from myapp import app", it works but not if I try to import models... I'm very surprised. I've try to add in myapp/init.py:
__all__ = ["models", "routes]
But same error...
EDIT3:
hummmm I've move all my modules under the libs folder into myapp and when I try to put in connection.py "from model import application" I've always the same error "ImportError: cannot import name application"
Other test in connection.py:
import models
print(models)
Output:
<module 'myapp.models' from 'C:\app\myapp\models.pyc'>
I can import my module named models but I can't import the class under models.py
EDIT4:
Ok, I think I found the problem. It's my ini.py in myapp, because if I comment this file content, the connection.py can now import my class application in models. I run the file run.py which uses routes.py and it's him that calls operation.py
With some tests, I've find the lines who create my error:
from models import db
db.init_app(app)
import myapp.routes
But why????
I don't know about Flask specifically, but in Python you should generally include a __init__.py in every folder and subfolder for them to be recognised as modules and/or packages.
In the diagram you provide, there is no __init__.py in the app folder. Try putting one and re-post if that resolves your problem.
If it doesn't work, try:
import os
print(os.getcwd())
If the current working directory isn't the app directory, you'll have to work around this. One way would be:
import sys
sys.path.append('/path/to/app')
import myapp.models
You can always see what directories are in your search path for modules by checking sys.path.
Update: Sorry I just realized that maybe you' re trying to run connections.py as a script. That would change you working directory to that of connections.py. Try importing connections.py from your main script with import models inside connections.py and see if you get an error.
Update (in reply to Edit 4): (I don't have enough reputation points to comment yet, so I reply here)
from models import db
db.init_app(app)
import myapp.routes
The problem in this piece of code is the import myapp.routes. Change that to import routes and it should work. As a rule of thumb, your main script's directory is your root directory. You can import any module located in your root directory from inside any other module (even modules inside a sub-folder!) with a simple import module.

Categories