I have a python script test.py that imports make_password function from Django library. It does it like this:
from django.contrib.auth.hashers import make_password
.... a lot of other stuff
def init():
...
if __name__ == "__main__":
init()
So, I want to run it from the command line like:
python test.py
But this results in a whole list of error messages, which are all about importing Django module. If I comment out from django.contrib.auth.hashers import make_password, then everything is ok (except the fact that I can't use make_password function).
The error messages your are getting are most likely complaints that the settings module is not available.
Django initializes its runtime environment (via django.core.management.setup_environ()) when you import any of its core modules. The django ecosystem is not meant to function without a valid project environment.
You have at least two options:
1. Manually set django settings module
import os
os.environ['DJANGO_SETTINGS_MODULE'] = 'yourapp.settings'
from django.contrib.auth.hashers import make_password
...
Note that this requires yourapp.settings to be available via sys.path, so it might be necessary to explicitly add the project path to sys.path (or PYTHON_PATH).
Other versions of basically the same thing are available.
2. Build a management command
This is explained in some detail in the documentation.
In principle, you need to provide a yourapp.management.mycommand module that contains a single Command class:
class Command(BaseCommand):
def handle(self, *args, **options):
# make_password()
The command can be run through django's manage.py.
Related
I am writing a web app using python3, venv and c9.io PAAS. I have the following structure of my code:
batch_runner.py
logic/
__init__.py
parsers/
__init__.py
time_parser.py
abstract_parser.py
here batch_runner imports abstract_parser, which, in it turn, import from time_parser. everything was installed and runs with venv activated.
To be specific, batch_runner.py contains:
from logic.parsers import abstract
from sys import argv
url = argv[1]
a = abstract(url)
logic/__init__.py is empty. logic/parsers/__init__.py contains:
from abstract_parser import abstract
from time_parser import _timeInfo
If I go to logic and run python abstract_parser.py directly, everything works as expected. However, if I go one level up, and run python batch_runner.py, it is able to import abstract_parser, but it can't find time_parser which is called from abstract_parser, throwing ImportError: No module named 'abstract'
Change this:
from abstract_parser import abstract
To
from logic.parsers.abstract_parser import abstract
Do read about importing from the python documentation on modules.
In this case, one possible solution is to use relative imports inside your package:
That is, in logic/parsers/__init__.py, use:
from .abstract_parser import abstract
from .time_parser import _timeInfo
and in abstract_parser.py:
from .time_parser import _timeInfo
This should let parsers/__init__.py find the abstract_parser module and the time_parser module.
The python import system has a surprising number of traps that you can fall into. This blog post by Nick Coghlan describes many of them, and I personally consider it a must-read if you're planning to develop a package.
I am trying to make a test pass with a mocked function:
#mock.patch('apps.myapp.views.messages')
def test_message_get_called(self, messages):
# tests
assert messages.add_message.called
This tests pass perfectly by default, no problem here.
Because I have a long views.py file I try to refactor. Instead of having a single file, I create a folder named views, put my views.py inside as all.py and add the following __init__.py:
from __future__ import absolute_import
from .all import (
....
)
So I import all my views class into this file to have access to them. This make the application work without problem, so I'm guessing the tests should be fine.
But it turns out the test fails:
AttributeError: <module 'apps.myapp.views' from '.../views/__init__.pyc'>
does not have the attribute 'messages'
So I add messages in my list of import. And I get the following error:
MessageFailure: You cannot add messages without installing
django.contrib.messages.middleware.MessageMiddleware
I already found that using middleware during test may cause problem:
https://code.djangoproject.com/ticket/17971
Why don't my Django unittests know that MessageMiddleware is installed?
But my tests seems to pass without the module, and it fails with.
What can be the issue here ?
I finally made the jump from python2 to python3 (hooray). However, I'm now plagued with import errors that I cannot seem to sanely resolve.
I have the standard Django 1.8 layout like this:
foo_bar
| - foo_bar
| - settings.py
| - urls.py
| - app_one
| - app_two
| - manage.py
My problem comes in when I try to import something from another app. For instance, importing a model from app_one.models.py into app_two.views.py.
I receive server errors depending on what I do.
1. Absolute Import
# in app_two.views.py
from foo_bar.app_one.models import MyModel
This gives the error:
No module named foo_bar.app_one
If I toggle my project back to 2.7, this import of course works A-OK. Not to mention, PyCharm is able to resolve this path and do auto-complete. So.. it's very confusing.
2. Relative imports:
# in app_two.views.py
from ..app_one.models import MyModel
This gives the error:
attempted relative import beyond top-level package
Again, same thing, seems like it should work -- even PyCharm thinks it should work (and can again autocomplete from the path). However, whenever I run my server, it explodes when this view is loaded.
Kind of Resolving:
Now, I can get the imports to work, but in a way that seems to make zero sense. If I leave off the top level package and abandon the relative import notation, it will import without error.
# in app_two.views.py
from app_one.models import MyModel
But this makes even less sense to me than everything else! Why does this work??? This one, of course, breaks when I swap back to 2.x. Further, PyCharm (for what it's worth), shows this as an unresolvable import.
For importing for Foreign Key relationships in a model (in Django 1.8+), you do not need to import explicitly, but can use string quoted version:
# in app1, import Customer from app2
customer_fk = models.ForeignKey('app2.Customer')
Complete Example:
from django.db import models
# this app is 'cart'
class ShoppingCart(models.Model):
# Import Customer Plan from another app - account
plan = models.ForeignKey('account.CustomerPlan')
started = models.DateTimeField()
cart_id = models.BigIntegerField()
I was trying to do a bit of testing on a pieace of code but I get the ImportError: Start directory is not importable. Below is my code. I would really appreciate if someone could help. I am using Python 2.7.5 and also pycharm.
This is the command I execute in virenv
manage.py test /project/tests.py
from django.test import TestCase
# Create your tests here.
from project.models import Projects
from signup.models import SignUp
class ProjectTestCase(TestCase):
def SetUp(self):
super(ProjectTestCase,self).SetUp()
self.john = SignUp.objects.get(email='john#john.com')
self.project = Projects.objects.get(pk=1)
def test_project_permission(self):
self.assertFalse(self.john.has_perm('delete',self.project))
self.assertTrue(self.john.has_perm('view',self.project))
self.assertTrue(self.john.has_perm('change',self.project))
You should verify that you have an __init__.py in your project directory (it can be an empty file)
You're not calling test correctly. Assuming you have an app known as project, the way to call the tests in that app is manage.py test project
[Edit for additional comment which is really getting into separate question territory]
I would suggest adding this to settings.py (at the bottom)
import sys
if 'test' in sys.argv:
DATABASES['default'] = {'ENGINE': 'django.db.backends.sqlite3'}
SOUTH_TESTS_MIGRATE = False
This:
A. Will use sqlite (sort of, I'm not sure if it's actually sqlite or an in-memory db that works like sqlite) ... I've noticed issues if I use postgres and am trying to have my permissions not be excessively liberal AND I've had a test abort)
B. Disables south migrations (so it will just start with a clean database built against whatever models are currently saying)
I'm running through the Django tutorial.
After editing a class it says:
Save these changes and start a new Python interactive shell by running python manage.py shell again:
>>> from polls.models import Poll, Choice
Is it possible to do that without quitting the shell?
No, it's not. Every edit you make to .py files will NOT get reloaded in the shell automatically. If you want to have that type of feature you would have to use
django-extensions which supports what you're after.
Not sure I agree with the other answer.
Python has a built in function reload() which, from the docs:
Reload a previously imported module. The argument must be a module object, so it must have been successfully imported before.
This is useful if you have edited the module source file using an external editor and want to try out the new version without leaving the Python interpreter. The return value is the module object (the same as the module argument).
However you have to do from polls import models and then models.Poll (as it has to be passed the actual module rather than a class) and models.Choice in your code.
That way, without leaving the shell you can run reload(models).
Edit 1:
If you can't be bothered typing models. all the time, you can also enter in your own shortcut;
from polls import models as pm
pm.Poll
pm.Choice
reload(pm)
I have encountered this situation sometimes. And it's already discussed on SO.
It's true, reload() works. But at the same time it's not a very convenient option.
>>> from polls.models import Poll, Choice
.... #Some changes are done to your polls/models.py file and saved
>>> Poll #gives you old model
>>> reload(polls.models) #Reload works at module level!
>>> from polls.models import Poll, Choice # import again from the reloaded module
>>> Poll #gives you new model
What about?
def reload_all():
import sys
module = type(sys) # this type has no name!
for m in sys.modules.values():
if isinstance(m, module):
try:
reload(m)
except:
pass
Not sure if this may have any side effect, though.