Brainstorm's snippets (20/228)

  Monit guide (updated)
  Flat list out of list of lists in Python
  Raspberry PI setup guide
setup, raspberrypi
  Run ssh-agent and ssh-add on login via SSH
  Management command to dump local db and media
django, management_command
  Send email from command line
  Capture Video from Camera
  Downgrade pg_dump 10 script to 9.x
  Git: apply patches
  Sentry Notes
  Deleting GIT branches
git, branch
  Django Custom Error Views setup
django, errors, views
  Many-to-many example using "through" to augment M2M relationships
django, models, M2M
  New Django project check-list
  Json prettified fields in Django admin
admin, json
  Sinewave redis PUBSUB example
redis, pubsub
  Removing the output of Django runserver
  Virtualbox - Fix Freezing with Linux Guests on Windows 10 Hosts
  Logging in to Django REST and POSTing forms using HTTPie
  Control Spotlight indexing activities

  Monit guide (updated)

Install Monit System Monitor On Ubuntu 18.04

sudo apt update
sudo apt install monit

After installing Monit, the commands below can be used to stop, start and enable Monit service:

sudo systemctl stop monit.service
sudo systemctl start monit.service
sudo systemctl enable monit.service

Configure Monit service

By default all files located on /etc/monit/conf.d/ and /etc/monit/conf-enabled/ are read by monit when the service is started.

Use the /etc/monit/conf.d/ directory to put all your monitoring configuration files in it.

Example: file /etc/monit/conf.d/disk:

check device root with path /
    if SPACE usage > 80% then alert

check device backup_disk with path /mnt/backup
    if SPACE usage > 80% then alert


sudo monit check -t
sudo monit reload
sudo monit start all

Check Monit status

sudo monit status

Access Monit Web Portal

Add this to file /etc/monit/monitrc:

set httpd port 2812
    allow admin:password

then access the web page from anywhere with:




  Flat list out of list of lists in Python

Given superlist as a list of lists,

flat_list = [item for sublist in superlist for item in sublist]

which means:

flat_list = []
for sublist in superlist:
    for item in sublist:


  Raspberry PI setup guide

1   Initial setup

2   Enable SSH connections

Connect with a keyboard, then issue these commands from terminal:

systemctl enable ssh.service
systemctl start ssh.service

3   Set locale

sudo -s
export LANGUAGE=en_US.UTF-8
export LANG=en_US.UTF-8
export LC_ALL=en_US.UTF-8
locale-gen en_US.UTF-8
dpkg-reconfigure locales

5   Expand swap partition ...

100 Mb (the default) is too small, and if you are doing memory intensive stuff (e.g., web surfing), you can easily max it out.

The recommended swap size is 2*physical RAM - in the case of the Pi (modern/current versions of), this is 2G.

You can increase the swap size by changing the CONF_SWAPSIZE or the CONF_SWAPFACTOR parameter in /etc/dphys-swapfile followed by a reboot:

cat /etc/dphys-swapfile


Test after reboot:

# free -h
              total        used        free      shared  buff/cache   available
Mem:           927M        259M        425M         30M        242M        585M
Swap:          1.8G          0B        1.8G

6   ... or remove it !

On the other hand, you might want to turn off swap entirely in order to reduce the amount of write operations on the SD card – because SD cards have their life limited to the amount of write operations:

sudo systemctl disable dphys-swapfile

Test after reboot:

# free -h
              total        used        free      shared  buff/cache   available
Mem:           927M        257M        437M         24M        232M        593M
Swap:            0B          0B          0B

Another option is to move swap to an external device (for example a USB key).


7   Setup SMTP

TODO; vedere:

Installazione e Configurazione di Postfix su Raspberry usando come Smarthost GMAIL:


8   Start chromium in Kiosk mode on raspbian jessie

file ~/Desktop/runChromium.desktop:

[Desktop Entry]
Exec=/usr/bin/chromium-browser --noerrdialogs --disable-session-crashed-bubble --disable-infobars --kiosk
Comment=Start Chromium in kiosk mode; copy int ~/.config/autostart to have it run automatically


10   Display rotation

file "/boot/config.txt":

# LCD Rotation

# Display Rotate (HDMI)

11   Disable screen sleep

file "/etc/lightdm/lightdm.conf":

# don't sleep the screen
xserver-command=X -s 0 dpms


sudo apt-get install xscreensaver

then configure the screensaver application under the Preferences option on the main desktop menu.

12   How to up a Static IP on Your Ethernet or Wireless Network Connection

file /etc/dhcpcd.conf:

# setup ethernet static ip
interface eth0
static routers=

# setup wireless static ip
interface wlan0
static routers=


# setup ethernet static ip
interface eth0
static ip_address=
static routers=
static domain_name_servers=


#sudo /etc/init.d/networking restart
sudo reboot

  Run ssh-agent and ssh-add on login via SSH

You can try adding this:

eval $(ssh-agent -s)
ssh-add ~/.ssh/id_rsa

This way the ssh-agent does not start a new shell, it just launches itself in the background and spits out the shell commands to set the appropriate environment variables.

As said in the comment, maybe you do not want to run the agent at all on the remote host, but rather on the box you are working from, and use:

ssh -A remote-host

to forward the services of your local ssh agent to the remote-host.

For security reasons you should only use agent forwarding with hosts run by trustworthy people, but it is better than running a complete agent remotely any time.

  Management command to dump local db and media

file management/commands/


usage: dump_local_data [-h] [--version] [-v {0,1,2,3}]
                                 [--settings SETTINGS]
                                 [--pythonpath PYTHONPATH] [--traceback]
                                 [--no-color] [--dry-run] [--max-age MAX_AGE]
                                 [--no-gzip] [--legacy]

Dump local db and media for backup purposes (and optionally remove old backup

positional arguments:
  target                choices: db, media, all

optional arguments:
  -h, --help            show this help message and exit
  --version             show program's version number and exit
  -v {0,1,2,3}, --verbosity {0,1,2,3}
                        Verbosity level; 0=minimal output, 1=normal output,
                        2=verbose output, 3=very verbose output
  --settings SETTINGS   The Python path to a settings module, e.g.
                        "myproject.settings.main". If this isn't provided, the
                        DJANGO_SETTINGS_MODULE environment variable will be
  --pythonpath PYTHONPATH
                        A directory to add to the Python path, e.g.
  --traceback           Raise on CommandError exceptions
  --no-color            Don't colorize the command output.
  --dry-run, -d         Dry run (simulation)
  --max-age MAX_AGE, -m MAX_AGE
                        If > 0, remove backup files old "MAX_AGE days" or more
  --no-gzip             Do not compress result
  --legacy              use legacy Postgresql command syntax

Code snippet has been moved to:

  Send email from command line

Using mail

    Subject: Hello World!
    This is an email to myself.

    Hope all is well.

and terminate with ^D.


echo "this is a test mail" | mail -s'send mail test'

Using mailx

mailx -s "subject" -r, < textfile

Using mailx with attachment

mailx -A attchment_file -s "subject" -r, < textfile

Test what's happening

tail -f /var/log/mail.log

  Capture Video from Camera

import cv2
import time
import shutil

cap = cv2.VideoCapture(0)
snapshot = "/tmp/snapshot.jpg"
snapshot_tmp = "/tmp/snapshot.tmp.jpg"

print('Press "q" to quit ...')


    # Capture frame-by-frame
    ret, frame =

    # Our operations on the frame come here
    gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)

    # Display the resulting frame
    cv2.imshow('frame', frame)

    # Update snapshot
    cv2.imwrite(snapshot_tmp, frame)
    shutil.move(snapshot_tmp, snapshot)
    print('%s "%s" updated' % (

    if cv2.waitKey(1) & 0xFF == ord('q'):


# When everything done, release the capture


  Downgrade pg_dump 10 script to 9.x

#!/usr/bin/env python3
import sys

#  Downgrades pg_dump 10 script to 9.x
#  removing 'AS integer' from 'CREATE SEQUENCE' statement
#  Usage:
#       $ python3 < test10.sql > test9.sql
#  or:
#       $ cat test10.sql | ./ > test9.sql
#  To obtain a compressed 9.x sql script from a compressed 10 sql script:
#       $ gunzip -c test10.sql.gz | ./ | gzip > test9.sql.gz

inside_create_sequence = False
for row in sys.stdin.readlines():

    if inside_create_sequence and row.strip().lower() == 'as integer':
        print(row, end='', flush=True)

    inside_create_sequence = row.strip().startswith('CREATE SEQUENCE ')

  Git: apply patches


Retrieve changes from a remote "working clone" of a project to your local development machine

On remote "working clone" ...

where you've done some changes to be recovered, procede as follows:

  1. Move changes to be recovered to a work branch, and commit them:
git stash
git checkout -b dirty
git stash apply

git add .
git commit -m "my new nice changes"
  1. Check the id of the new commit:
$ git log --oneline
eddc3c6 (HEAD -> dirty) my new nice changes
  1. Build a single patch file referring to the specific commit:
git format-patch -o patches/ -1 eddc3c6


git format-patch -o patches/ -1 HEAD
  1. Sent it to the developer:

or download from development machine via rsync:

rsync -a --rsync-path="sudo rsync" master@host:/home/project/project/patches .
  1. Later (after the changes have been integrated in the main project), you might want to cleanup your working clone:
git checkout master
git branch -D dirty
rm -fr ./patches

On your development machine ...

Apply the changes:

$ git am patches/0001-retrieve_avatars-fixes.patch

Note that, as a result of applying the patch, the changes have already been committed to your working branch:

$ git log --oneline
de4ccec (HEAD -> master) my new nice changes

  Sentry Notes

Setting up Your Development Environment

  Deleting GIT branches

Deleting a local branch:

git branch -d feature/login

To delete a remote branch, we do not use the "git branch" command, but instead "git push" with the "--delete" flag:

git push origin --delete feature/login

If that fails because the remote branch has already been deleted, update your local list of remote branches:

git remote update origin --prune

Please keep in mind that local and remote branches actually have nothing too do with each other. They are completely separate objects in Git. Even if you've established a tracking connection (which you should for most scenarios), this still does not mean that deleting one would delete the other, too!

If you want any branch item to be deleted, you need to delete it explicitly.

  Django Custom Error Views setup

First, create your custom views for error handling:

file main/

from django.shortcuts import render

def bad_request(request, exception=None, template_name='400.html'):
    return render(request, 'errors/400.html')

def permission_denied(request, exception=None, template_name='403.html'):
    return render(request, 'errors/403.html')

def not_found(request, exception=None, template_name='404.html'):
    return render(request, 'errors/404.html')

def server_error(request, exception=None, template_name='500.html'):
    return render(request, 'errors/500.html')

and the corresponding templates:

file main/templates/errors/error_base.html:

<!DOCTYPE html>
<html lang="en">
    <!-- Simple HttpErrorPages | MIT License | -->
    <meta charset="utf-8" /><meta http-equiv="X-UA-Compatible" content="IE=edge" /><meta name="viewport" content="width=device-width, initial-scale=1" />
    <title>{% block pagetitle %} Override Here {% endblock %}</title>
    <style type="text/css">/*! normalize.css v5.0.0 | MIT License | */html{font-family:sans-serif;line-height:1.15;-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%}body{margin:0}article,aside,footer,header,nav,section{display:block}h1{font-size:2em;margin:.67em 0}figcaption,figure,main{display:block}figure{margin:1em 40px}hr{box-sizing:content-box;height:0;overflow:visible}pre{font-family:monospace,monospace;font-size:1em}a{background-color:transparent;-webkit-text-decoration-skip:objects}a:active,a:hover{outline-width:0}abbr[title]{border-bottom:none;text-decoration:underline;text-decoration:underline dotted}b,strong{font-weight:inherit}b,strong{font-weight:bolder}code,kbd,samp{font-family:monospace,monospace;font-size:1em}dfn{font-style:italic}mark{background-color:#ff0;color:#000}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}audio,video{display:inline-block}audio:not([controls]){display:none;height:0}img{border-style:none}svg:not(:root){overflow:hidden}button,input,optgroup,select,textarea{font-family:sans-serif;font-size:100%;line-height:1.15;margin:0}button,input{overflow:visible}button,select{text-transform:none}[type=reset],[type=submit],button,html [type=button]{-webkit-appearance:button}[type=button]::-moz-focus-inner,[type=reset]::-moz-focus-inner,[type=submit]::-moz-focus-inner,button::-moz-focus-inner{border-style:none;padding:0}[type=button]:-moz-focusring,[type=reset]:-moz-focusring,[type=submit]:-moz-focusring,button:-moz-focusring{outline:1px dotted ButtonText}fieldset{border:1px solid silver;margin:0 2px;padding:.35em .625em .75em}legend{box-sizing:border-box;color:inherit;display:table;max-width:100%;padding:0;white-space:normal}progress{display:inline-block;vertical-align:baseline}textarea{overflow:auto}[type=checkbox],[type=radio]{box-sizing:border-box;padding:0}[type=number]::-webkit-inner-spin-button,[type=number]::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}[type=search]::-webkit-search-cancel-button,[type=search]::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}details,menu{display:block}summary{display:list-item}canvas{display:inline-block}template{display:none}[hidden]{display:none}/*! Simple HttpErrorPages | MIT X11 License | */body,html{width:100%;height:100%;background-color:#21232a}body{color:#fff;text-align:center;text-shadow:0 2px 4px rgba(0,0,0,.5);padding:0;min-height:100%;-webkit-box-shadow:inset 0 0 100px rgba(0,0,0,.8);box-shadow:inset 0 0 100px rgba(0,0,0,.8);display:table;font-family:"Open Sans",Arial,sans-serif}h1{font-family:inherit;font-weight:500;line-height:1.1;color:inherit;font-size:36px}h1 small{font-size:68%;font-weight:400;line-height:1;color:#777}a{text-decoration:none;color:#fff;font-size:inherit;border-bottom:dotted 1px #707070}.lead{color:silver;font-size:21px;line-height:1.4}.cover{display:table-cell;vertical-align:middle;padding:0 20px}footer{position:fixed;width:100%;height:40px;left:0;bottom:0;color:#a0a0a0;font-size:14px}</style>
    <div class="cover">
          {% block title %}Bad Request{% endblock title %}
          <small>{% block subtitle %}Error 400{% endblock subtitle %}</small>
      <p class="lead">
          {% block explain %}The server cannot process the request due to something that is perceived to be a client error.{% endblock explain %}

      <br />
      <a href="/">Click here to reload</a>

      {% comment %}
      <p>Technical Contact: <a href=""></a></p>
      {% endcomment %}
      <p>{{ SITE_COMPANY }} - {{ SITE_TITLE }} - {{ PROJECT_BUILD }}</p>

file main/templates/errors/400.html:

{% extends 'errors/error_base.html' %}

{% block pagetitle %}
Bad Request
{% endblock pagetitle %}

{% block title %}
Bad Request
{% endblock title %}

{% block subtitle %}
Error 400
{% endblock subtitle %}

{% block explain %}
The server cannot process the request due to something that is perceived to be a client error.
{% endblock explain %}

file main/templates/errors/403.html:

{% extends 'errors/error_base.html' %}

{% block pagetitle %}
Access Denied
{% endblock pagetitle %}

{% block title %}
Access Denied
{% endblock title %}

{% block subtitle %}
Error 403
{% endblock subtitle %}

{% block explain %}
The requested resource requires an authentication.
{% endblock explain %

file main/templates/errors/404.html:

{% extends 'errors/error_base.html' %}

{% block pagetitle %}
Resource Not Found
{% endblock pagetitle %}

{% block title %}
Resource Not Found
{% endblock title %}

{% block subtitle %}
Error 404
{% endblock subtitle %}

{% block explain %}
The requested resource could not be found but may be available again in the future.
{% endblock explain %}

file main/templates/errors/500.html:

{% extends 'errors/error_base.html' %}

{% block pagetitle %}
Webservice currently unavailable
{% endblock pagetitle %}

{% block title %}
Webservice currently unavailable
{% endblock title %}

{% block subtitle %}
Error 500
{% endblock subtitle %}

{% block explain %}
An unexpected condition was encountered.<br />
Our service team has been dispatched to bring it back online.
{% endblock explain %

Finally, tell Django to use our custom views:

file main/

handler400 = 'main.views.bad_request'
handler403 = 'main.views.permission_denied'
handler404 = 'main.views.not_found'
handler500 = 'main.views.server_error'

Test with DEBUG=False in settings


  Many-to-many example using "through" to augment M2M relationships

On one side of the relation, we do the following:


class Device(models.Model):

    users = models.ManyToManyField(

class DeviceUsers(models.Model):

    class Meta:
        verbose_name = _("Device/User")
        verbose_name_plural = _("Device/Users")

    device = models.ForeignKey(Device, verbose_name=_('Device'), on_delete=models.CASCADE)
    user = models.ForeignKey(User, verbose_name=_('User'), on_delete=models.CASCADE)
    enabled = models.BooleanField(_('Enabled'), null=False, default=True, blank=True)
    expiration_data = models.DateField(_('Expiration date'), null=True, blank=True)

    def __str__(self):
        return ''

while nothing is required in the related Model.

In the admin, we can:

  • add inlines to edit the relation (in both ModelAdmins),
  • (optionally) list the related models in the listing
  • note that we also add a search_fields attribute to have autocomplete_fields working (Django 2.x)


class UserForDeviceTabularInline(admin.TabularInline):
    model = Device.users.through
    extra = 0
    autocomplete_fields = ['user', ]

class DeviceAdmin(BaseModelAdmin):

    list_display = [..., 'list_users', ]
    search_fields = ['=id', 'description', 'code', ]
    inlines = [UserForDeviceTabularInline, ]

    def list_users(self, obj):
        return mark_safe(', '.join([
            '<a href="%s">%s</a>' % (user.get_admin_url(), str(user))
            for user in obj.users.all()  # .order_by('panelregisters__position')
    list_users.short_description = _('users')

class DeviceTabularInline(admin.TabularInline):
    from backend.models import Device
    model = Device.users.through
    #exclude = ['position', ]
    extra = 0
    autocomplete_fields = ['device', ]

class UserAdmin(AuthUserAdmin, HijackUserAdminMixin):

    list_display = [..., 'list_devices', ]
    inlines = [DeviceTabularInline, ]

    def list_devices(self, obj):
        return mark_safe(', '.join([
            '<a href="%s">%s</a>' % (device.get_admin_url(), str(device))
            for device in obj.devices.all()  # .order_by('panelregisters__position')
    list_devices.short_description = _('devices')

TODO: add select_related() as required

  New Django project check-list

A check list of what I normally do when creating a brand new Django project.

Initial project skeleton

  • create a local virtual environment for development, and install lastest version of django in it

  • create a folder container for the project as follows:

    |- customerName
         |- myNewProjectName
               |- logs
               |- dumps
               |- public
               |     |- media
               |     |- static
               |- myNewProjectName  <-- project sources go here
  • create the project skeleton with python django-admin startproject and name it main

  • replace file with a "settings" module, and adjust it as needed; the final project layout is:

    |- customerName
         |- myNewProjectName
               |- logs
               |- dumps
               |- public
               |     |- media
               |     |- static
               |- myNewProjectName
                     |- main


        from main.settings.local import *
        from main.settings.settings import *
  • main/settings/ will contain db settings and the secret_key, and will be excluded from GIT repo

  • add a requirements file to keep track of installed modules and versions

Custom User model

  • create a "users" app
  • use it to override User model (derived from django.contrib.auth.models.AbstractUser)
  • add and configure Hijack app

Versioning and other initializations

  • create a git repo for the project
  • create an "admin_ex" app for a customized (possibly empty) AdminSiteEx(admin.AdminSite)
  • add a main.apps.MainConfig to install admin_ex.admin_site.AdminSiteEx as project admin
  • define and variables
  • configure bumpversion to manage versioning

Deployment procedure

  • add "django-channels" to have daphne installed
  • setup a provisioning procedure for initial host setup
  • setup a deployment procedure for project installation and update
  • run it over a staging server asap

Email setting

Add helper apps

  • django-constance
  • django-smuggler
  • django-debug-toolbar

Review settings for security

  • python check --deploy

Sample README.rst file

Project "XXXXX"

Manual provisioning on local development machine

Create environment for new project::

    $ cd /Projects/
    $ mkdir XXXXX
    $ mkdir XXXXX/public
    $ mkdir XXXXX/public/static
    $ mkdir XXXXX/public/media

Create and activate a virtualenv for the project::

    $ mkvirtualenv XXXXX
    $ workon XXXXX

Clone source repository::

    $ cd /Projects/XXXXX
    $ git clone

The final project layout is::

    ├── XXXXX
    │   ├── README.rst
    │   ├── ...
    │   ├──
    │   ├── main          <---- this is the Django project
    │   ├── requirements
    │   └── ...
    └── public
        ├── media
        └── static

Update the virtualenv (that is: Install required python packages)::

    $ cd /Project/XXXXX/XXXXX
    $ pip install -r requirements/development.txt

Create a local settings file;
for example, copy and adapt ""::

    $ cd /Project/XXXXX/XXXXX
    $ cp main/settings/ main/settings/

Create database (use database name and password specified in

    $ psql
    $ create user XXXXX with encrypted password '<PASSWORD>';
    $ create database XXXXX owner XXXXX;

Populate database struct::

    $ python migrate

Update front-end assets (if any)::

    $ npm install

Create a supersuser account::

    $ python createsuperuser

Run the development web server::

    $ python runserver

Development workflow


    $ cd /Project/XXXXX/XXXXX
    $ workon XXXXX
    $ git pull
    $ git submodule update
    $ pip install -r requirements/development.txt
    $ python migrate
    $ npm install
    $ python runserver


  Json prettified fields in Django admin

To render a JSONfield as colored and formatted text in a Django change-view, add a readonly field as follows:

class DeviceTestTaskAdmin(TaskAdmin):

    exclude = ('program_steps', )

    readonly_fields = [..., 'program_steps_prettified', ]

    def program_steps_prettified(self, obj):
        return json_prettify(obj.program_steps)

where json_prettify() is a helper function responsible to format JSON data using Pygments:


import json
from django.utils.safestring import mark_safe
from pygments import highlight
from pygments.lexers import JsonLexer
from pygments.formatters import HtmlFormatter

def json_prettify_styles():
    Used to generate Pygment styles (to be included in a .CSS file) as follows:
    formatter = HtmlFormatter(style='colorful')
    return formatter.get_style_defs()

def json_prettify(json_data):
    Adapted from:

    # Get the Pygments formatter
    formatter = HtmlFormatter(style='colorful')

    # Highlight the data
    json_text = highlight(
        json.dumps(json_data, sort_keys=True, indent=2),

    # # remove leading and trailing brances
    # json_text = json_text \
    #     .replace('<span class="p">{</span>\n', '') \
    #     .replace('<span class="p">}</span>\n', '')

    # Get the stylesheet
    #style = "<style>" + formatter.get_style_defs() + "</style>"
    style = ''

    # Safe the output
    return mark_safe(style + json_text)

Suitable styles can be produced with:


and included in a CSS file; for example:

 *  Pygment styles
 *  Generated by 'gui.utils.json_prettify_styles()'

.highlight .hll { background-color: #ffffcc }
.highlight .c { color: #888888 } /* Comment */
.highlight .err { color: #FF0000; background-color: #FFAAAA } /* Error */
.highlight .k { color: #008800; font-weight: bold } /* Keyword */


  Sinewave redis PUBSUB example

sinewave publisher

import math, time
import redis

r = redis.StrictRedis(host='localhost', port=6379, db=0)

for n in range(0, 100000):
    row = (62 * 'X')[0:32 + int(30*math.sin(n/8.0))]
    r.publish('sinewave', row)
    print('\x1b[1;36;40m' + row + '\x1b[0m')

sinewave listener

import redis

r = redis.StrictRedis(host='localhost', port=6379, db=0, decode_responses=True)

pubsub = r.pubsub()

for item in pubsub.listen():
    if item['type'] == 'message':

  Removing the output of Django runserver

In settings:


    'version': 1,
    'disable_existing_loggers': True,
    'handlers': {
        'null': {
            'class': 'logging.NullHandler',
    'loggers': {
        'django.server': {
            'handlers': ['null'],
            'level': 'INFO',
            'propagate': False,

# import logging.config
# logging.config.dictConfig(LOGGING)

If using channels, use 'django.channels.server' logger instead:

'loggers': {
    'django.server': {
        'handlers': ['null'],
        'level': 'INFO',
        'propagate': False,
    'django.channels.server': {
        'handlers': ['null'],
        'level': 'INFO',
        'propagate': False,


To print everything except 200 responses, you could use

./ runserver 2>&1 | grep -v " 200 "

  Virtualbox - Fix Freezing with Linux Guests on Windows 10 Hosts

In Settings/Storage/Controller: SATA:

make sure "Use Host I/O Cache" is checked


  Logging in to Django REST and POSTing forms using HTTPie

Logging in to Django REST using HTTPie

Logging in to Django using HTTPie:

http localhost:8000/users/ -h
HTTP/1.0 403 Forbidden
Content-Type: application/json
Date: Wed, 13 Apr 2016 12:01:24 GMT
Server: WSGIServer/0.1 Python/2.7.11
Vary: Accept, Cookie
X-Frame-Options: SAMEORIGIN

First we want to get the CSRF Token by visiting a page:

http localhost:8000/api-auth/login/ --session=session1 -h
HTTP/1.0 200 OK
Cache-Control: no-cache, no-store, must-revalidate, max-age=0
Content-Type: text/html; charset=utf-8
Date: Wed, 13 Apr 2016 12:01:51 GMT
Expires: Wed, 13 Apr 2016 12:01:51 GMT
Last-Modified: Wed, 13 Apr 2016 12:01:51 GMT
Server: WSGIServer/0.1 Python/2.7.11
Set-Cookie:  csrftoken=Z6BWtOS9hmVtZ0QoVkYegMo8Ckduyv7y; expires=Wed, 12-Apr-2017 12:01:51 GMT; Max-Age=31449600; Path=/
Vary: Cookie
X-Frame-Options: SAMEORIGIN

It is now stored in a cookie:

cat session1.json
    "__meta__": {
        "about": "HTTPie session file",
        "help": "",
        "httpie": "0.9.3"
    "auth": {
        "password": null,
        "type": null,
        "username": null
    "cookies": {
        "csrftoken": {
            "expires": 1491998511,
            "path": "/",
            "secure": false,
            "value": "Z6BWtOS9hmVtZ0QoVkYegMo8Ckduyv7y"
    "headers": {}

Then we log in with the X-CSRFToken header set:

http -f POST localhost:8000/api-auth/login/ username=admin password=password123 X-CSRFToken:Z6BWtOS9hmVtZ0QoVkYegMo8Ckduyv7y --session=session1 -h
HTTP/1.0 302 Found
Cache-Control: no-cache, no-store, must-revalidate, max-age=0
Content-Type: text/html; charset=utf-8
Date: Wed, 13 Apr 2016 12:02:46 GMT
Expires: Wed, 13 Apr 2016 12:02:46 GMT
Last-Modified: Wed, 13 Apr 2016 12:02:46 GMT
Location: /accounts/profile/
Server: WSGIServer/0.1 Python/2.7.11
Set-Cookie:  csrftoken=xhZLDurJlYrTKu6JGTwaF0BQinQfV8l4; expires=Wed, 12-Apr-2017 12:02:46 GMT; Max-Age=31449600; Path=/
Set-Cookie:  sessionid=skjcmbsm4a4jtn43sl0npybpdopttk5y; expires=Wed, 27-Apr-2016 12:02:46 GMT; httponly; Max-Age=120960
0; Path=/
Vary: Cookie
X-Frame-Options: SAMEORIGIN


Altra sessione per eseguire un POST complesso via linea comandi

In tutte le chiamate faremo riferimento al file di sessione "./session.json" per garantire la persistenza degli headers custom in successive richieste allo stesso host.

Eseguimo un post sulla pagina di login, che fallira' con errore CSRF_FAILURE_VIEW:

http POST -h
Content-Language: it
Content-Type: text/html
Date: Tue, 28 Aug 2018 15:19:51 GMT
Server: WSGIServer/0.1 Python/2.7.13
Set-Cookie: sessionid=70b12537dfdf4fec75fbce86d0d6f6e7; expires=Tue, 11-Sep-2018 15:19:51 GMT; Max-Age=1209600; Path=/
Vary: Accept-Language, Cookie

Per ottenere il csrftoken, consultiamo nuovamente la pagina (metodo GET):

http --session=./session.json -h
HTTP/1.0 200 OK
Cache-Control: max-age=0
Content-Language: it
Content-Type: text/html; charset=utf-8
Date: Tue, 28 Aug 2018 15:23:52 GMT
ETag: "7892c1deb1c4eeca304cada025e5db84"
Expires: Tue, 28 Aug 2018 15:23:52 GMT
Last-Modified: Tue, 28 Aug 2018 15:23:52 GMT
Server: WSGIServer/0.1 Python/2.7.13
Set-Cookie: csrftoken=87035d38eee0ce9c3728c3caf53e21e3; Max-Age=31449600; Path=/
Set-Cookie: sessionid=eb0cc1b2a6c930fb12b76857446a19ed; expires=Tue, 11-Sep-2018 15:23:52 GMT; Max-Age=1209600; Path=/
Vary: Cookie, Accept-Language

Eseguiamo il submit della form di login includendo il csrftoken appena ricevuto:

http -f POST localhost:8000/login/ username=USERNAME password=PASSWORD X-CSRFToken:87035d38eee0ce9c3728c3caf53e21e3 --session=./session.json -h

A questo punto possiamo eseguire il post di arbitrarie form; nel seguente esempio abbiamo utilizzato i dati di una form precedentemente compilata interattivamente, ricavati dall'inspector.

Notare che e' stato aggiunto un "&" al termine per evitare che l'ultimo parametro terminasse con un "n" indesiderato:

 echo "target_user=677&elearning_hours=45&section_3=23&section_3=24&section_4=26&promo_code=&company_vat_id=02409140361&company_name=Brainstorm&company_street_type=Viale&company_address=Francesco+Crispi%2C+2&company_zipcode=41121&company_city=MODENA&company_province=108&"
| http POST --session=./session.json -h
HTTP/1.0 302 FOUND
Content-Language: it
Content-Type: text/html; charset=utf-8
Date: Tue, 28 Aug 2018 15:38:20 GMT
Server: WSGIServer/0.1 Python/2.7.13
Set-Cookie: sessionid=f25876fa079fd975c435e7dbc75dba95; expires=Tue, 11-Sep-2018 15:38:20 GMT; Max-Age=1209600; Path=/
Vary: Accept-Language, Cookie

  Control Spotlight indexing activities

Turns off indexing of files:

sudo mdutil -a -i off

To turn indexing back on, run:

sudo mdutil -a -i on

Complete re-indexing of your hard drive (be aware this could be an over night job): it will delete your Spotlight data base forcing it to start over:

sudo rm -rf /.Spotlight-V100/*


add others to your (do not scan), privacy settings.