I want to have different settings.py for when I run my project locally and in production, because I have a setting in settings.py that forces my project to use https, but django runserver.py can only use http, not https, so I am unable to run my project locally now. Also, I want to have debug=True on my computer, and debug=False in production. So how can I have a different settings.py for my computer and for production?
There are some options, one these to create two settings files:
add the following to the end of your settings.py:
import os
# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
PROJECT_APP_PATH = os.path.dirname(os.path.abspath(__file__))
PROJECT_APP = os.path.basename(PROJECT_APP_PATH)
BASE_DIR = os.path.dirname(PROJECT_APP_PATH)
DEBUG = False
...
...
##################
# LOCAL SETTINGS #
##################
# Allow any settings to be defined in local_settings.py which should be
# ignored in your version control system allowing for settings to be
# defined per machine.
f = os.path.join(PROJECT_APP_PATH, "local_settings.py")
if os.path.exists(f):
import sys
import imp
module_name = "%s.local_settings" % PROJECT_APP
module = imp.new_module(module_name)
module.__file__ = f
sys.modules[module_name] = module
exec(open(f, "rb").read())
Create local_settings.py and overwrite the desired settings:
#####################
# OVERWRITE SETTINGS #
#####################
DEBUG = True
SECURE_PROXY_SSL_HEADER = None
SECURE_SSL_REDIRECT = False
...
You could have a folder called settings that include different python files for the base settings, the dev settings, the staging settings, the production settings and the test settings.
The base settings could be imported in dev, staging, production and test settings and then, you can set the value of existing variables (e.g. DEBUG) or define new variables.
The tree structure could be:
{your-project-name}/
settings/
base.py
dev.py
staging.py
production.py
test.py
Then you can use them such as:
$ python manage.py runserver --settings={your-project-name}.settings.dev
For the deployment, you could pass the proper settings through env variable (e.g. in case of docker images)
I have a Django project containing some files which are, obviously, not automatically discovered by Django. My workaround is to import them in urls.py so that Django can see them. This is how my urls.py looks like:
from django.contrib import admin
from django.urls import path
from custom_file_1 import * # "unused" import
from custom_file_2 import * # "unused" import
urlpatterns = [
...
]
My IDE considers the commented imports unused, since they are not used, but they are vital so that Django can process those files.
And the question: is there any nice way to let Django see those files? And how to do that?
It is usually not a good idea to import things with wildcards. Imagine that in one of the custom files some object with the name path is present, then it will override the reference to the path function you imported from django.urls.
Usually one imports such files (that for example contain signals, etc.) in the AppConfig.
In the directory of the app, there is an __init__.py file. You can write
# app/__init__.py
default_app_config = 'app.config.CustomAppConfig'
In your app directory, you then define the config of your app:
# app/config.py
from django.apps import AppConfig
class CustomAppConfig(AppConfig):
name = 'app'
def ready(self):
import custom_file_1 # noqa
import custom_file_2 # noqa
Here # noqa is used to ignore the flake8 warnings.
If i want to use some model in extra file in my Django project, i can't do it by this simple way:
from myproject_app.models import *
because i get this error:
django.core.exceptions.ImproperlyConfigured: Requested setting DEFAULT_INDEX_TABLESPACE, but settings are not configured. You must either define the environment variable DJANGO_SETTINGS_MODULE or call settings.configure() before accessing settings.
To solve this problem, I found this solution:
import os
import django
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "myproject.settings")
django.setup()
from myproject_app.models import *
Ok. It works. But if i want to use any fuction from this extra file in models.py project does not start at all!
Please help me.
i think you forgot to register your app in,
INSTALLED_APPS = (
myproject_app,
)
Add all application you created to INSTALLED_APPS, and as PEP8 perspective never import all models by '*', instead import individually by its name which you are using
It seems to be relatively normal in the Django world to import a local environment settings override file at the end of settings.py, something like:
from settings_local.py import *
This has a couple of issues, most notably for me being that you cannot inspect or modify base settings, only override them - which leads to some painful duplication and headaches over time.
Instead, is there anything wrong with importing an init function from a local file and injecting the output of globals() to allow that local file to read and modify the settings a bit more intelligently?
settings.py:
from settings_local.py import init
init( globals() )
settings_local.py:
def init( config ):
config['INSTALLED_APPS'].append( 'some.app' )
This seems to address a number of the concerns related to using import *, but I'd like to know if this is a bad idea for a reason I am not yet aware of.
The more common and readable way to handle this is to have multiple settings files, where you put all the common settings in one module and import that at the beginning of the environment-specific settings files:
settings
__init__.py
base.py
development.py
staging.py
production.py
This allows you the mutations you are referring to:
# base.py
INSTALLED_APPS = [
'foo',
'bar'
]
# development.py
from .base import *
INSTALLED_APPS += [
'debug_toolbar'
]
Then you run your app locally with DJANGO_SETTINGS_MODULE=settings.development
I'm writing a script to import some model objects into the database my django application uses. In the past I've solved this by running ./manage.py shell and then import myscript. I'm sure there's a better way. I'd like to be able to call a script from anywhere on my HD using python scriptname.py, and in the first few lines of that script it would do whatever imports / other operations necessary so that it can access model objects and behave as though it was run using manage.py shell.
What do I need to add to my script to achieve this?
EDIT:
Based on #Melug's answer, with addition of dynamically setting Python path to address the 'anywhere on my HD' part of the question:
import sys
sys.path.append('c:\\my_projec_src_folder')
from myproject import settings
from django.core.management import setup_environ
setup_environ(settings)
Since Django 1.4 you should avoid using setup_environ(settings) (post by Melug) because it is deprecated. Use the following instead and you will be able to access your model
import os
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "your_project_name.settings")
# your imports, e.g. Django models
from your_project_name.models import Location
# From now onwards start your script..
Here is an example to access and modify your model:
if __name__ == '__main__':
# e.g. add a new location
l = Location()
l.name = 'Berlin'
l.save()
# this is an example to access your model
locations = Location.objects.all()
print locations
# e.g. delete the location
berlin = Location.objects.filter(name='Berlin')
print berlin
berlin.delete()
Example model:
class Location(models.Model):
name = models.CharField(max_length=100)
To get models loaded too, I had to combine this with this answer, otherwise I get django.core.exceptions.AppRegistryNotReady: Models aren't loaded yet
import os
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "my_project.settings")
import django
django.setup()
As an extra, I add this to the __init__.py of my django projects, it will automatically discover the app name so it is copy/paste-able:
import os
def setup():
module = os.path.split(os.path.dirname(__file__))[-1]
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "{}.settings".format(module))
import django
django.setup()
Then I can just do:
from <app> import setup
setup()
For Django version 1.9 or later you can use this:
import sys
import os
import django
sys.path.append('your_project_directory')
os.environ['DJANGO_SETTINGS_MODULE'] = 'your_project.settings'
django.setup()
from yourapp.models import your_model
so you can use object as same django object:
from myapp.models import Locations
all_locations = Locations.object.all()
first_location = Locations.object.get(id=1)
print first_location.name()
first_location.save()
I think the best way is to create your custom management command(s). Then you can call manage.py <yourcommand> from anywhere.
You need to setup django environment first:
from your_project import settings
from django.core.management import setup_environ
setup_environ(settings)
At last import your models, everything goes just like django.
FOR DJANGO 1.11
Upper solutions did not work, but gave me an error:
django.core.exceptions.AppRegistryNotReady: Apps aren't loaded yet.
For me solution from here worked out:
import os
from django.core.wsgi import get_wsgi_application
os.environ['DJANGO_SETTINGS_MODULE'] = 'myapp.settings'
application = get_wsgi_application()
Since at least Django 1.11, your main app includes a wsgi module that does the neccessary setup on import. Assuming myproject/myproject is where your settings.py is, in your script just import:
from myproject.wsgi import application
Here is the answer for Django versions > 1.4:
from django.core.management import settings
from myproject.myproject import settings as project_settings
if not settings.configured:
settings.configure(default_settings=project_settings)
If you get:
django.core.exceptions.AppRegistryNotReady: Models aren't loaded yet.
Try:
import os
from django.core.wsgi import get_wsgi_application
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'myapp.settings')
application = get_wsgi_application()
for django >= 2.0 it is enough to do these 2 imports
from your_project_path import settings as your_project_settings
from django.core.management import settings
then you can do just from my_app.models import MyModel
and work with your Model MyModel
Try:
os.environ["DJANGO_SETTINGS_MODULE"] = "mysite.settings"
if os.environ.setdefault doesn't work. (Windows 10, python3.6.4, django 2.0.3)
As Stavros pointed out here, you can just copy the wsgi.py and put it at the beginning of you script. Besides setting up DJANGO_SETTINGS_MODULE, you also need to get the applications. Hope it helps. It works for me at django 2.1.5.
import os
from django.core.wsgi import get_wsgi_application
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'revochem.settings')
application = get_wsgi_application()
Many of the above answers are correct, but don't reference the official documentation.
First you need to configure settings or set the DJANGO_SETTINGS_MODULE envrionment variable
from django.conf import settings
if not settings.configured:
settings.configure(myapp_defaults, DEBUG=True)
The docs then specify:
After you’ve either set DJANGO_SETTINGS_MODULE or called
configure() you’ll need to call django.setup() to load your
settings and populate Django’s application registry. For example:
import django from django.conf
import settings from myapp
import myapp_defaults
settings.configure(default_settings=myapp_defaults, DEBUG=True)
django.setup()
# Now this script or any imported module can use any part of Django it needs. from myapp import models ```
The docs also include an important caveat:
django.setup() may only be called once.
Therefore, avoid putting reusable application logic in standalone
scripts so that you have to import from the script elsewhere in your
application. If you can’t avoid that, put the call to django.setup()
inside an if block:
if __name__ == '__main__':
import django
django.setup()