Working Ninja
2017-08-30T17:52:40

Using the ManifestStaticFilesStorage storage backend alters the filename of our static files. For example, style.css becomes something like style.3d94ea84cd8a.css. When collectstatic is run and finds a file that has changed, the MD5 portion of the filename will be updated (style.3d94ea84cd8a.css -> style.1d74ea7349df.css). This prevents browsers and other caching technologies (e.g. Cloudflare) from referring to an outdated static file.

Here are the minimum settings / steps to get this going:

# settings.py
STATIC_ROOT = os.path.join(BASE_DIR, 'static'),

STATICFILES_STORAGE = 'django.contrib.staticfiles.storage.ManifestStaticFilesStorage'

STATICFILES_DIRS = [
    os.path.join(BASE_DIR, 'staticfiles'),
]

After setup (and after updates to any files contained within STATICFILES_DIRS), make sure to run ./manage.py collectstatic. This is easy to forget!

More:
https://docs.djangoproject.com/en/stable/ref/contrib/staticfiles/#manifeststaticfilesstorage
https://docs.djangoproject.com/en/stable/ref/settings/#staticfiles-storage

2017-08-27T08:56:34

Here's how I set up logging where:

  • Log files rotate nightly (at midnight).
  • We keep 10 total log files (as history).
import logging
import os

# Set up logging
logger = logging.getLogger(__file__)
handler_kwargs = {
    'filename': os.path.join(base_dir, 'file.log'),
    'when': 'midnight',
    'backupCount': 10
}
handler = handlers.TimedRotatingFileHandler(**handler_kwargs)
formatter = logging.Formatter('%(asctime)s %(levelname)s %(message)s')
handler.setFormatter(formatter)
logger.addHandler(handler)
logger.setLevel(logging.INFO)

# Now log something
logger.info('Log something informative.')
logger.warning('Log a warning.')
logger.error('Log an error.')
logger.critical('Log a critical error.')

More examples and configurations: https://docs.python.org/2.7/library/logging.html

2017-08-27T08:44:20

Python 2.7 is not provided on CentOS 6 because Yum depends on Python 2.6. Simply installing 2.7 over 2.6 will break Yum. Thankfully, Red Hat provides us with an alternate installation method through their SCL project.

First, get Python 2.7 installed:
https://www.softwarecollections.org/en/scls/rhscl/python27/

Next, add the project path to the top of the script:

import sys
sys.path.insert(0,'/path/to/project')
sys.path.insert(0,'/path/to/project/env/lib/python2.7/site-packages')

Lastly, call the script via Cron:

cat /path/to/project/script.py | scl enable python27 python
2017-08-24T21:01:28

Here's a custom manager for a class (Change) that gets all approved changes where "today's date" falls between the Change.start_date and Change.end_date.

# models.py
import datetime
...
# Custom Change Manager that only pulls active, approved changes
class ApprovedChanges(models.Manager):
    def get_queryset(self):
        today = datetime.date.today()
        return super(ApprovedChanges, self).get_queryset().filter(
            approved=True,
            start_date__lte=today,
            end_date__gte=today
        )

class Change(models.Model):
    ...
    approved_changes = ApprovedChanges()

In our view, we could then call all changes for "today" that have been approved:

# views.py
def todays_changes(self):
   changes = Changes.approved_changes.all()
   ...

Source: https://docs.djangoproject.com/en/stable/topics/db/managers/

2017-08-24T07:47:57
# Simple List
', '.join([author.name for author in authors])

# Django
', '.join([author.name for author in book.author_set.all()])

Both will output "Author Name, Author 2 Name, ..., Author x Name"

2017-05-29T10:58:45

I just started my first Django project with Python 3 in earnest. One of the first things I have noticed is that reload isn't available by default from the Django shell. It needs to be imported:

>>> from importlib import reload
>>> reload(<module>)

This became a pretty tedious process and didn't always reload the module as expected. So, instead of reloading the shell and the module to run a command, I moved the commands that I was running into a custom Django management command. No more reloading =)

2017-05-02T17:37:37

The following code allows us to monkey patch the json() method that is returned by requests.post().

import requests
from mock import MagicMock


@mock.patch.object(requests, 'post')
def my_function(self, post):
    attrs = {'json.return_value': {'id': 1}}
    post.return_value = MagicMock(**attrs)

    r = requests.post()
    r.json()['id']

Source: https://docs.python.org/dev/library/unittest.mock.htmll#unittest.mock.NonCallableMock

2017-04-03T20:16:40
from sqlalchemy.sql import text
from sqlalchemy import create_engine

import secrets


engine = create_engine(
    'mssql+pyodbc://{}:{}@MSSQL'.format(
        secrets.username, secrets.password
    )
)
conn = engine.connect()

s = text("SELECT * FROM users WHERE name = :name")
result = conn.execute(s, name=name).fetchall()
print result

For further information on installing and configuring unixODBC (requirement for pyodbc) on Linux:
https://github.com/mkleehammer/pyodbc/wiki/Connecting-to-SQL-Server-from-RHEL-or-Centos

Connecting to Microsoft SQL Server with pyodbc:
http://docs.sqlalchemy.org/en/latest/dialects/mssql.html#dialect-mssql-pyodbc-connect

2017-03-23T17:22:08

Here's a simple way to count lines of code via the command line that I recently used for a Django project:

find . -name '*.py' -not -path "*/migrations/*" | xargs wc -l

or

wc -l **/*.py

Source: http://stackoverflow.com/questions/1358540/how-to-count-all-the-lines-of-code-in-a-directory-recursively#1358573

2017-02-16T15:41:13
#!/usr/bin/python
import sys


try: 
    hex_val = str(sys.argv[1])
except Exception as e:
    sys.exit('Please provide a hex code as an argument (e.g. hex2rgb 333333).')

r = int(hex_val[0:2], 16)
g = int(hex_val[2:4], 16)
b = int(hex_val[4:6], 16)

print('{}, {}, {}'.format(r, g, b))

Append your ~/.bash_aliases with:

alias hex2rgb="~/bin/hex2rgb.py"

Load the new alias:

$ source ~/.bash_aliases

Now we're able to convert Hex to RGB from the command line:

$ hex2rgb e1e1e1
255, 255, 255