====== Django Configuration ====== **General Information** Configuring the Django Web Framework and its dependencies. \\ The **EXAMPLE** sections of code end up building an inventory website. \\ **Checklist** * [[python_wiki:django_install|Django installed]] ---- ====== Database: MariaDB ====== Configuring the MariaDB Database. * Configure MariaDB to listen only on localhostvim /etc/my.cnf [mysqld] bind-address=127.0.0.1 * Start/Enable the databasesystemctl enable mariadb systemctl start mariadb * Run secure setupmysql_secure_installation * Prompts for the following: * Current password for root (should be none, just press enter) * Set database root password * Remove anonymous users * Disallow root logins remotely * Remove test databases * Reload privilege tables * Connect to the databasemysql -u root -p * Create your project's databasecreate database myprojecthere character set utf8; * Create a database user that Django will usecreate user appuserhere@localhost identified by 'PASSWORDHERE'; * Grant permissions for the app user on your project's databasegrant all privileges on myprojecthere.* to appuserhere@localhost; * Flush privilegesflush privileges; ---- ====== Django ====== Configuring Django. * Verify django workspython >>> import django >>> print(django.get_version()) >>> exit() ===== Project/App Setup ===== * Create a directory to store the projectmkdir /home/django cd /home/django * Create a new Django projectdjango-admin startproject myprojecthere cd /home/django/myprojecthere * Create a new Django application inside of the projectpython manage.py startapp myapphere * Edit project settings (/home/django/myprojecthere/myprojecthere/settings.py)# Allowed Referrer Hosts (hostname and any cnames) ALLOWED_HOSTS = ['djangoserver.mycorps.domain.org','myapp.mycorps.domain.org'] # Application definition (add the application, the rest are built in) INSTALLED_APPS = [ # APPNAME.apps.APPCLASSNAME -> see ../myapphere/apps.py 'myapphere.apps.MyapphereConfig', # add your application here 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', ] # Static files (CSS, JavaScript, Images) #https://docs.djangoproject.com/en/1.11/howto/static-files/ STATIC_URL = '/static/' STATIC_ROOT = '/var/www/static/' ===== Database Setup ===== * Edit project settings (/home/django/myprojecthere/myprojecthere/settings.py)# Database Configuration # https://docs.djangoproject.com/en/1.11/ref/settings/#databases DATABASES = { 'default': { 'ENGINE': 'django.db.backends.mysql', 'NAME': 'myprojecthere', 'USER': 'appuserhere', 'PASSWORD': 'PASSWORDHERE', 'HOST': '127.0.0.1', 'PORT': '3306', 'OPTIONS': { 'init_command': "SET sql_mode='STRICT_TRANS_TABLES'", }, } } * Run the initial migrate command to create database tables for built in apps that come with Djangocd /home/django/myprojecthere python manage.py migrate * Describe your data models (objects that will be stored in the database) (/home/django/myprojecthere/myapphere/models.py) **EXAMPLE**# -*- coding: utf-8 -*- from __future__ import unicode_literals from django.db import models # Asset Inventory Example class AssetEntry(models.Model): ##-- Tuples for Use in Field Choices --## #asset_type choices DEVICE_TYPES = ( ('Firewalls', 'Firewalls'), ('Routers', 'Routers'), ('Servers', 'Servers'), ('Storage', 'Storage'), ('Switches', 'Switches'), ('Workstations', 'Workstations'), ) # asset_env choices ENV_NAMES = ( ('Dev', 'Development'), ('Test', 'Testing'), ('Prod', 'Production'), ) # Linux OS List OS_NAMES_LINUX = ( ('CentOS 6', 'CentOS 6'), ('CentOS 7', 'CentOS 7'), ('RHEL 6', 'Red Hat Enterprise Linux 6'), ('RHEL 7', 'Red Hat Enterprise Linux 7'), ('Ubuntu 16.04', 'Ubuntu 16.04'), ('Ubuntu 18.04', 'Ubuntu 18.04'), ) # Windows OS List OS_NAMES_WINDOWS = ( ('Win 2008', 'Windows 2008'), ('Win 2012', 'Windows 2012'), ('Win 2016', 'Windows 2016'), ('Win 7', 'Windows 7'), ('Win 10', 'Windows 10'), ) # Other OS List OS_NAMES_OTHER = ( ('Cisco IOS', 'Cisco IOS'), ('Extreme XOS', 'Extreme XOS'), ('Juniper JunOS', 'Juniper JunOS'), ('NA', 'None'), ('Other', 'Other'), ('VMware ESXi', 'VMware ESXi'), ) # Combined OS List - for asset_os choices OS_NAMES = OS_NAMES_LINUX + OS_NAMES_WINDOWS + OS_NAMES_OTHER # asset_hardware choices HW_TYPES = ( ('Virtual', 'Virtual'), ('Physical', 'Physical'), ) ##-- AssetEntry Fields --## asset_name = models.CharField('Name', max_length=50) asset_type = models.CharField('Device Type', max_length=15, choices=DEVICE_TYPES) asset_description = models.CharField('Description', max_length=100) asset_env = models.CharField('Environment', max_length=15, choices=ENV_NAMES) asset_os = models.CharField('OS Name/Version', max_length = 20, choices=OS_NAMES) asset_hardware = models.CharField('Hardware: Virtual or Physical', max_length = 15, choices=HW_TYPES) # Object representation def __str__(self): return self.asset_name * Stage changes to the databasecd /home/django/myprojecthere python manage.py makemigrations myapphere * Make changes to the databasecd /home/django/myprojecthere python manage.py migrate ===== Logging Setup ===== * Edit project settings (/home/django/myprojecthere/myprojecthere/settings.py)# Logging Configuration LOGGING = { 'version': 1, 'disable_existing_loggers': False, 'formatters': { 'verbose': { 'format' : "[%(asctime)s] %(levelname)s [%(name)s:%(lineno)s] %(message)s", 'datefmt' : "%d/%b/%Y %H:%M:%S", }, 'simple': { 'format': '%(levelname)s %(message)s', }, }, 'handlers': { 'file': { 'level': 'INFO', 'class': 'logging.handlers.RotatingFileHandler', 'filename': '/var/log/myprojecthere/myapphere.log', 'maxBytes': 500000000, # 500 MB 'backupCount': 10, 'formatter': 'verbose', }, }, 'loggers': { 'django': { 'handlers': ['file'], 'level': 'INFO', 'propagate': True, }, 'myapphere': { 'handlers': ['file'], 'level': 'INFO', }, }, } ####---- End of Logging Config ----#### * Create logging directory and setup ownership/permissionsmkdir /var/log/myprojecthere chown :apache /var/log/myprojecthere chmod g+rwxs /var/log/myprojecthere ===== Admin Interface ===== * Create an admin userpython manage.py createsuperuser * Make your models/objects available for editing in the admin portal (/home/django/myprojecthere/myapphere/admin.py)# -*- coding: utf-8 -*- from __future__ import unicode_literals from django.contrib import admin # Register your models here. # Make Class Available in Admin Portal (see /home/django/myprojecthere/myapphere/models.py) from .models import AssetEntry admin.site.register(AssetEntry) ---- ===== URLs/Views ===== A URL+View will generate a web page. ==== URLs ==== **Project Level URLs File** * Edit project URLs (/home/django/myprojecthere/myprojecthere/urls.py) # add the "import include" part or you won't be able to refer to app level url files from django.conf.urls import url, include from django.contrib import admin # URL Regex Patterns - Map URIs to App's url file for additional matching urlpatterns = [ # No URI following site name (default app to use) url(r'^$', include('myapphere.urls')), # URI for app's name url(r'^myapphere/', include('myapphere.urls')), # Included /admin URI url(r'^admin/', admin.site.urls), ] \\ **App Level URLs File** * Create a new App level URLs file (/home/django/myprojecthere/myapphere/urls.py) **EXAMPLE**# urls.py - App URLs Map to App Views from django.conf.urls import url from . import views urlpatterns = [ # "/myapphere/" beginning is implied because we are in the "myapphere" urls file already # /myapphere/ - All Devices, All Environments (the index) url(r'^$', views.index, name='index'), # /myapphere/stats - All Devices, Statistics url(r'^stats/$', views.stats, name='stats'), # /myapphere/env_name - All Devices, Specific Environment url(r'^(?P(dev|test|prod))/$', views.env, name='env'), # /myapphere/device_type/ - Specific Device, All Environments url(r'^(?P(firewalls|routers|servers|storage|switches|workstations))/$', views.asset_type_all_env, name='asset_type_all_env'), # /myapphere/device_type/env_name - Specific Device, Specific Environment url(r'^(?P(firewalls|routers|servers|storage|switches|workstations))/(?P(dev|test|prod))/$', views.type_env, name='type_env'), # /myapphere/ - Physical or Virtual url(r'^(?P(physical|virtual))/$', views.asset_hardware, name='asset_hardware'), ] ==== Views ==== * Edit the App Views that are loaded depending upon URL match(/home/django/myprojecthere/myapphere/views.py) **EXAMPLE**# views.py - URLs are mapped to views # -*- coding: utf-8 -*- from __future__ import unicode_literals # Render http response+templates from django.shortcuts import render # Object or 404 from django.shortcuts import get_object_or_404 # HTTP Response from django.http import HttpResponse # Logging import logging logger = logging.getLogger(__name__) # Your Apps Model from .models import AssetEntry # /myapphere/ - All Devices, All Environments (the index) def index(request): # Get all asset objects all_asset_list = AssetEntry.objects.order_by('asset_type', 'asset_env', 'asset_name') # Get number of assets in list number_assets = len(all_asset_list) # Map template variable names (1st) to Python variables (2nd) for use in html templates context = { 'all_asset_list': all_asset_list, 'asset_count': number_assets } # Logging logger.info("Rendering index.html - All Devices, All Environments") # Render the http request, using the template, passing the context return render(request, 'myapphere/index.html', context) # /myapphere/stats - All Devices, Statistics def stats(request): # Get all asset objects all_asset_list = AssetEntry.objects.order_by('asset_type', 'asset_env', 'asset_name') # Get all asset device types asset_type_list = [key for key,value in AssetEntry.DEVICE_TYPES] # Get all os names, Linux only, Windows only os_list = [key for key,value in AssetEntry.OS_NAMES] os_list_linux = [key for key,value in AssetEntry.OS_NAMES_LINUX] os_list_windows = [key for key,value in AssetEntry.OS_NAMES_WINDOWS] # Log for debug purposes #for key in os_list: # logger.info("Field names are: " + key) #- Build Statistics -# # Initialize Stats list (will be a list of dictionaries) stats_list = [] ####---- Asset Counts Table: Grand Total Row ----#### sysstats_grand_total = 0 sysstats_grand_physical = 0 sysstats_grand_physical_linux = 0 sysstats_grand_physical_windows = 0 sysstats_grand_physical_other = 0 sysstats_grand_virtual = 0 sysstats_grand_virtual_linux = 0 sysstats_grand_virtual_windows = 0 sysstats_grand_virtual_other = 0 sysstats_grand_vmware = 0 # Calculate stats for each type of device for device_type in asset_type_list: # Initialize an empty device stats list device_stats = [] # Add node to the device_stats list if a node from the all_asset_list matches the current device type for node in all_asset_list: if ''.join(node.asset_type.lower().split()) == device_type.lower(): device_stats.append(node) ####---- Asset Counts Table ----#### # Total Count count_total = len(device_stats) #- Add to grand total sysstats_grand_total += count_total # Physical and Virtual Counts count_physical = 0 count_physical_linux = 0 count_physical_windows = 0 count_physical_other = 0 count_virtual = 0 count_virtual_linux = 0 count_virtual_windows = 0 count_virtual_other = 0 for node in device_stats: if node.asset_hardware == "Physical": count_physical += 1 if node.asset_os in os_list_linux: # Physical+Linux Count count_physical_linux += 1 elif node.asset_os in os_list_windows: # Physical+Windows Count count_physical_windows += 1 else: # Physical+Other OS count_physical_other += 1 elif node.asset_hardware == "Virtual": # Virtual Count count_virtual += 1 if node.asset_os in os_list_linux: # Virtual+Linux Count count_virtual_linux += 1 elif node.asset_os in os_list_windows: # Virtual+Windows Count count_virtual_windows += 1 else: # Virtual+Other OS count_virtual_other += 1 #- Add to grand total physical sysstats_grand_physical += count_physical sysstats_grand_physical_linux += count_physical_linux sysstats_grand_physical_windows += count_physical_windows sysstats_grand_physical_other += count_physical_other #- Add to grand total virtual sysstats_grand_virtual += count_virtual sysstats_grand_virtual_linux += count_virtual_linux sysstats_grand_virtual_windows += count_virtual_windows sysstats_grand_virtual_other += count_virtual_other ####---- OS Counts Table ----#### # Initialize a new empty OS Counts List os_counts = [] # Add all the os names and an initial count of 0 for name in os_list: os_counts.append({ 'os_name': name, 'count': 0 }) # Check each node in the devices specific stats for node in device_stats: # Compare node's OS against each os name in the os_counts list and increment count if a match is found for os_entry in os_counts: if os_entry['os_name'] == node.asset_os: # Increment count value on an os name match os_entry['count'] += 1 ####---- After All Stats Calculations: Add Device Stats to stats_list ----#### # Add device statistics to stats_list stats_list.append({ 'asset_type': device_type, 'total': count_total, 'physical': count_physical, 'physical_linux': count_physical_linux, 'physical_windows': count_physical_windows, 'physical_other': count_physical_other, 'virtual': count_virtual, 'virtual_linux': count_virtual_linux, 'virtual_windows': count_virtual_windows, 'virtual_other': count_virtual_other, 'os_count_stats': os_counts }) # Grand Total Only: VMware ESXi Host Count for node in device_stats: if node.asset_os.startswith("VMware"): sysstats_grand_vmware += 1 #-- END OF Calculate Device Type Stats loop --# ##-- Calculate OS stats grand totals --## # Initialize a new empty OS Counts Total List os_counts_total = [] # Add all the os names and an initial count of 0 for name in os_list: os_counts_total.append({ 'os_name': name, 'count': 0}) # For each device specific stats entry, add up grand total os counts for device_entry in stats_list: # For each device_entry in the stats_list, go through its os_count_stats value, which is a list of os_names and counts for os_device_entry in device_entry['os_count_stats']: # Check each os_count_stats os_name against the os_counts_total os_name list for os_entry_total in os_counts_total: # If we have an os_name match, add the device's os count to the total os count if os_entry_total['os_name'] == os_device_entry['os_name']: os_entry_total['count'] += os_device_entry['count'] ####---- Add grand totals to stats_list ----#### stats_list.append({ 'asset_type': 'Total', 'total': sysstats_grand_total, 'physical': sysstats_grand_physical, 'physical_linux': sysstats_grand_physical_linux, 'physical_windows': sysstats_grand_physical_windows, 'physical_other': sysstats_grand_physical_other, 'virtual': sysstats_grand_virtual, 'virtual_linux': sysstats_grand_virtual_linux, 'virtual_windows': sysstats_grand_virtual_windows, 'virtual_other': sysstats_grand_virtual_other, 'os_count_stats': os_counts_total }) #- Other Grand Totals: Calculate -# sysstats_grand_linux = sysstats_grand_physical_linux + sysstats_grand_virtual_linux sysstats_grand_windows = sysstats_grand_physical_windows + sysstats_grand_virtual_windows sysstats_grand_other = sysstats_grand_physical_other + sysstats_grand_virtual_other # Map template variable names (1st) to the Python variables (2nd) for use in templates context = {'device_stats': stats_list, 'total_linux': sysstats_grand_linux, 'total_windows': sysstats_grand_windows, 'total_other': sysstats_grand_other, 'total_vmware': sysstats_grand_vmware, 'os_list': os_list} # Logging logger.info("Rendering stats.html") # Render the HTTP request, using the template, passing the context return render(request, 'myapphere/stats.html', context) # /myapphere/env_name - All Devices, Specific Environment def env(request, env_name): # Get all asset objects all_asset_list = AssetEntry.objects.order_by('asset_type', 'asset_env', 'asset_name') # New List for the asset types in the passed environment only new_list = [] # Check each asset, add to new list if it matches the requested environment name for node in all_asset_list: if ''.join(node.asset_env.lower().split()) == env_name.lower(): new_list.append(node) # Get number of assets in list number_assets = len(new_list) # Map template variable names (1st) to Python variables (2nd) for use in html templates context = { 'all_asset_list': new_list, 'env': env_name, 'asset_count': number_assets } # Logging logger.info("Rendering index.html - All Devices, " + env_name) # Render the http request, using the template, passing the context return render(request, 'myapphere/index.html', context) # /myapphere/device/ - Specific Device, All Environments def asset_type_all_env(request, device_type): # Get all asset objects all_asset_list = AssetEntry.objects.order_by('asset_type', 'asset_env', 'asset_name') # New List for specific devices only new_list = [] # Check each asset, add to new list if it matches the requested device type for node in all_asset_list: if ''.join(node.asset_type.lower().split()) == device_type.lower(): new_list.append(node) # Get number of assets in list number_assets = len(new_list) # Map template variable names (1st) to Python variables (2nd) for use in html templates context = { 'all_asset_list': new_list, 'asset_type': device_type, 'asset_count': number_assets } # Logging logger.info("Rendering index.html - Devices: " + device_type + ", All Environments") # Render the http request, using the template, passing the context return render(request, 'myapphere/index.html', context) # /myapphere/device/env_name - Specific Device, Specific Environment def type_env(request, device_type, env_name): # Get all asset objects all_asset_list = AssetEntry.objects.order_by('asset_type', 'asset_env', 'asset_name') # New List for specific devices and environment only new_list = [] # Check each asset, add to new list if it matches the requested device and environment for node in all_asset_list: if ''.join(node.asset_type.lower().split()) == device_type.lower(): if ''.join(node.asset_env.lower().split()) == env_name.lower(): new_list.append(node) # Get number of assets in list number_assets = len(new_list) # Map template variable names (1st) to Python variables (2nd) for use in html templates context = { 'all_asset_list': new_list, 'asset_type': device_type, 'env': env_name, 'asset_count': number_assets } # Logging logger.info("Rendering index.html - Devices: " + device_type + ", Env: " + env_name) # Render the http request, using the template, passing the context return render(request, 'myapphere/index.html', context) # /myapphere// - Physical or Virtual def asset_hardware(request, asset_hardware): # Get all asset objects all_asset_list = AssetEntry.objects.order_by('asset_type', 'asset_env', 'asset_name') # New List for asset_hardware (physical or virtual) new_list = [] # Check each asset, add to new list if it matches the requested hardware type for node in all_asset_list: if ''.join(node.asset_hardware.lower().split()) == asset_hardware.lower(): new_list.append(node) # Get number of assets in list number_assets = len(new_list) # Map template variable names (1st) to the Python variables (2nd) for use in templates context = {'all_asset_list': new_list, 'asset_hardware': asset_hardware, 'asset_count': number_assets } # Logging logger.info("Rendering index.html - All Devices, " + asset_hardware) # Render the HTTP request, using the template, passing the context return render(request, 'myapphere/index.html', context) ---- ===== Web Page Templates ===== Creating the web page templates. * Create directory structuremkdir -p /home/django/myprojecthere/myapphere/templates/myapphere * Create new pages * templates/myapphere/index.html * templates/myapphere/stats.html ==== Page Content: Index ==== Example page content for the index.html page. /home/django/myprojecthere/myapphere/templates/myapphere/index.html Asset List {% load static %}
{% if user.is_authenticated %} Logged in: {{ user.username }}
Logout {% endif %}

{% if asset_type == 'firewalls' %} {% if env == 'dev' %} Asset List - Firewalls - Development Environment {% elif env == 'test' %} Asset List - Firewalls - Test Environment {% elif env == 'prod' %} Asset List - Firewalls - Production Environment {% else %} Asset List - Firewalls - All Environments {% endif %} {% elif asset_type == 'routers' %} {% if env == 'dev' %} Asset List - Routers - Development Environment {% elif env == 'test' %} Asset List - Routers - Test Environment {% elif env == 'prod' %} Asset List - Routers - Production Environment {% else %} Asset List - Routers - All Environments {% endif %} {% elif asset_type == 'servers' %} {% if env == 'dev' %} Asset List - Servers - Development Environment {% elif env == 'test' %} Asset List - Servers - Test Environment {% elif env == 'prod' %} Asset List - Servers - Production Environment {% else %} Asset List - Servers - All Environments {% endif %} {% elif asset_type == 'storage' %} {% if env == 'dev' %} Asset List - Storage - Development Environment {% elif env == 'test' %} Asset List - Storage - Test Environment {% elif env == 'prod' %} Asset List - Storage - Production Environment {% else %} Asset List - Storage - All Environments {% endif %} {% elif asset_type == 'switches' %} {% if env == 'dev' %} Asset List - Switches - Development Environment {% elif env == 'test' %} Asset List - Switches - Test Environment {% elif env == 'prod' %} Asset List - Switches - Production Environment {% else %} Asset List - Switches - All Environments {% endif %} {% elif asset_type == 'workstations' %} {% if env == 'dev' %} Asset List - Workstations - Development Environment {% elif env == 'test' %} Asset List - Workstations - Test Environment {% elif env == 'prod' %} Asset List - Workstations - Production Environment {% else %} Asset List - Workstations - All Environments {% endif %} {% else %} {% if env == 'dev' %} Asset List - All Types - Development Environment {% elif env == 'test' %} Asset List - All Types - Test Environment {% elif env == 'prod' %} Asset List - All Types - Production Environment {% else %} Asset List - All Types - All Environments {% endif %} {% endif %} {% if asset_hardware %} {% if asset_hardware == 'physical' %} - Physical - {% elif asset_hardware == 'virtual' %} - Virtual - {% endif %} {% endif %} {% if asset_count %} {% if asset_count == 1 %} ({{ asset_count }} asset) {% else %} ({{ asset_count }} assets) {% endif %} {% else %} (0 assets) {% endif %}
{% endfor %}
Device Type Name Description Environment OS Hardware
{{ name.asset_type }} {{ name.asset_name }} {{ name.asset_description }} {{ name.asset_env }} {{ name.asset_os }} {{ name.asset_hardware }}



==== Page Content: Stats ==== Example page content for the stats.html page. /home/django/myprojecthere/myapphere/templates/myapphere/stats.html Asset List - Stats {% load static %}
{% if user.is_authenticated %} Logged in: {{ user.username }}
Logout {% endif %}

Asset List - Statistics - Asset Counts
{% for asset in device_stats %} {% if asset.asset_type == 'Total' %} {% else %} {% endif %} {% endfor %}
Device Type Systems Physical Physical Linux Physical Windows Physical Other Virtual Virtual Linux Virtual Windows Virtual Other
{{ asset.asset_type }} {{ asset.total }} {{ asset.physical }} {{ asset.physical_linux }} {{ asset.physical_windows }} {{ asset.physical_other }} {{ asset.virtual }} {{ asset.virtual_linux }} {{ asset.virtual_windows }} {{ asset.virtual_other }}{{ asset.asset_type }} {{ asset.total }} {{ asset.physical }} {{ asset.physical_linux }} {{ asset.physical_windows }} {{ asset.physical_other }} {{ asset.virtual }} {{ asset.virtual_linux }} {{ asset.virtual_windows }} {{ asset.virtual_other }}
Total Linux {{ total_linux }}
Total Windows {{ total_windows }}
Total Other {{ total_other }}
Total VMware ESXi* {{ total_vmware }}
*Physical Virtual Hosts (VMware ESXi) count is included in Physical Linux/Total Linux counts.

Asset List - Statistics - OS Counts
{% for os_name in os_list %} {% endfor %} {% for asset in device_stats %} {% if asset.asset_type == 'Total' %} {% for name in asset.os_count_stats %} {% endfor %} {% else %} {% for name in asset.os_count_stats %} {% endfor %} {% endif %} {% endfor %}
Device Type{{ os_name }}
{{ asset.asset_type }}{{ name.count }}{{ asset.asset_type }}{{ name.count }}



---- ===== Static Files/Stylesheets ===== Configuring stylesheets. * Create directory structuremkdir -p /home/django/myprojecthere/myapphere/static/myapphere * Create stylesheet (/home/django/myprojecthere/myapphere/static/myapphere/style.css)/* style.css : Styles for html templates */ /* ---- Table Styles ---- */ /* table settings */ table.layout { border-collapse: collapse; border-spacing: 0px; padding: 0px; } td.layout { border-spacing: 0px; padding: 0px; } table.myapphere { border-collapse: collapse; } /* table headers, table definitions */ table.myapphere, th.myapphere, td.myapphere { border-collapse: collapse; border: 1px solid #ddd; padding: 5px; } /* th -> table headers */ th.myapphere { background-color: #4CAF50; color: white; } /* tr -> table rows * * tr:nth-child -> color every even table row * * tr:hover -> Mouse hover background color effect */ tr.myapphere:nth-child(even) {background-color: #f2f2f2;} tr.myapphere:hover {background-color: #ddd;} td.center { text-align: center; } td.totals { background-color: #b3b3b3; font-weight: bold; } /* ---- Menu Styles ---- */ ul.asset_type { list-style-type: none; margin: 0; padding: 0; overflow: hidden; background-color: #333; width: 671px; } ul.env { list-style-type: none; margin: 0; padding: 0; overflow: hidden; background-color: #333; width: 163px; } ul.stats { list-style-type: none; margin: 0; padding: 0; overflow: hidden; background-color: #333; width: 60px; } ul.asset_hardware { list-style-type: none; margin: 0; padding: 0; overflow: hidden; background-color: #333; width: 163px; } li { float: left; } li a { display: block; color: white; text-align: center; padding: 10px 10px; text-decoration: none; } a:hover:not(.active) { background-color: #111; } .active { background-color:#4CAF50; } /* ---- Non-Menu Styles ---- */ a:link.plain { background-color: #ffffff; } a:visited.plain { background-color: #ffffff; } a:hover.plain { background-color: #4caf50; } ---- ====== Apache ====== Configuring Apache to pass traffic to the application. * Configure Apache's mod_wsgi for the application (new file)vim /etc/httpd/conf.d/myapphere.conf # Asset List Django/WSGI Config # WSGIScriptAlias: The base URL to serve the application from WSGIScriptAlias / /home/django/myprojecthere/myprojecthere/wsgi.py # WSGI Daemon Process Config WSGIDaemonProcess myapphere python-path=/home/django/myprojecthere WSGIProcessGroup myapphere # Location of Django Application and wsgi.py config Require all granted # Static files (admin interface and style sheet) Alias /static/ /var/www/static/ Require all granted * Configure the virtual host (new file)vim /etc/httpd/conf.d/vhosts.conf # Virtual Host Config # Redirect shortname to fully qualified ServerName djangoserver Redirect "/" "http://djangoserver.mycorps.domain.org/" # Redirect all http to https ServerName djangoserver.mycorps.domain.org # Redirect all to https RewriteEngine On RewriteCond %{HTTPS} off RewriteRule (.*) https://%{HTTP_HOST}%{REQUEST_URI} # Redirect shortname to fully qualified ServerName djangoserver Redirect "/" "https://djangoserver.mycorps.domain.org/" # Django Application lives here at the root /. See: /etc/httpd/conf.d/myapphere.conf # Fully qualified server name ServerName djangoserver.mycorps.domain.org Header always set Strict-Transport-Security "max-age=63072000; includeSubdomains;" # OPTIONAL: CNAME for website - will only work with SSL if using a wildcard certificate ServerName myapphere.mycorps.domain.org Header always set Strict-Transport-Security "max-age=63072000; includeSubdomains;" * Configure SSL Certificatevim /etc/httpd/conf.d/ssl.conf SSLCertificateFile /etc/pki/tls/certs/current_crt.crt SSLCertificateKeyFile /etc/pki/tls/certs/current_key.key SSLCertificateChainFile /etc/pki/tls/certs/current_ca.crt * [[linux_wiki:ssl_certificates#create_request|Generate a self signed cert]] if this is just a lab environment. * Start and Enable Apachesystemctl start httpd systemctl enable httpd ---- ====== Django: Authentication ====== Adding authentication to Django requires basic auth to be setup first, as LDAP auth builds upon it. ===== Basic Authentication ===== Basic authentication uses Django local user accounts. * Edit Project Settings (/home/django/myprojecthere/myprojecthere/settings.py)# Redirect Successful Logins Here LOGIN_REDIRECT_URL = '/myapphere/' # Ensure contrib.auth is added to installed apps: # Application definition INSTALLED_APPS = [ 'myapphere.apps.MyapphereConfig', 'django.contrib.admin', 'django.contrib.auth', # must exist for basic auth to work ... ] * Add login and logout URLs to project URLs (/home/django/myprojecthere/myprojecthere/urls.py)# auth views - authentication login/logout module from django.contrib.auth import views as auth_views # URL Patterns - Map to Projects Within Django urlpatterns = [ ... # Login URLs url(r'^login/$', auth_views.login, {'template_name': 'login.html'}, name='login'), url(r'^logout/$', auth_views.logout, {'next_page': '/login/'}, name='logout'), ... ] * Edit the application views (/home/django/myprojecthere/myapphere/views.py)# Require login decorator from django.contrib.auth.decorators import login_required # Put login decorator before every function definition that you want to require login to view: #-> Require login for the view following it <-# @login_required(login_url="/login/") def index(request): * Create a HTML Login Page (/home/django/myprojecthere/myapphere/templates/login.html) {% block title %}Asset List{% endblock %}

Asset List

{% if user.is_authenticated %} Greetings, {{ user.username }}. logout {% endif %}

Login

{% csrf_token %} {{ form.as_p }}

===== LDAP Authentication ===== Configuring LDAP authentication. * Install the python django ldap packagepip install django-auth-ldap * Edit Project Settings (/home/django/myprojecthere/myprojecthere/settings.py) # LDAP Module Imports import ldap from django_auth_ldap.config import LDAPSearch from django_auth_ldap.config import GroupOfNamesType from django_auth_ldap.config import LDAPGroupQuery # Authentication Backends (LDAP and Django Local) AUTHENTICATION_BACKENDS = ( 'django_auth_ldap.backend.LDAPBackend', 'django.contrib.auth.backends.ModelBackend', ) ####- LDAP Server Config -#### AUTH_LDAP_SERVER_URI = "ldap://LDAPSERVER01.mycorps.domain.org ldap://LDAPSERVER02.mycorps.domain.org" AUTH_LDAP_START_TLS = True # Bind Info: Use authenticating user to get user and group info AUTH_LDAP_BIND_AS_AUTHENTICATING_USER = True AUTH_LDAP_USER_DN_TEMPLATE = "uid=%(user)s,cn=users,cn=accounts,dc=mycorps,dc=domain,dc=org" # Cache LDAP Groups for use with permissions AUTH_LDAP_CACHE_GROUPS = True AUTH_LDAP_GROUP_CACHE_TIMEOUT = 3600 # Group Info Gathering AUTH_LDAP_GROUP_SEARCH = LDAPSearch "cn=groups,cn=accounts,dc=mycorps,dc=domain,dc=org", ldap.SCOPE_SUBTREE, "(objectClass=groupofnames)" ) AUTH_LDAP_GROUP_TYPE = GroupOfNamesType() # Group restrictions - Who can login via LDAP AUTH_LDAP_REQUIRE_GROUP = ( # Allow login for members of the LDAP group "list_users" LDAPGroupQuery("cn=list_users,cn=groups,cn=accounts,dc=mycorps,dc=domain,dc=org") | # Allow login for members of the LDAP group "admin_group" LDAPGroupQuery("cn=admin_group,cn=groups,cn=accounts,dc=mycorps,dc=domain,dc=org") ) # Use LDAP group membership to calculate group permissions. AUTH_LDAP_FIND_GROUP_PERMS = True # Update Django record from LDAP each time user logs in AUTH_LDAP_ALWAYS_UPDATE_USER = True # Populate the Django user info from LDAP directory info AUTH_LDAP_USER_ATTR_MAP = { "first_name": "givenname", "last_name": "sn", "email": "mail" } # Set user permission flags by group - set LDAP group "admin_group" as Django Staff Members AUTH_LDAP_USER_FLAGS_BY_GROUP = { "is_staff": "cn=admin_group,cn=groups,cn=accounts,dc=mycorps,dc=domain,dc=org" } ---- ====== Django: Jquery ====== Jquery can be added in order to enable an Export as CSV and/or Excel buttons. Reference: Export Jquery Buttons: https://github.com/kayalshri/tableExport.jquery.plugin * From the reference link, download: * jquery.base64.js * tableExport.js * Search the internet for CSV and XLS icons. Download them. * CSV = save as "csv.png" * XLS = save as "xls.png" * Save the Javascript files and small pictures (CSV/XLS) into the same directory as the style sheet/home/django/myprojecthere/myapphere/static/myapphere/ * Install the Django Jquery integrationpip install django-jquery * Add Jquery to the "INSTALLED_APPS" list (/home/django/myprojecthere/myprojecthere/settings.py)# Application definition INSTALLED_APPS = [ 'jquery', * Add jquery to HTML templates ---- ====== Django: Static Files ====== No matter which steps from above you skip, you absolutely need to collect static files to copy them into the location Apache expects them to be. This is for Apache's access to javascript, css, etc. * Collect static filescd /home/django/myprojecthere/ python manage.py collectstatic ---- ====== DEBUG: TURN OFF ====== Lastly, when you are not developing/debugging your site, **turn off debug mode** to avoid dumping sensitive information to the screen in the event of an error. \\ Edit the project settings (/home/django/myprojecthere/myprojecthere/settings.py)# SECURITY WARNING: don't run with debug turned on in production! DEBUG = False ---- ====== Next Steps ======= [[python_wiki:django_api|Proceed to the Django API]] section. ----