My Django runserver shortcut script
This is a little shell script I save as rs
, put on my path, and use as a shortcut to start the Django development server. It has several features that make me more productive:
- It’s shorter to type than
python manage.py runserver
. - It recognizes what project I’m in and runs many of them on different ports.
- It opens the web site’s front page in my browser.
Running my most important projects on separate ports has a couple of advantages:
- I can run several simultaneously.
- My browser can differentiate the projects. When everything runs at localhost:8000, my browser might cache a file like style.css and have no way of knowing when I switch projects and style.css is completely different. If one project is at localhost:8001 and the other is at localhost:8002, the cache keeps them separate.
- It opens the current site in my browser (after giving the server a few seconds to start) because that’s typically what I do next anyway, and it saves me having to keep track of which project uses which port.
- If I already have the site open in my browser, I just pass “.” as the first command line argument and it skips opening another browser tab. Any other runserver arguments can follow that, except for address:port which this script doesn’t recognize.
How it works
The script identifies the project that I’m working on by looking at which virtual environment is active. When a virtual environment has been activated, the environment variable VIRTUAL_ENV
is set to the full path of the virtual environment directory. The script looks at the last component of that, which is the name of the virtual environment.
It could just as well have looked at the last component of the working directory, since it currently assumes it’s being run from the top directory where manage.py
is anyway, but I wanted to leave open the possibility of improving that part and not have to change how it detects the project later.
To open the site’s main page in a browser after giving Django a few seconds to start, the script starts a background subshell using the (commands)&
shell construct. In that subshell, it waits a few seconds using sleep before invoking a command to open a page in the browser.
Next steps
I’m presenting this as a starting point for your own ideas, not as a finished solution. There's definitely room for improvement in the script, and in any case it’ll require some customization to work in your environment.
To customize it:
- Edit the case statement to replace “Project1” and “Project2” with some of your own projects, and add more lines and port numbers as needed.
- If 4 seconds isn’t long enough for your Django projects to start, change
sleep 4
to a longer period. - If you don’t run it in a directory where
manage.py
is, you’ll have to edit the line that starts your server.
Here are some things that could be improved in the script:
- The script will pass most command line options along to runserver, but doesn’t recognize an address:port argument.
- If the server takes more than 4 seconds to start, the web page fails to load (but it’s easy enough to reload it).
- The projects are hard-coded.
- It assumes you have
manage.py
in the current directory.
Here’s the current script. I’ll also host it at https://github.com/dpoirier/runserver. Pull requests are welcome.
#!/bin/sh
# Start the Django project in the current directory using runserver,
# with a unique port if the project name is known, and then open
# the front page in a browser.
if [ "$1" = "." ] ; then
# "." means don't open the page in a browser
OPEN=false
shift
else
# Try to figure out how to open a page on this system, and set
# OPEN to the command.
case `uname` in
Darwin) OPEN=open;;
Linux) OPEN=xdg-open;;
*) echo "Don't know how to open URLs on "`uname`; exit 1;;
esac
fi
case $VIRTUAL_ENV in
*/Project1) PORT=8001;;
*/Project2) PORT=8002;;
# ...
*) PORT=8000;;
esac
TARGET=localhost:$PORT
# Open page in browser after giving Django a few seconds to start
if [ "$OPEN" != "false" ] ; then
(sleep 4;$OPEN http://$TARGET)&
fi
exec python manage.py runserver "$@" "$TARGET"