Mount-Mockery - django

/mycreole/attachment/it/howto/django/django.png

Initial project creation

Prepare project and venv

$ mkdir <PROJECTNAME>
$ cd <PROJECTNAME>
$ python -m venv venv
$ source venv/bin/activat
$ pip install Django

Activate your venv

Every time you want to use your django project, you need to enable the venv. This venv activation will not be mentioned in the rest of the instruction.

$ source venv/bin/activat

Create the django project

Create the project

The basic django environment can be created by the following command:

$ django-admin startproject <PROJECTNAME> .

Create your app

A django project can consist out of multiple apps. With this command you are able to create your own first app:

$ django-admin startapp <APP>

and add the following line to the list INSTALLED_APPS of your <PROJECTNAME>/settings.py:

    '<APP>.apps.<APP_as_camelcase>Config',

Migrate

After data structure changes you need to do a migration. After initially creating a project you also need to do a migration by:

python manage.py migrate

Start the server

Now you are able to start the server. You havn't created content yet. Therefore you see a welcome page when you visit http://127.0.0.1:8000 (also mentioned in the output of the command starting the server):

$ python manage.py runserver

Add the first content

Create an example view

In the file <app>/views.py you can create a method, which is called, if a defined page is executed. Here is an example for your view file:

from django.http import HttpResponse
from django.conf import settings
import logging

logger = logging.getLogger(settings.ROOT_LOGGER_NAME).getChild(__name__)


def example(request, rel_path=''):
    logger.info("Someone called the example page. The page was rel_path=%s", rel_path)
    return HttpResponse("This is an example only...")

Remark: You need to define ROOT_LOGGER_NAME in your settings.py or add the logging configuration (see section below).

Add the example view to your project

You can choose one of the following sections for adding your first page to an url. In both cases, you edit the file <PROJECTNAME>/urls.py.

Add the view directly

Import your <APP> on the top beneath the other imports

import <APP>.views

and add the following line to the list urlpatterns:

    path('<APP>/', <APP>.views.example, name='<APP>-example'),
    path('<APP>/<path:rel_path>', <APP>.views.example, name='<APP>-example'),

Add views by an import

Import include on the top beneath the other imports

from django.urls import include

and add the following line to the list urlpatterns:

    path('<APP>/', include('<APP>.urls')),

In addition you need to create the file <APP>/urls.py, where you can define the <APP> urls:

from django.urls import path
from . import views

urlpatterns = [
    path('', views.example, name='app-example'),
    path('<path:rel_path>', views.example, name='app-example'),
]

Inspect your first page

In the urls.py we defined two urls. The first is the root page (assuming <APP> was app)

http://127.0.0.1:8000/app

The second url definition is for all subpages below this url. Here an example

http://127.0.0.1:8000/app/any/random/subpage

Remark: We added a log entry, but we can't see that log. See the logging section at the configuration.

My extensions

Themes

This extension provides a clear theme. See also here.

Users

This extension provides basic user actions (login, logout, register, ...). See also here.

Mycreole

This extension provides the possibility to use creole markup language for for pages. See also here.

Configuration

Config extention

config.py

This config extention makes it possible to move user specific parameters to a config.py.

Remark: Your config.py shall have a SECRET_KEY definition and the access to that file shall be limited to the owner.

Here is an example of such a config.py:

#######################################################################
# Configuration of your django application
#######################################################################

#
# Django
#
# This defines the mode of the running server
# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = True

# This a the secret key for your application.
# SECURITY WARNING: don't run with a dummy secret in production! And don't let others read this key!
#SECRET_KEY = "Insecure_KEY"

# This defines the listener hostnames for your django server
# SECURITY WARNING: don't run with '0.0.0.0' in in production, unless you know what you are doing!
#ALLOWED_HOSTS = ['<YOUR_SERVER_HOSTNAME>', ]

# This might be needed for usage in a docker environment
#CSRF_TRUSTED_ORIGINS = ['<YOUR_SERVER_URL>', ]

#
# Themes library
#
# This defines the default theme, if no theme is set in the django parameters
#DEFAULT_THEME= 'clear-blue',

Settings extentions

Place these imports on the top of the file <PROJECTNAME>/settings.py:

import config
from logging.handlers import SocketHandler as _SocketHandler
import os
import random
import stat
import sys

and add this code at the very end

# Check permission of config.py
#
if sys.platform == 'linux' or sys.platform == 'linux2':
    st = os.stat(os.path.join(BASE_DIR, 'config.py'))
    if st.st_mode & stat.S_IRGRP or st.st_mode & stat.S_IROTH:
        raise PermissionError("conig.py is readable by group or others.")

# Default values, if not defined in config.py
#
USER_CONFIG_DEFAULTS = {
    'DEBUG': False,
    'SECRET_KEY': None,
    'DEFAULT_THEME': 'clear-blue',
    'ALLOWED_HOSTS': ['127.0.0.1', 'localhost', ],
    'CSRF_TRUSTED_ORIGINS': [],
}

# Set configuration parameters
#
thismodule = sys.modules[__name__]
for property_name in USER_CONFIG_DEFAULTS:
    try:
        value = getattr(config, property_name)
    except AttributeError:
        value = USER_CONFIG_DEFAULTS[property_name]
    setattr(thismodule, property_name, value)

# SECURITY WARNING: keep the secret key used in production secret!
#
if SECRET_KEY is None:
    chars = 'abcdefghijklmnopqrstuvwxyz0123456789!@#$%^&*(-_=+)'
    s_key = ''.join([random.choice(chars) for n in range(50)])
    secret_key_warning = "You need to create a config.py file including at least a SECRET_KEY definition (e.g.: --> %s <--).    " % repr(s_key)
    raise KeyError(secret_key_warning)

Logging

To enable the logging of your personal modules, you need to adapt the settings.py. In debug mode the logging will be passed to a socket. You need a tool to view the logs (e.g. cutelog).

# Logging Configuration
#
ROOT_LOGGER_NAME = os.path.basename(os.path.dirname(__file__))
default_handler = ['socket', 'console'] if DEBUG else ['console']


class DjangoSocketHandler(_SocketHandler):
    def emit(self, record):
        if hasattr(record, 'request'):
            record.request = None
        return super().emit(record)


LOGGING = {
    'version': 1,
    'disable_existing_loggers': False,
    'formatters': {
        'short': {
            'format': "%(name)25s - %(levelname)10s - %(message)s",
            'datefmt': '[%d/%b/%Y %H:%M:%S]',
        },
        'long': {
            'format': """~~~~(%(levelname)-10s)~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
File "%(pathname)s", line %(lineno)d, in %(funcName)s
%(asctime)s: %(name)s - %(message)s
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~""",
        },
    },
    'handlers': {
        'console': {
            'level': 'DEBUG',
            'class': 'logging.StreamHandler',
            'formatter': 'short',
        },
        'socket': {
            'level': 'DEBUG',
            'class': f'{ROOT_LOGGER_NAME}.settings.DjangoSocketHandler',
            'host': '127.0.0.1',
            'port': 19996,
        },
    },
    },
    'loggers': {
        'django': {
            'handlers': ['console'],
            'level': 'INFO',
            'propagate': False,
        },
        ROOT_LOGGER_NAME: {
            'handlers': ['console'],
            'level': 'DEBUG' if DEBUG else 'INFO',
            'propagate': False,
        },
    },
}