Django app: can I run management command that is defined in a dependency? - django

My Django application called my_app pulls in a dependency called my_dependency.
my_dependency declares a management command called useful_thing
Is there a way I can run useful_thing directly from my_app's start.sh?
I've tried calling it directly but it's not found, but maybe there's a way I can configure it to look for management commands from a particular place? I'm new to Django and suspect this is not a sensible thing to try and do.

You can call any (properly defined) management command using Django's manage.py, just like any other Django command:
python manage.py userful_thing

Related

How to use django 3.0 ORM in a Jupyter Notebook without triggering the async context check?

Django 3.0 is adding asgi / async support and with it a guard around making synchronous requests in an async context. Concurrently, IPython just added top level async/await support, which seems to be running the whole interpreter session inside of a default event loop.
Unfortunately the combination of these two great addition means that any django ORM operation in a jupyter notebook causes a SynchronousOnlyOperation exception:
SynchronousOnlyOperation: You cannot call this from an async context - use a thread or sync_to_async.
As the exception message says, it's possible to wrap each ORM call in a sync_to_async() like:
images = await sync_to_async(Image.objects.all)()
but it's not very convenient, especially for related fields which would usually be implicitly resolved on attribute lookup.
(I tried %autoawait off magic but it didn't work, from a quick glance at the docs I'm assuming it's because ipykernels always run in an asyncio loop)
So is there a way to either disable the sync in async context check in django or run an ipykernel in a synchronous context?
For context: I wrote a data science package that uses django as a backend server but also exposes a jupyter based interface on top of the ORM that allows you to clean/annotate data, track machine learning experiments and run training jobs all in a jupyter notebook.
It works for me
os.environ["DJANGO_ALLOW_ASYNC_UNSAFE"] = "true"
BTW, I start my notebook using the command
./manage.py shell_plus --notebook
Contrary to other answers I'd suggest just running from the shell as:
env DJANGO_ALLOW_ASYNC_UNSAFE=true ./manage.py shell_plus --notebook
and not modifying any config files or startup scripts.
The advantage of doing it like this is that these checks still seem useful to have enabled almost everywhere else (e.g. when debugging locally via runserver or when running tests). Disabling via files would easily disable these in too many places negating their advantage.
Note that most shells provide easy ways of recalling previously invoked command lines, e.g. in Bash or Zsh Ctrl+R followed by notebook would find the last time you ran something that had "notebook" in. Under the fish shell just type notebook and press the up arrow key to start a reverse search.
For now I plan on just using a forked version of django with a new setting to skip the async_unsafe check. Once the ORM gets async support I'll probably have to rewrite my project to support it and drop the flag.
EDIT: there's now a PR to add an env variable (DJANGO_ALLOW_ASYNC_UNSAFE) to disable the check (https://github.com/django/django/pull/12172)
I added
os.environ["DJANGO_ALLOW_ASYNC_UNSAFE"] = "true" code in the setting.py of your project all the way down to the file and then
command python3 manage.py shell_plus --notebook
if you are using python3 or use python
That's it. worked for me.

Where to up django app startup code that must interact with the database?

I have some django code that needs to run once when my app is loaded in the dev server or as a wsgi worker. This code also needs to write to the database. In my particular case I do not need the code to run for many management commands like collectstatic or createsuperuser, etc.
This SO question "Where to put Django startups code?" recommends using AppConfig.ready for startup code.
However, the docs for the ready function clearly warn against interacting with the database:
Although you can access model classes as described above, avoid interacting with the database in your ready() implementation. This includes model methods that execute queries (save(), delete(), manager methods etc.), and also raw SQL queries via django.db.connection. Your ready() method will run during startup of every management command. For example, even though the test database configuration is separate from the production settings, manage.py test would still execute some queries against your production database!
Is there some later startup hook I should use for code that does need to update the database?
The code registers my server as a webhook endpoint with a 3rd party service and stores required connection information in the database. I only register for the webhook if not already configured.
We have a similar use case:
If the server is restarted, it needs to manage database information in order to not leave some procedures in stall state.
The way we solve this is with a systemd script, only executed once during startup, which calls a script, which performs operations in django's database.
1) Create a python script that will do the required operations and changes to the database:
/djangoproject/boot_script.py
Which contains:
from yourdjangoapp.models import XModel
# DO STUFF WITH XModel
2) Create a script wich calls to a python script for django:
/.../execute_boot_script.sh
Which contains:
cd /djangoproject
python manage.py shell < boot_script.py
And has execution rights:
sudo chmod +x /.../execute_boot_script.sh
3) Create a file for the service:
/etc/systemd/system/execute_boot_script.service
which contains:
[Unit]
After=apache2.service
[Service]
Environment=ENVPATH=:/usr/local/... # ONLY IF YOU NEED TO SET SOME ENVIRONMENT VARIABLE
Type=oneshot
ExecStart=/.../execute_boot_script.sh
[Install]
WantedBy=multi-user.target
More info:
https://linuxconfig.org/how-to-automatically-execute-shell-script-at-startup-boot-on-systemd-linux
This answer works in linux, but could be also easily achieved in windows with a programmed task launched at startup, though.

Django command without Django application?

Is there any way I can add a custom Django command which doesn't need an underlying application or project to work (pretty much like startapp or startproject)?
$ django-admin.py startveryniceproject projectname
One way I can imagine this could be accomplished would be to copy a startveryniceproject.py into django.core.management.commands, but does that really sound "clean"?

How does django register management commands

I'm having a weird issue with something in a deployed django app (long story).
Something that might help me is to know:
How django goes about detecting and maintaining a list of active management commands?
Some things you should consider if you have troubles executing a management command:
The app containing the command has to be in settings.INSTALLED_APPS.
To be recognized as an app the package has to contain a models.py (although it can be empty).
All packages need to have an __init__.py file (your app's directory as well as the management and command folder).
Sometimes Django seems to be choking on something like an ImportError that doesn't get displayed properly - so it might help to open a manage.py shell and try something like import MyCommand from myapp.management.commands.mycommand.
It looks for any module under management.commands inside installed applications. See https://docs.djangoproject.com/en/dev/howto/custom-management-commands/ for more details.
The code looks for Python modules in management/commands direction in each installed app using pkgutil.iter_modules.

Is there a way to add custom django-admin.py commands that work outside of projects?

I'm trying to write a custom command that works outside of Django projects. I was thinking I could follow the coding patterns of Django's own such commands (e.g., startproject), include my command in an app and install it.
Alas, it seems django cannot see this command, as perhaps it doesn't scan site-packages for custom commands.
Is there a way to make this work or am I sadly correct?
UPDATE: I should note that the goal I was trying to accomplish (writing a command that starts projects based on custom templates) is supported in the coming 1.4 release of Django: https://docs.djangoproject.com/en/dev/ref/django-admin/#django-admin-startproject (see the --template option).
Based on this code from django.core.management, it does appear that django only searches for project-less commands in its own packages, and will then only find command by scanning INSTALLED_APPS, which means a project is required.
You can use a custom manage.py.
You do need a project. A project is, although, nothing more than a python package with a settings.py (and maybe a urls.py file)
So you could just create a project, with whatever commands you want, and in your setup script include a binary script that is nothing more than a manage.py in disguise.
I use it to have a manage.py in the bin path of a virtualenv, but you can call it something else and have that "django" project installed in your system python.
I don't quite understand from your post, for what purpose do You want to write such command using Django's manage.py. But suppose you want (as I was) to run some script, that works with Django models, for example. You cannot run such script without setting Django environment.
I do the following:
put my code in script.py
manage.py shell
execfile('script.py')
Maybe, this helps.