Development =========== This section covers some of the basic steps and guidelines when doing "development" of *Majic Django Templates*. This refers to updating the templates and adding support for new Django versions, and should not be confused with actual Django development that is based on templates. Environment ----------- For development purposes, it is recommended to have a dedicated Python virtual environment. For example, let's say that *Majic Django Templates* has been cloned in directory ``~/majic-django-templates``. You would simply create a new virtual environment, and set its home path to point to cloned repository:: mkvirtualenv majic-django-templates -a ~/majic-django-templates The virtual environment allows you to install the necessary Django versions without affecting the rest of the system. Once you are in the virtual environment, you may want to update ``pip`` and ``setuptools`` to have a couple of more up-to-date features available when installing the packages:: workon majic-django-templates && pip install -U pip setuptools Adding project template for new Django release ---------------------------------------------- Since Django follow semantic versioning, project template needs to be added for every new major or minor release of Django. This is just a rough outline of what needs to be done. .. warning: All values like package versions etc are provided as examples. Make sure to update them before running the commands. 1. Start off by activating your virtual environment:: workon majic-django-templates 2. Install latest patch release of targeted Django version, removing any currently installed version:: pip install -U Django~=1.8.0 3. Start a new Django project using a unique string as project name. This name will not be used for the final product, it merely lets you locate certain parts of the file that need to be changed in order to use templated project name:: django-admin startproject abcdef 4. Replace placeholder project name with proper Django template variable:: find abcdef/ -type f -exec sed -i -e 's/abcdef/{{ project_name }}/' '{}' \; 5. Set-up the project settings to be a Python module and move the current set of settings to be the base configuration:: mkdir abcdef/abcdef/settings/ touch abcdef/abcdef/settings/__init__.py mv abcdef/abcdef/settings.py abcdef/abcdef/settings/base.py 6. Set-up settings file for development environment. It should default to using SQLite3, debugging should be fully enabled, and secret key should be static, coming from auto-generated value from ``django-admin startproject`` command. .. warning: Pay special care that parameters listed in this file make sense with your Django version. For example, debugging options have been known to change in Django. :file:`abcdef/abcdef/settings/development.py` :: # Development environment settings for project {{ project_name }}. # Import the base settings. from .base import * # Credentials in development environment are static. SECRET_KEY="{{ secret_key }}" # Enable debugging in development environment. DEBUG = True for template_config in TEMPLATES: template_config['OPTIONS']['debug']=True # Site administrators and managers. ADMINS = ( # ('Your Name', 'your_email@example.com'), ) MANAGERS = ADMINS # Use SQLite3 for simplicity in development environment. DATABASES = { 'default': { 'ENGINE': 'django.db.backends.sqlite3', 'NAME': 'development.sqlite3', 'USER': '', 'PASSWORD': '', 'HOST': '', 'PORT': '', } } 7. Set-up settings files for **testing**, **staging**, and **production** environments. These should be identical, except for the header (which should clearly identify the environment). .. warning: Pay special care that parameters listed in this file make sense with your Django version. :file:`abcdef/abcdef/settings/ENVIRONMENT.py` :: # ENVIRONMENT environment settings for project {{ project_name }}. # Import the base settings. from .base import * # Import credentials. try: from .credentials import DATABASE_PASSWORD except ImportError: raise ImproperlyConfigured("Please configure DATABASE_PASSWORD in credentials.py.") try: from .credentials import SECRET_KEY except ImportError: raise ImproperlyConfigured("Please configure SECRET_KEY in credentials.py.") # Disable debugging. DEBUG = False for template_config in TEMPLATES: template_config['OPTIONS']['debug']=False # Site administrators and managers. ADMINS = ( # ('Your Name', 'your_email@example.com'), ) MANAGERS = ADMINS # Database configuration. DATABASES = { 'default': { 'ENGINE': 'django.db.backends.mysql', 'NAME': '{{ project_name }}', 'USER': '{{ project_name }}', 'PASSWORD': DATABASE_PASSWORD, 'HOST': '127.0.0.1', 'PORT': '', } } # Hostnames/FQDNs considered valid for accessing the installation. ALLOWED_HOSTS = [] 8. Further customisations will depend on Django version being used. At the very least take the following guidelines into consideration: - Anything representing a secret/password should only be explicitly specified in ``development.py``. In all other settings files the parameter should be removed, and should be instead imported from ``credentials`` module. - Introduce explicit checks for existence of imported variables from credentials module. This will save you in the long run in case of misconfiugurations of credentials (and things like typos). - Remove credentials/secrets from ``base.py``. - Remove debugging options from ``base.py``. - Remove things like allowed hosts from ``base.py``. - Remove database configuration from ``base.py``. - Configure things like media/static URLs and media/static roots. It is recommended to use dedicated assets directory for those, lying one level above the project root. A convenient way to calculate assets directory dynamically is (put this somewhere in ``base.py``):: # Determine assets directory location. ASSETS_ROOT = os.path.normpath(os.path.join(BASE_DIR, "assets")) Afterawards you can have something similar to the following snippet at the end of ``base.py``:: # URLs for serving the static and media files. STATIC_URL = '/static/' MEDIA_URL = '/media/' # Absolute filesystem path to directory that will hold user-uploaded # files. MEDIA_ROOT = os.path.normpath(os.path.join(ASSETS_ROOT, "media")) # Absolute filesystem path to directory that will hold static files. STATIC_ROOT = os.path.normpath(os.path.join(ASSETS_ROOT, "static")) # Additional locations for static files. Useful for project-wide overrides of # default static files. STATICFILES_DIRS = ( os.path.normpath(os.path.join(BASE_DIR, "static")), ) 9. At this point you need to be a bit more creative. Depending on Django version, you may need to isolate different settings to be part of the base settings file, defined in development settings file etc. 10. Update the comments in all settings files to be more informational. If there are existing project templates, you may want to have a look at those to get a good idea what should be written. 11. Rename the directories:: mv abcdef/abcdef/ abcdef/project_name mv abcdef/ project-django-1.8 12. Create usage instructions for the new project template. It is important to do so even if it duplicates other instructions since different versions of Django can have both subtle and important differences in how they are configured. Instructions should cover how the project is started, layout of directories and settings files, as well as useful information on how to have the system running when used in testing/staging/production environment via Gunicorn.