Django runserver in command with custom settings - python

I try to execute the runserver inside a command with custom settings. But the settings are not loaded:
from django.core.management.base import BaseCommand
from django.core.management import call_command
from django.core.management import setup_environ, ManagementUtility
import settings_api
setup_environ(settings_api)
class Command(BaseCommand):
help = "Local API to retrieve realtime quotes"
def handle(self, *args, **options):
if not settings_api.DEBUG:
call_command('runserver', '127.0.0.1:8002')
else:
call_command('runserver', '0.0.0.0:8002')
Output is:
Used API settings
Used API settings
Validating models...
0 errors found
Django version 1.4b1, using settings 'site.settings'
Development server is running at http://0.0.0.0:8002/
Quit the server with CONTROL-C.

runserver forces default settings unless passed --settings=. Use a separate WSGI container (or even the built-in one, brought up yourself) if you want custom settings.

Ignacios answer pointed me the right direction: executing the command with custom settings param solved it:
./manage.py command --settings=settings_api
More details here

Related

Accessing django database from python script

I'm trying to access my Django database from within a regular Python script. So far what I did is:
import os
import django
from django.db import models
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "m_site.settings")
django.setup()
from django.apps import apps
ap=apps.get_model('py','Post')
q=ap.objects.all()
for a in q:
print(a.title)
There is an application in Django called py where I have many posts (models.py, which contains class Post(models.Model)).
I would like to have the possibility to access and update this database from a regular Python script. So far script above works fine, I can insert, update or query but it looks like it is a separate database and not the database from Django's py application. Am I doing something wrong or missing something? Any help would be very appreciated.
Consider writing your script as a custom management command. This will let you run it via manage.py, with Django all properly wired up for you, e.g.
python manage.py print_post_titles
Something like this should be a good start:
from django.core.management.base import BaseCommand
from py.models import Post
class Command(BaseCommand):
help = 'Prints the titles of all Posts'
def handle(self, *args, **options):
for post in Post.objects.all():
print(a.title)

Django DB connections validation at runserver

In our project we are not going by the Django ORM so i cant use Django db validations. I have a requirement of validating DB connection before starting the server. Can anybody help me with the best practice to achieve the same ??
What I have in my mind is introducing few lines of code or module in manage.py that would validate the DB connectivity before going to execute_from_command_line(sys.argv) . Is my approach correct or is there a better way to achieve the same.
You can write your own manage command which will check db connection and if it's ok call runserver command:
from django.core.management.base import BaseCommand
from django.core.management import call_command
from django.db import connection
class Command(BaseCommand):
def handle(self, *args, **options):
cursor = connection.cursor()
cursor.execute("select 1")
call_command('runserver')
If you want to replace the runserver command and inject your test before running it:
project/settings.py
INSTALLED_APPS = [
...
'project.app',
'django.contrib.staticfiles'
]
The order is important because it dictates which app will overload the other's management commands.
project/app/management/commands/runserver.py
from django.core.management.commands.runserver import Command as BaseCommand
class Command(BaseCommand):
def __init__(self, *args, **kwargs):
try:
#test your connections
except SomeException as e:
#handle your error
super(BaseCommand, self).__init__(*args, **kwargs)
This way your runserver command always checks your constraint before each run. You can also reraise the error in the except clause if you want the command not to run. This resulted in the init code being run twice, I'm not sure why.
If you are using django-devserver then the import becomes:
from django_devserver.devserver.management.commands.runserver import Command as BaseCommand

Django app initialization process

There is a set of functions that I need to carry out during the start of my server. Regardless of path whether that be "/", "/blog/, "/blog/post". For developments purposes I'd love for this script to run every time I run python manage.py runserver and for production purposes I would love this script to run during deployment. Anyone know how this can be done?
My script is scraping data off and making a call to Facebook's Graph API with python and some of its libraries.
I would suggest you to use custom management commands:
Create command for initialization:
e.g. app/management/commands/initialize_some_stuff.py
from django.core.management.base import BaseCommand
class Command(BaseCommand):
help = 'Description of your command.'
def handle(self, *args, **options):
# Add your initialization here.
print 'What should I initialize?'
Create command for running server during development:
e.g. app/management/commands/rundevserver.py
import os
from django.core.management import call_command
from django.core.management.base import BaseCommand
class Command(BaseCommand):
help = 'Description of your command.'
def handle(self, *args, **options):
if not os.environ.get('RUN_MAIN'):
call_command('initialize_some_stuff', *args, **options)
call_command('runserver', *args, **options)
Call ./manage.py rundevserver instead of ./manage.py runserver during development.
Add ./manage.py initialize_some_stuff to your deployment script.
As an alternative to 3rd clause you can also override default runserver command and conditionally call ./manage.py initialize_some_stuff from it:
Add additional imports:
import os
from django.conf import settings
Override handle method:
def handle(self, *args, **options):
if os.environ.get('RUN_MAIN') and settings.DEBUG:
call_command('initialize_some_stuff', *args, **options)
super(Command, self).handle(*args, **options)
Sounds like the quickest (if not most elegant) solution would be to call 'python manage.py runserver' at the end of your script.

Run python script from django

I added some python file in my django project but that python file did not execute. How can i run that python scrip in django.
OK it seems you want to run a script outside of the HTTP request/response cycle,
I'd recommend you make a Django admin command, because a script will need to e.g. have access to the database environment to update records
from django.core.management.base import BaseCommand
from yourapp.models import Thing
import your_script
class Command(BaseCommand):
help = 'Closes the specified poll for voting'
def handle(self, *args, **options):
# Do your processing here
your_script.process(Thing.objects.all())
With this you can call ./manage.py process_thing and it'll run independently
More on Django admin commands here, https://docs.djangoproject.com/en/1.8/howto/custom-management-commands/
If the processing is triggered programmatically e.g. from user requests,
you'll have to setup a queue and have a task job created for each request, I'd try Celery, more on that here http://celery.readthedocs.org/en/latest/django/first-steps-with-django.html

Where to put Django startup code?

I'd like to have these lines of code executed on server startup (both development and production):
from django.core import management
management.call_command('syncdb', interactive=False)
Putting it in settings.py doesn't work, as it requires the settings to be loaded already.
Putting them in a view and accessing that view externally doesn't work either, as there are some middlewares that use the database and those will fail and not let me access the view.
Putting them in a middleware would work, but that would get called each time my app is accessed. An possible solution might be to create a middleware that does all the job and then removes itself from MIDDLEWARE_CLASSES so it's not called anymore. Can I do that without too much monkey-patching?
Write middleware that does this in __init__ and afterwards raise django.core.exceptions.MiddlewareNotUsed from the __init__, django will remove it for all requests :). __init__ is called at startup by the way, not at the first request, so it won't block your first user.
There is talk about adding a startup signal, but that won't be available soon (a major problem for example is when this signal should be sent)
Related Ticket: https://code.djangoproject.com/ticket/13024
Update: Django 1.7 includes support for this. (Documentation, as linked by the ticket)
In Django 1.7+ if you want to run a startup code and,
1. Avoid running it in migrate, makemigrations, shell sessions, ...
2. Avoid running it twice or more
A solution would be:
file: myapp/apps.py
from django.apps import AppConfig
def startup():
# startup code goes here
class MyAppConfig(AppConfig):
name = 'myapp'
verbose_name = "My Application"
def ready(self):
import os
if os.environ.get('RUN_MAIN'):
startup()
file: myapp/__init__.py
default_app_config = 'myapp.apps.MyAppConfig'
This post is using suggestions from #Pykler and #bdoering
If you were using Apache/mod_wsgi for both, use the WSGI script file described in:
http://blog.dscpl.com.au/2010/03/improved-wsgi-script-for-use-with.html
Add what you need after language translations are activated.
Thus:
import sys
sys.path.insert(0, '/usr/local/django/mysite')
import settings
import django.core.management
django.core.management.setup_environ(settings)
utility = django.core.management.ManagementUtility()
command = utility.fetch_command('runserver')
command.validate()
import django.conf
import django.utils
django.utils.translation.activate(django.conf.settings.LANGUAGE_CODE)
# Your line here.
django.core.management.call_command('syncdb', interactive=False)
import django.core.handlers.wsgi
application = django.core.handlers.wsgi.WSGIHandler()
You can create a custom command and write your code in the handle function. details here https://docs.djangoproject.com/en/dev/howto/custom-management-commands/
Then you can create a startup script that runs the django server then executes your new custom command.
If you are using mod_wsgi you can put it in the wsgi start app
Here is how I work around the missing startup signal for Django:
https://github.com/lsaffre/djangosite/blob/master/djangosite/models.py
The code that is being called there is specific to my djangosite project, but the trick to get it called by writing a special app (based on an idea by Ross McFarland) should work for other environments.
Luc

Categories

Resources