I know this question has come up but many answers refer to older versions of Django and Python. I am running Django 3 and Python 3.
Besides in our project we have decided to separate each model in its own file under a "models" folder. Please see below our tree structure:
├── db.sqlite3
├── manage.py
├── poi
│ ├── admin.py
│ ├── apps.py
│ ├── CHANGELOG.md
│ ├── fabfile.py
│ ├── __init__.py
│ ├── LICENSE
│ ├── migrations
│ │ ├── 0001_initial.py
│ │ ├── 0002_auto_20210104_1048.py
│ │ ├── __init__.py
│ │ └── __pycache__
│ │ ├── 0001_initial.cpython-38.pyc
│ │ ├── 0002_auto_20210104_1048.cpython-38.pyc
│ │ └── __init__.cpython-38.pyc
│ ├── models
│ │ ├── __init__.py
│ │ ├── layer.py
│ │ ├── poi.py
│ │ ├── __pycache__
│ │ │ ├── __init__.cpython-38.pyc
│ │ │ ├── layer.cpython-38.pyc
│ │ │ ├── poi.cpython-38.pyc
│ │ │ └── tag.cpython-38.pyc
│ │ └── tag.py
│ ├── models.py
In our models/init.py we have:
from .poi import Poi
from .tag import Tag
from .layer import Layer
In our models/poi/poi.py we have:
from django.db import models
from .tag import Tag
from .layer import Layer
class Poi(models.Model):
...
...
tags = models.ManyToManyField('Tag', through='Layer')
def __str__(self):
return self.name
In our models/poi/tag.py we have:
from django.db import models
import poi.models.poi
import poi.models.layer
class Tag(models.Model):
name = models.CharField(max_length=100)
pois = models.ManyToManyField('Poi', through='Layer')
def __str__(self):
return self.name
In our models/poi/layer.py we have:
from django.db import models
import poi.models.poi
import poi.models.tag
class Layer(models.Model):
poi = models.ForeignKey(Poi, on_delete=models.CASCADE)
tag = models.ForeignKey(Tag, on_delete=models.CASCADE)
The error comes up when we run python3 manage.py makemigrations.
Error:
File "/media/elena/DATA2/Python-projects/osm-pois/osm-pois/upoi/poi/models/layer.py", line 8, in Layer
poi = models.ForeignKey(Poi, on_delete=models.CASCADE)
NameError: name 'Poi' is not defined
We have tried other ways of import in layer.py such as:
from .poi import Poi
from .tag import Tag
But that gave us the following error:
File "/media/elena/DATA2/Python-projects/osm-pois/osm-pois/upoi/poi/models/layer.py", line 2, in <module>
from .poi import Poi
ImportError: cannot import name 'Poi' from partially initialized module 'poi.models.poi' (most likely due to a circular import) (/media/elena/DATA2/Python-projects/osm-pois/osm-pois/upoi/poi/models/poi.py)
Any idea of how to solve this? Thanks!
I am posting as an answer what #TonySuffolk66 suggested via a comment since it worked perfectly. Thanks again!
Because your models are defined in different files, try doing this : poi = models.ForeignKey('Poi', on_delete=models.CASCADE) That is using a string for the model name, not a reference name. You can't 'easily' import other models like this due to the way that Django initializes
Related
Im writing a library for internal use,its called "etllib", and I have the following structure:
etl-lib
├── README.md
├── etllib
│ ├── __init__.py
│ ├── client
│ │ ├── __init__.py
│ │ ├── elastic.py
│ │ └── qradar.py
│ ├── etl
│ │ ├── __init__.py
│ │ └── etl_imperva.py
│ └── util
│ ├── __init__.py
│ ├── config.py
│ ├── daemon.py
│ ├── elastic
│ │ ├── __init__.py
│ │ └── impeva_index_config.py
│ └── imperva
│ ├── __init__.py
│ ├── kpe_config.py
│ └── query_config.py
├── scripts
│ └── etl_imperva
└── setup.py
And I have a script called "etl_imperva" in etllib/scripts. The code inside looks like this :
#!/usr/bin/python3
import sys
from etllib.etl.etl_imperva import ETL
# Run with python3 imperva_run.py start|run|stop|restart
ETL.startup(sys.argv)
If I install this package(etllib) and call this script, it works just fine. But when I need to test stuff, how can I tell python to use the modules that are on my working directory instead the ones are installed? Because each time I make a change on the modules, I need to reinstall the package and this is a little time consuming.
I also tried uninstalling the package for testing, but whe I run this script I get the following error :
Exception has occurred: ModuleNotFoundError
No module named 'etllib'
File "/home/jleonse/etl-lib/scripts/run_imperva", line 3, in <module>
from etllib.etl.etl_imperva import ETL
Is there a better way to do this?
Actually, it is not on the same level in the hierarchy.
from etllib.etl.etl_imperva import ETL
would work only if etllib was in the same directory or in a directory in your system PATH, but the etllib is in the parent directory, hence it can not find it.
so you can make it work if you change the project structure to be:
etl-lib
├── README.md
├── etllib
│ ├── __init__.py
│ ├── client
│ │ ├── __init__.py
│ │ ├── elastic.py
│ │ └── qradar.py
│ ├── etl
│ │ ├── __init__.py
│ │ └── etl_imperva.py
│ └── util
│ ├── __init__.py
│ ├── config.py
│ ├── daemon.py
│ ├── elastic
│ │ ├── __init__.py
│ │ └── impeva_index_config.py
│ └── imperva
│ ├── __init__.py
│ ├── kpe_config.py
│ └── query_config.py
├── etl_imperva
│
└── setup.py
I have the next directory structure:
.
├── README.md
├── my_import
│ ├── __init__.py
│ ├── items.py
│ ├── middlewares.py
│ ├── pipelines.py
│ ├── spiders
│ │ ├── __init__.py
│ │ ├── spider1.py
│ │ ├── spider2.py
│ │ ├── spider3.py
│ ├── settings.py
│ ├── test.py
├── requirements.txt
├── scrapy.cfg
I want to test a one method of spider1 with unittests.
test.py
import unittest
from spiders.spider1 import SpiderA
class TestResult(unittest.TestCase):
def test_return(self):
string1 = '1'
string2 = '1st'
item = SpiderA()
self.assertEqual(item.get_result(string1), string1)
if __name__ == '__main__':
unittest.main()
But I received the error:
ModuleNotFoundError: No module named 'my_import'
However I am able to import settings.py, items.py, pipelines.py files in test.py file.
I think this is due to the reason I am importing class from items.py inside of spider1.py file and this caused this error.
Any ideas how I can overcome this issue?
I think what u have to do is :
from products_spiders.spider1 import SpiderA
I have a directory that looks like this:
├── libraryweb
│ ├── __init__.py
│ ├── __init__.pyc
│ ├── __pycache__
│ │ ├── __init__.cpython-37.pyc
│ │ ├── forms.cpython-37.pyc
│ │ ├── models.cpython-37.pyc
│ │ └── routes.cpython-37.pyc
│ ├── forms.py
│ ├── models.py
│ ├── routes.py
│ ├── save_books.py
│ ├── site.db
│ ├── static
│ │ ├── book_pics
│ │ └── user_pics
│ │ └── default.jpg
│ └── templates
│ ├── account.html
│ ├── base.html
│ ├── book.html
│ ├── book_update.html
│ ├── home.html
│ ├── login.html
│ └── register.html
└── run.py
Now in the file save_books.py, I want to import a class Book from models.py in the libraryweb module. I have tried from libraryweb.models import Book, from .models import Book, and from models import Book, but none of them works.
The __init__.py file contains the following code:
from flask_sqlalchemy import SQLAlchemy
from flask import Flask
from flask_bcrypt import Bcrypt
from flask_login import LoginManager
import os
app = Flask(__name__)
app.config['SECRET_KEY'] = os.environ.get('SECRET_KEY')
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///site.db'
db = SQLAlchemy(app)
bcrypt = Bcrypt(app)
login_manager = LoginManager(app)
login_manager.login_view='login'
login_manager.login_message_category='info'
from libraryweb import routes
I got the following error message:
Exception has occurred: ModuleNotFoundError
No module named 'libraryweb'
File "/Users/gracezhou/cs/python_flask/flask-library/hey/libraryweb/save_books.py", line 3, in <module>
from libraryweb.models import Book
Have you set your PYTHONPATH variable pointing to your application path ?
Can you please show your ouput of below command.
import sys
sys.path
All directories where module files are exist needed to be in PYTHONPATH env variable. If you dump everything in the single directory then you just need folder which contains python files into your PYTHONPATH. Refer to below https://docs.python.org/3/library/sys.html#sys.path
I'm trying to run django unittest using VSCode, not terminal.
my project tree looks like this:
├── db.sqlite3
├── hero
│ ├── __init__.py
│ ├── __pycache__
│ │ ├── __init__.cpython-37.pyc
│ │ ├── admin.cpython-37.pyc
│ │ ├── apps.cpython-37.pyc
│ │ ├── models.cpython-37.pyc
│ │ ├── tests.cpython-37.pyc
│ │ ├── urls.cpython-37.pyc
│ │ └── views.cpython-37.pyc
│ ├── admin.py
│ ├── apps.py
│ ├── migrations
│ │ ├── 0001_initial.py
│ │ ├── 0002_hero_age.py
│ │ ├── __init__.py
│ │ └── __pycache__
│ │ ├── 0001_initial.cpython-37.pyc
│ │ ├── 0002_hero_age.cpython-37.pyc
│ │ └── __init__.cpython-37.pyc
│ ├── models.py
│ ├── tests.py
│ ├── urls.py
│ └── views.py
├── manage.py
└── toh
├── __init__.py
├── __pycache__
│ ├── __init__.cpython-37.pyc
│ ├── settings.cpython-37.pyc
│ ├── urls.cpython-37.pyc
│ └── wsgi.cpython-37.pyc
├── settings.py
├── urls.py
└── wsgi.py
I made tests.py file inside hero directory.
My tests.py code looks like this:
from django.test import TestCase, Client
from .models import Hero
# Create your tests here.
class HeroTestCase(TestCase):
def setUp(self):
Hero.objects.create(name='Superman', age=10)
Hero.objects.create(name='Batman', age=1)
Hero.objects.create(name='Ironman', age=30)
def test_hero_count(self):
self.assertEqual(Hero.objects.all().count(), 3)
def test_hero_id(self):
client=Client()
response=client.get('/hero/1/')
self.assertEqual(response.status_code, 200)
self.assertIn('1', response.content.decode())
def test_hero_visit_count(self):
client = Client()
response = client.get('/hero/hello')
self.assertEqual(response.status_code, 200)
self.assertIn('1', response.content.decode())
response = client.get('/hero/hello')
self.assertEqual(response.status_code, 200)
self.assertIn('2', response.content.decode())
And my .vscode/settings.json looks like this:
{
"python.pythonPath": "/anaconda3/bin/python",
"python.linting.pylintEnabled": true,
"python.linting.enabled": true,
"python.testing.unittestArgs": [
"-v",
"-s",
"./hero",
"-p",
"*test*.py"
],
"python.testing.pytestEnabled": false,
"python.testing.nosetestsEnabled": false,
"python.testing.unittestEnabled": true
}
But when I ran test by VSCode this error keeps coming out.
======================================================================
ERROR: tests (unittest.loader._FailedTest)
----------------------------------------------------------------------
ImportError: Failed to import test module: tests
Traceback (most recent call last):
File "/anaconda3/lib/python3.7/unittest/loader.py", line 436, in _find_test_path
module = self._get_module_from_name(name)
File "/anaconda3/lib/python3.7/unittest/loader.py", line 377, in _get_module_from_name
__import__(name)
File "toh/hero/tests.py", line 2, in <module>
from .models import Hero
ImportError: attempted relative import with no known parent package
Or:
django.core.exceptions.ImproperlyConfigured: Requested setting INSTALLED_APPS, but settings are not configured. You must either define the environment variable DJANGO_SETTINGS_MODULE or call settings.configure() before accessing settings.
So I checked whether there are something wrong with my test code, but my test code pass when I ran python manage.py test ! How do I resolve this problem?
The relative import problem is because you set -p to hero which changes the top-level directory to that and so it no longer looks like a package to Python.
The configuration problem is because unittest isn't running manage.py. You can go to https://github.com/microsoft/vscode-python/issues/73 and 👍 the issue to vote for it to be prioritized.
I have the following directory structure in my home projects folder.
|ALL-IN-ONE
|demo
|__init__.py
|__main__.py
|models
|grpc
|allinone_server.py
And I want to import from allinone_server.py a function defined in main.py called images_demo. I have tried
from demo.__main__ import images_demo
It is not working. How can I import it? The function I am trying to import is located inside main.py which is inside demo directory. I am trying to import it from the file allinone_server.py in grpc. I guess I have made my question clear now.
Here is the whole tree for the project
├── demo
│ ├── __init__.py
│ ├── __main__.py
│ └── __pycache__
│ ├── __init__.cpython-36.pyc
│ └── main.cpython-36.pyc
├── description
├── environment.yml
├── HEAD
├── hooks
│ ├── applypatch-msg.sample
│ ├── commit-msg.sample
│ ├── fsmonitor-watchman.sample
│ ├── post-update.sample
│ ├── pre-applypatch.sample
│ ├── pre-commit.sample
│ ├── prepare-commit-msg.sample
│ ├── pre-push.sample
│ ├── pre-rebase.sample
│ ├── pre-receive.sample
│ └── update.sample
├── imgs
│ └── 44.jpg
├── info
│ └── exclude
├── __init__.py
├── loggers
│ ├── __init__.py
│ └── __pycache__
│ └── __init__.cpython-36.pyc
├── models
│ ├── adience_large1.h5
│ ├── adience_small1.h5
│ ├── AgeModel.json
│ ├── detection_age_gender_large1.h5
│ ├── detection_age_gender_small1.h5
│ ├── detection_age_gender_smile_large1.h5
│ ├── detection_age_gender_smile_small1.h5
│ ├── detection_age_large1.h5
│ ├── detection_age_small1.h5
│ ├── detection_large1.h5
│ ├── detection_small1.h5
│ ├── grpc
│ │ ├── adele_2016.jpg
│ │ ├── allinone_client.py
│ │ ├── all_in_one_pb2_grpc.py
│ │ ├── all_in_one_pb2.py
│ │ ├── all_in_one.proto
│ │ ├── allinone_server.py
│ │ ├── benedict_cumberbatch_2014.png
│ │ ├── cat.png
│ │ ├── classroom_in_tanzania.jpg
│ │ ├── decoded1.py
│ │ ├── decoded.py
│ │ ├── elon_musk_2015.jpg
│ │ ├── laos.jpg
│ │ ├── model_face.jpg
│ │ ├── __pycache__
│ │ │ ├── all_in_one_pb2.cpython-36.pyc
│ │ │ ├── all_in_one_pb2_grpc.cpython-36.pyc
│ │ │ └── decoded.cpython-36.pyc
│ │ ├── sophia.jpg
│ │ ├── test
│ │ │ ├── __init__.py
│ │ │ ├── __pycache__
│ │ │ │ └── __init__.cpython-36.pyc
│ │ │ └── test_images
│ │ │ ├── adele_2016.jpg
│ │ │ ├── benedict_cumberbatch_2014.png
│ │ │ ├── classroom_in_tanzania.jpg
│ │ │ ├── elon_musk_2015.jpg
│ │ │ ├── __init__.py
│ │ │ ├── laos.jpg
│ │ │ ├── model_face.jpg
│ │ │ ├── sophia.jpg
│ │ │ ├── waaah.jpg
│ │ │ ├── woman.jpg
│ │ │ └── zebra_stripes.jpg
│ │ ├── waaah.jpg
│ │ ├── woman.jpg
│ │ └── zebra_stripes.jpg
So you've referred to main.py, but you also have __main__.py in your directory structure. I'll assume that your directory actually contains main.py instead of __main__.py.
To import from levels up in a package, start your import with a period.
To import just one function you would use from .main import images_demo
Now, let's start by saying main.py is in grpc/ along with allinone_server.py, then we'll move it to different directories and see how the import changes.
If it were in grpc/ from .main import images_demo
If it were in models/ from ..main import images_demo
If it were in __ALL-IN-ONE/ from ...main import images_demo
If it were in __demo/ from ...__demo.main import images_demo
Every extra period brings you up one level in the hierarchy, then you use the name of the next level down in the target path until you reach where you want to be.
Now let's suppose you wanted to import the whole of main.py.
If it were in grpc/ from . import main
If it were in models/ from .. import main
If it were in __ALL-IN-One/ from ... import main
If it were in __demo/ from ...__demo import main
Finally, the dot notation to move up a level only works if the file that uses it is in a package, so this will work fine if at the top level you start your program in a scope outside of this package then use from __ALL-IN-ONE.models.grpc import allinone_server
However, if you run allinone_server.py directly then it will fail to import anything above it as it isn't being imported as part of a package. Try that out, and let me know if that needs better explanation.
Good luck!
You can't import a function from another folder directly and for that you have to use this:
import sys
sys.path.insert(0, "../../demo/")
Another step is to rename __main__ to main.
here is the exact example that worked for me:
The tree:
.
├── demo
│ ├── __init__.py
│ ├── main.py
│
└── models
└── grpc
└── allinone_server.py
main.py:
def images_demo():
print("hello there")
The calling file(allinone_server.py):
import sys
sys.path.insert(0, "../../demo/")
import main
main.images_demo()