Some tips for django

Easily increment migrations numbers

Here is a small bash script to increment the numbers of your migrations. Put it into your ~/.profile or ~/.bashrc. Use it like: inc-migrations PROJECT/apps/APP_NAME/migrations 0012

It will rename all migrations from 0012 (ie transform 0012_mig.py into 0013_mig.py and so on) and replace all occurrences of the previous name (eg 0012_mig.py) with the new one (eg 0013_mig.py).

function inc-migrations() {
    local folder="$1"
    local number="$2"
    local start_file
    local new_number
    local next_file

    if ! [[ "$(pwd)" =~ "${folder}$" ]]; then
        cd "${folder}"
    fi

    if [[ -f "${number}" ]]; then
        start_file="${number}"
        number=$(echo "${number}" | cut -d _ -f 1)
    else
        start_file=$(ls ${number}* 2> /dev/null)
    fi

    if [[ ! -f "${start_file}" ]]; then
        echo "${start_file} doesn't exits" >&2
        return 1
    fi
    let "new_number = ${number} + 1"
    new_number=$(printf "%04d\n" "${new_number}")
    next_file=$(ls ${new_number}* 2> /dev/null)

    new_file_name="${start_file/${number}/${new_number}}"
    git mv "${start_file}" "${new_file_name}"
    sed -i "s/${start_file/.py/}/${new_file_name/.py/}/g" *.py

    if [[ -f "${next_file:-}" ]]; then
        inc-migrations "${folder}" "${next_file}"
    fi
}

Create a widget with custom display

class BonusTimeWidget(AdminIntegerFieldWidget):
    UNITS_TO_TRANSLATIONS = {
        'month': partial(ungettext_lazy, '%(count)d month', '%(count)d free months'),
    }

    def __init__(self, *args, unit='month', **kwargs):
        super().__init__(*args, **kwargs)
        if unit not in self.UNITS_TO_TRANSLATIONS:
            supported_units = ','.join(self.UNITS_TO_TRANSLATIONS.keys())
            raise ValueError(
                f'{unit} is not a supported unit. Supported units are: {supported_units}',
            )

        self.bonus_translation = self.UNITS_TO_TRANSLATIONS[unit]

    def render(self, name, value, attrs=None):
        """Render the value in a custom span."""
        if value == 0:
            return ''

        text = self.bonus_translation(value) % {'count': value}
        return mark_safe(f'<span>+ {text}</span>')

Use a nginx reverse proxy in dev

The django web server works well but can be slow when it needs to handle many requests (to load many images for instance). One way to solve this is to use a production web server (nginx in this case) to handle most of the work (ie everything but dynamically generated pages).

Prerequisites:

  1. Install nginx
  2. Add the domain you want to use in your /etc/hosts file. For instance 127.0.0.1 myproject.localhost.
  3. Make sure nginx has access to the files of your project. Most of the time a chmod 755 /PATH/TO/PROJECT will do (repeat on each subdirectory nginx need to pass to access to your files). If you are using a shared computer, you may need to think about a more secure way to allow nginx to access the file (ACL may help you).
  4. If you are using SELinux, don't forget to add the proper context to the files. For instance, do something like:
    1. Add these files to the proper SELinux context by copying the one from the default web folder: semanage fcontext --add --equal /var/www/html /PATH/TO/PROJECT
    2. Restore the context of the files: restorecon -R /home/jenselme/Work/bureauxlocaux
    3. Check that the context is correct: ls -Z The output should contain something like system_u:object_r:httpd_sys_content_t:s0.

Here is the nginx configuration to put in /etc/nginx/conf.d (or /etc/nginx/sites-enabled):

server {
    listen 80;
    # Make sure this host is in the ALLOWED_HOSTS variable in the settings.
    server_name PROJECT.localhost;
    root /PATH/TO/PROJECT;

    # Prevent access to pyc and py files.
    location ~ .*\.pyc? {
        return 404;
    }

    # Search for files in the media folder. Change this if you configured Django to store your uploaded files elsewhere.
    location ~ ^/files/(.*) {
        try_files /media/$1 =404;
    }

    # Look for static files in the static folder or at the root of the project.
    location ~ ^/static {
        # Look both in the production static folder at the root of you project and in PROJECT
        # (where you have the apps directory and the static directory you use in dev).
        try_files /PROJECT/$uri /$uri $uri;
    }

    # Relay everything else to the django web server.
    location / {
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header Host $http_host;
        proxy_redirect off;
        proxy_pass http://127.0.0.1:8000;
    }
}

Pages

blogroll

social

>