Django + WSGI: When is wsgi.py called? - python

I deployed my Django-project via Apache2 on a server.
The problem I have is that I have two setting-modules: settings.py which are my local development settings and settingsprod.py which are my productive settings.
I found the following line in the WSGI.py:
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "proj.settings")
Is this module only called when using WSGI? And if yes is this a good place to use my production settings like so?
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "proj.settingsprod")
For local development I use the development server like so:
python3 manage.py runserver
Does this still defaults to settings.py then?

Yes, your setup works as expected. Though if you use extra tools like celery, you might need to also specify the settingsprod for those setups aswell.
The way I handle such a situation is exactly the other way around: I use settings.py for my production settings and have an additional settings_development.py that I use for all development tasks. This way I don't have to remember setting the production settings in all production relevant files, but instead simply use the development settings for development like so:
python3 manage.py runserver --settings=proj.settings_development
If you often use manage.py commands and want to save some time typing, you can make a copy of your manage.py e.g. as manage_dev.py and change the settings module line like so:
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "proj.settings_development")
and then call your manage functions with:
python3 manage_dev.py runserver

Related

What is the command for starting a WSGI server for Django?

I've developed an application in Django that I usually run in development mode:
python manage.py runserver
I do the same for my deployed instances - obviously a security issue that I now want to resolve.
From the Django docs, its not clear to me how to:
For simplicity sake, I picked wsgi (over asgi): https://docs.djangoproject.com/en/4.0/howto/deployment/wsgi/ . From this page, its not clear to me how my 'runserver' command changes to run the wsgi server over the development server. Should I run the wsgi.py file? That doesn't seem to do anything.
From the page above, its not clear whether wsgi is actually a server, or more a platform/type of servers. Do I need to use uwsgi/uvicorn/etc. instead?
I'm testing on windows - uvicorn is unix only, so I tried uwsgi, but thats giving me this error message: AttributeError: module 'os' has no attribute 'uname' - I guess its Unix only as well
So I'm using the docker image I was already building for deployment - uwsgi is giving me issues again because my docker image has no compiler, so I try now with gunicorn.
that should be easy: gunicorn project.wsgi, which gives me:
ModuleNotFoundError: No module named 'project/wsgi'
my folder structure looks like:
root-folder
project
wsgi.py
settings.py
django_app_1
django_app_2
manage.py
As the manual says, the gunicorn command should work as long as you run the gunicorn command from the same location as manage.py - which is what I'm doing.
I guess I'm missing something very obvious - who knows what?
The wsgi.py file just gives you a WSGI compatible application that a WSGI HTTP server (such as Gunicorn) can run.
I guess you have to run gunicorn project.wsgi from the root folder (that one containing the project module).
Typically, the directory containing manage.py and the module in which wsgi.py resides are one and the same. But not in your case.

Django code changes not reflected without restart

I used python manage.py runserver to start the django server locally. I noticed the change of HTML code is not reflected if I don't re-start the server. Is it normal? Is it possible to see the change without restarting the server?
Update:
I saw the I am in the production env, so the Debug is False. I am wondering how can I change to Development mode?
It is always recommended to create a local settings so you can work in a "development environment", so, you can have a settings.py where you set all the configuration for your production server, always with DEBUG=False, never set DEBUG=True in production.
And also, you can additionally create a local_settings.py where you change only those variables that you need to change for your development environment, like the DEBUG value, so, in your local_settings.py you can have only this:
# local_settings.py
DEBUG=True
And in your settings.py add this at the end:
# settings.py
try:
from local_settings import *
except ImportError:
pass
This will override the variables you set in the local_settings when you run the development server.
Make sure you don't push this file to your server (if you're using git add it to your .gitignore file)

Django: Applying database migration on server start with wsgi

I would like Django to automatically apply migrations when server starts.
How to do it?
I serve django with uwsgi - actually as one of emperor applications.
After publishing new version, I change wsgi.ini file and emperor restarts whole service. But database is not migrated.
But when running tests - locally - by manage.py the migrations are apllied to the database.
Currently the only idea I have is to call subprocess.check_output("manage.py migrate") from settings.py.
The problem here is that calling system command is dependent on system environment. Additionally wsgi is usually running on virtual env.
I could be missing something but is must be possible to run migrations from within the starting code of server.
In the file wsgi.py which is generated next to settings.py add:
from django.core.management import call_command
and after setup call migrate:
application = get_wsgi_application()
call_command("migrate")
related answers:
In django, how do I call the subcommand 'syncdb' from the initialization script?

Running Django with gunicorn: Bad Request (400)

I am following this tutorial to set up a Django application and serve it with Gunicorn on a Debian DigitalOcean server: http://michal.karzynski.pl/blog/2013/06/09/django-nginx-gunicorn-virtualenv-supervisor/
I have got as far as the section starting "Now that you have gunicorn, you can test whether it can serve your Django application by running the following command". Now I'm stuck.
In other words, I can successfully run the application using python manage.py runserver, but not by using gunicorn.
I've successfully accessed my app with:
$ python manage.py runserver xx.xx.xx.xx:8000
Now from the same directory, I'm trying to run:
$ gunicorn my_django.wsgi:application --bind xx.xx.xx.xx:8001
It appears to start OK, but when I go to http://xx.xx.xx.xx:8001, I see:
Bad Request (400)
I'm not sure how to debug this: there's nothing in /var/log/gunicorn/.
I have set ALLOWED_HOSTS=['xx.xx.xx.xx'] in my settings file.
UPDATE: Being an idiot: gunicorn was looking in production settings file, not local settings file. Setting the ALLOWED_HOSTS in production settings fixed it.
I'd still really like to know how to debug problems like this though.
The answer: gunicorn was looking in production settings file, not local settings file. Setting the ALLOWED_HOSTS in production settings fixed it.

Selecting the correct settings file to use in Django

I'm following the approach in Two Scoops of Django: Best Practices for Django 1.6 regarding multiple settings files. I'm using Django 1.7 and virtualenvwrapper.
My setup is as follows:
project/
app1/
app2/
project/
__init__.py
settings/
__init__.py
base.py
local.py
production.py
manage.py
I'm a bit confused as to how Django knows which settings file to use. I do not want to specify the settings file every time I run manage.py. I would rather like to set the DJANG_SETTINGS_MODULE environmental variable as explained in omouse anser here:
What confuses me is in the wsgi.py file there is a line:
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "{{ project_name }}.settings.production")
Is this file only used in the production server? What happens if I already have a DJANGO_SETTINGS_MODULE environmental variable defined on the server?
When running it locally, I understand I need to set the DJANGO_SETTINGS_MODULE env variable every time I open the console. I've read here that I can define a postactivate hook in virtualenvwrapper. This hook will then create the environmental variables that I require everytime I activate the environment.
Is this the recommended way of ensuring the correct DJANGO_SETTINGS_MODULE env variable is loaded on my local machine? Would I also need to setup a similar file on my hosting server? I'm planning on using PythonAnywhere for hosting.
Lastly, if I run a staging server, how would I tell Django to load the staging settings file? The staging server is the practically the same as the production server, so I guess need a different wsgi.py file for the staging server, but that seems like a anti-pattern.
os.environ.setdefault only sets the value if it is not set. When you run in production, export the environment variable DJANGO_SETTINGS_MODULE and set it to your production/staging settings file, and you don't have to set anything when running in development (if you set it by default to your development settings). This is the DRY-est method.
The method with a local_settings.py (which is most of the times kept out of the repo!) is not best practice and should be avoided.

Categories