Django DB connections validation at runserver - python

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

Related

Is it possible to get django info without running it

I have a django model, the whole code is completed. but I want to access my model info. a code like this to get field names.
for f in myModel._meta.fields:
print(f.get_attname())
is it possible to do it from an external python script without running django server?
other possible automated ways of doing this and saving results to a file are also appreciated.
try1
because Im using docker I ran it up. and from django container I started python shell
>>> from django.conf import settings
>>> settings.configure()
>>> import models
it gave django.core.exceptions.AppRegistryNotReady: Apps aren't loaded yet.
try2
by #Klaus D advice in comments I tried management command. so I created
users/
__init__.py
models.py
management/
__init__.py
commands/
__init__.py
_private.py
modelInfo.py
structure. in modelInfo.py I did
from django.core.management.base import BaseCommand, CommandError
from users import views2
def savelisttxtfile(the_list, path_, type_='w', encoding="utf-8"):
with open(path_, type_, encoding=encoding) as file_handler:
for item in the_list:
file_handler.write("{}\n".format(item))
class Command(BaseCommand):
def handle(self, *args, **options):
dic=[]
for f in views2.ChertModel._meta.fields:
print(f.get_attname())
dic.append(f.get_attname())
savelisttxtfile(dic,"F:\projects\sd.txt")
and from another python file I tried
os.chdir(r'F:\projects\users\management\commands')
from subprocess import run
import sys
run([sys.executable, r'F:\projects\users\management\commands\modelInfo.py'])
and it returned
CompletedProcess(args=['C:\\ProgramData\\Anaconda3\\python.exe', 'F:\projects\users\management\commands\modelInfo.py'], returncode=1)
and the results were not save in sd.txt
thanks to #klaus D and management command documentation I made this structure
users/
__init__.py
models.py
management/
__init__.py
commands/
__init__.py
_private.py
modelInfo.py
and in modelInfo.py I did
from django.core.management.base import BaseCommand, CommandError
from users import views2
def savelisttxtfile(the_list, path_, type_='w', encoding="utf-8"):
with open(path_, type_, encoding=encoding) as file_handler:
for item in the_list:
file_handler.write("{}\n".format(item))
class Command(BaseCommand):
def handle(self, *args, **options):
dic=[]
for f in views2.ChertModel._meta.fields:
print(f.get_attname())
dic.append(f.get_attname())
savelisttxtfile(dic,"F:\projects\sd.txt")
and to run it I went to manage.py location and executed python manage.py modelInfo to launch it.
Regarding your "try1" it seems to be a little bit trickier to start a python shell like python manage.py shell than what you propose there.
Fortunately you can do this:
python manage.py shell < your_script.py
and your script will be executed as if typed directly into the "django shell". Keep in mind that you still need to import your models relative to your project, i.e. from myapp.models import mymodel.

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 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

Django runserver in command with custom settings

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

Categories

Resources