Django-Mako-Plus Documentation

Similar documents
Building a Django Twilio Programmable Chat Application

Django urls Django Girls Tutorial

django-baton Documentation

django-scaffold Documentation

wagtailmenus Documentation

Quick.JS Documentation

django-baton Documentation

Client Side JavaScript and AJAX

wagtailmenus Documentation

MIT AITI Python Software Development Lab DJ1:

django-ad-code Documentation

Graphene Documentation

CSCU9B2 Practical 1: Introduction to HTML 5

Django File Picker Documentation

Quick housekeeping Last Two Homeworks Extra Credit for demoing project prototypes Reminder about Project Deadlines/specifics Class on April 12th Resul

django-session-security Documentation

Django Test Utils Documentation

wagtailtrans Documentation

Section 1. How to use Brackets to develop JavaScript applications

Unifer Documentation. Release V1.0. Matthew S

HTML/CSS Lesson Plans

django-sticky-uploads Documentation

nacelle Documentation

Djam Documentation. Release Participatory Culture Foundation

web.py Tutorial Tom Kelliher, CS 317 This tutorial is the tutorial from the web.py web site, with a few revisions for our local environment.

CSS BASICS. selector { property: value; }

webkitpony Documentation

AP CS P. Unit 2. Introduction to HTML and CSS

The Django Web Framework Part II. Hamid Zarrabi-Zadeh Web Programming Fall 2013

Using GitHub to Share with SparkFun a

Django. Jinja2. Aymeric Augustin DjangoCong 2016

Django-CSP Documentation

HTML5: Adding Style. Styling Differences. HTML5: Adding Style Nancy Gill

2. Write style rules for how you d like certain elements to look.

django-dajaxice Documentation

django-ratelimit-backend Documentation

EmberJS A Fitting Face for a D8 Backend. Taylor Solomon

Using Dreamweaver CC. Logo. 4 Creating a Template. Page Heading. Page content in this area. About Us Gallery Ordering Contact Us Links

Release Joris Beckers

About the Tutorial. Audience. Prerequisites. Copyright & Disclaimer. Laravel

yawrap Documentation Release Michal Kaczmarczyk

Web Development for Dinosaurs An Introduction to Modern Web Development

CIS192 Python Programming

django-xross Documentation

Django EL(Endless) Pagination Documentation

Django starting guide

These are notes for the third lecture; if statements and loops.

Week 8 Google Maps. This week you ll learn how to embed a Google Map into a web page and add custom markers with custom labels.

CISC-124. Casting. // this would fail because we can t assign a double value to an int // variable

Using Dreamweaver CS6

Django PAM Documentation

One of the fundamental kinds of websites that SharePoint 2010 allows

ASP.NET MVC Training

In fact, as your program grows, you might imagine it organized by class and superclass, creating a kind of giant tree structure. At the base is the

Django File Picker Documentation

MapEntity Documentation

Django Standalone Apps

Episode 298. Getting Started With Spree

Lab 1 - Introduction to Angular

ThingLink User Guide. Andy Chen Eric Ouyang Giovanni Tenorio Ashton Yon

Developing ASP.NET MVC 4 Web Applications

Django_template3d Documentation

Using Development Tools to Examine Webpages

We are assuming you have node installed!

XP: Backup Your Important Files for Safety

SASS Variables and Mixins Written by Margaret Rodgers. Variables. Contents. From Web Team. 1 Variables

Rapid Development with Django and App Engine. Guido van Rossum May 28, 2008

CMSC 201 Fall 2016 Lab 09 Advanced Debugging

CID Documentation. Release Francis Reyes

wagtail-robots Documentation

JavaScript Fundamentals_

Before you begin, make sure you have the images for these exercises saved in the location where you intend to create the Nuklear Family Website.

Human-Computer Interaction Design

LECTURE 14. Web Frameworks

Table Basics. The structure of an table

Techniques for Optimizing Reusable Content in LibGuides

What is version control? (discuss) Who has used version control? Favorite VCS? Uses of version control (read)

Without further ado, let s go over and have a look at what I ve come up with.

We re working full time this summer alongside 3 UCOSP (project course) students (2 from Waterloo: Mark Rada & Su Zhang, 1 from UofT: Angelo Maralit)

AngularJS Fundamentals

Design Document V2 ThingLink Startup

Unveiling the Basics of CSS and how it relates to the DataFlex Web Framework

Course 20486B: Developing ASP.NET MVC 4 Web Applications

django-embed-video Documentation

ganetimgr Documentation

Ruby on Rails Welcome. Using the exercise files

Intro. Scheme Basics. scm> 5 5. scm>

Web API Lab. The next two deliverables you shall write yourself.

kaleo Documentation Release 1.5 Eldarion

Django QR Code Documentation

Data Visualization on the Web with D3

Django Dynamic Fields Documentation

Creating a CSS driven menu system Part 1

ORB Education Quality Teaching Resources

Webpack. What is Webpack? APPENDIX A. n n n

learn programming the right way

Building a Python Flask Website A beginner-friendly guide

BF Survey Pro User Guide

django-contact-form Documentation

Django: Views, Templates, and Sessions

Transcription:

Django-Mako-Plus Documentation Release 4.1 Conan C. Albrecht Feb 14, 2018

Contents 1 Code 3 2 Features 5 3 Quick Start 7 4 Contents 9 4.1 About DMP............................................... 9 4.2 Upgrade Notes.............................................. 12 4.3 Installation................................................ 14 4.4 Tutorial.................................................. 20 4.5 Topics................................................... 35 5 Compatability 75 i

ii

Show Me the Code: 1. Django Syntax vs. DMP Syntax 2. Simple Template 3. Basic View (.py file) 4. Ajax Example Routing Django to Mako since 2013 Contents 1

2 Contents

CHAPTER 1 Code https://github.com/doconix/django-mako-plus 3

4 Chapter 1. Code

CHAPTER 2 Features DMP adds convention-over-configuration to Django: Uses standard Python in templates; no more weak-sauce Django templating. Calls any view function by convention instead of listing every. single. page. in urls.py. Converts parameters in the URL and loads model objects by convention. Automatically links.js and.css in your HTML documents by convention. Automatically sets context variables in the Javascript namespace. Provides Django-style signals. Extends Django s redirecting with exception-based redirecting. Supports language translations, class-based views, and collection of static files. Includes a comprehensive test suite. DMP doesn t replace Django; the standard router and template engine can be used alongside it. 5

6 Chapter 2. Features

CHAPTER 3 Quick Start # install django, mako, and DMP pip3 install django-mako-plus # create a new project with a 'homepage' app python3 -m django startproject --template=http://cdn.rawgit.com/doconix/django-mako- plus/master/project_template.zip mysite cd mysite python3 manage.py startapp --template=http://cdn.rawgit.com/doconix/django-mako-plus/ master/app_template.zip --extension=py,htm,html homepage # open mysite/settings.py and append 'homepage' to the INSTALLED_APPS list INSTALLED_APPS = [... 'homepage', ] # run initial migrations and run the server python3 manage.py migrate python3 manage.py runserver # Open a browser to http://localhost:8000/ Note that on Windows, python3 is python and pip3 is pip. Python 3+ is required. 7

8 Chapter 3. Quick Start

CHAPTER 4 Contents 4.1 About DMP Contents About DMP Frequently Asked Questions * Where Is DMP Used? * What s wrong with Django s built-in template language? * Why Mako instead Django or Jinja2? * Can I use DMP with regular Django apps? Comparison with Django Django-Mako-Plus makes creating web sites faster through convention-over-configuration in the Django framework. It integrates the Mako templating engine, which looks much more like Python than the standard templating language. Yet it still conforms to the Django API and plugs in as a standard engine. DMP boasts the following advantages: 1. It uses the Mako templating engine rather than the weaker Django templating engine. Why would I want to learn a whole new language for templating when Mako uses my favorite language: Python? 2. It enables calling views and html pages by convention rather than specific entries in urls.py. Any.html file on your site can be called without new entries in urls.py for every. single. new. page. Doesn t Python favor convention over configuration? 3. DMP introduces the idea of URL parameters with automatic type conversion. These allow you to embed parameters in urls, Django style meaning you can use pretty URLs like http://myserver.com/abc/def/123/ without explicit entries in urls.py and without the need for traditional (i.e. ulgy)?first=abc&second=def&third=123 syntax. 9

4. It includes CSS and JS files with the same name as the current template automatically. This means that mypage.css and mypage.js get linked in mypage.html automatically. Plus, DMP allows sending context values from your Python view code right into your Javascript namespace, without any significant hacks. 5. DMP can compile your preprocessor files, such as.scss,.less, or even Transcrypt.py. 4.1.1 Frequently Asked Questions Where Is DMP Used? This app was developed at MyEducator.com, primarily by Dr. Conan C. Albrecht. Please email me if you find errors with this tutorial or have suggestions/fixes. In addition to several production web sites, I use the framework in my Django classes at BYU. 120+ students use the framework each year, and many have taken it to their companies upon graduation. At this point, the framework is quite mature and robust. It is fast and stable. I ve been told by some that DMP has a lot in common with Rails. When I developed DMP, I had never used RoR, but good ideas are good ideas wherever they are found, right? :) What s wrong with Django s built-in template language? Django comes with its own template system, but it s fairly weak (by design). Mako, on the other hand, is a fantastic template system that allows full Python code within HTML pages. The primary reason Django doesn t allow full Python in its templates is the designers want to encourage you and I to keep template logic simple. I fully agree with this philosophy. I just don t agree with the forced part of this philosophy. The Python way is rather to give freedom to the developer but train in the correct way of doing things. Even though I fully like Python in my templates, I still keep them fairly simple. Views are where your logic goes. Why Mako instead Django or Jinja2? Python has several mature, excellent templating languages. Both Django and Jinja2 are fairly recent yet mature systems. Both are screaming fast. Mako itself is very stable, both in terms of lack of bugs and in completed feature set. Today, the Mako API almost never changes because it does exactly what it needs to do and does it well. This make it an excellent candidate for server use. The short answer is I liked Mako s approach the best. It felt the most Pythonic to me. Jinja2 may feel more like Django s built-in template system, but Mako won out because it looked more like Python and the point of DMP is to include Python in templates. Can I use DMP with regular Django apps? Yes. DMP plugs in as a regular templating engine per the standard Django API. You can use both DMP and regular Django simultaneously in the same project. When you include DMP s urls.py module in your project, patterns for each DMP-enabled app in your project are linked to our convention-based router. Other apps won t match these patterns, so other apps route the normal Django way. This means third-party apps work just fine with DMP. Note also that other apps likely use Django s built-in templating system rather than DMP s Mako templating system. The two templating systems work fine side by side, so other apps should render fine the normal Django way and your custom apps will render fine with Mako. 10 Chapter 4. Contents

Further, if you temporarily need to switch to Django templating syntax, you can do that with ease. This allows the use of Django-style tags and syntax right within your Mako code. No new files needed. 4.1.2 Comparison with Django If you have read through the Django Tutorial, you ve seen examples for templating in Django. While the rest of Django, such as models, settings, migrations, etc., is the same with or without DMP, the way you do templates will obviously change with DMP. The following examples should help you understand the different between two template systems. Note that, for the most part, the right column uses standard Python syntax. That s why Mako rocks. Django Output the value of the question variable: DMP (Mako) {{ question }} ${ question } Call a method on the User object: {{ user.get_full_name }} ${ user.get_full_name() } Call a method with parameters on the User object: Requires a custom tag. ${ user.has_perm( app.get_main_view ) } Iterate through a relationship: <ul> {% for choice in question.choice_set.all %} <li>{{ choice.choice_text }}</li> {% endfor %} </ul> <ul> %for choice in question.choice_set.all(): <li>${ choice.choice_text }</li> %endfor </ul> Set a variable: {% with name= Sam %} <% name = Sam %> Format a date: {{ value date: D d M Y }} ${ value.strftime( %D %d %M %Y ) } Join a list: {{ mylist join:, }} ${,.join(mylist) } Use the /static prefix: {% load static %} <img src= {% get_static_prefix %}images/hi.jpg /> Call a Python method: <img src= ${ STATIC_ROOT }images/hi.jpg /> Continued on next page 4.1. About DMP 11

Table 4.1 continued from previous page Django DMP (Mako) Requires a custom tag, unless a built-in tag provides the Any Python method can be called: <%! import random behavior. %> ${ random.randint(1, 10) } Print a Django form: <form action= /your-name/ method= post > {% csrf_token %} {{ form }} <input type= submit value= Submit /> </form> Output a default if empty: {{ value default: nothing }} Run arbitrary Python (keep it simple, Tex!): <form action= /your-name/ method= post > ${ csrf_input } ${ form } <input type= submit value= Submit /> </form> Use a boolean: ${ value or nothing } or use a Python if statement: ${ value if value is not None else nothing } Requires a custom tag Inherit another template: <% %> i = 1 while i < 10: context.write( <p>testing {0}</p>.format(i)) i += 1 {% extends base.html %} <%inherit file= base.htm /> Override a block: {% block title %}My amazing blog{% endblock %} <%block name= title >My amazing blog</%block> Link to a CSS file: Place in template: <link rel= stylesheet type= text/css href=... > Perform per-request logic in JS files: Difficult, young padwan... very difficult. Simply name the.css/.js file the same name as your.html template. DMP will include the link automatically. Wrap context keys with jscontext(), and DMP will make the variable available in your JS file. 4.2 Upgrade Notes This document contains upgrade notes for those already using DMP. We started the document at version 4.3. 5.0.1 - February, 2018 Most changes can be summarized in the DMP settings.py options. We recommend comparing your settings.py file against the current template (see file project_template/project_name/settings.py-tpl on GitHub). This will likely signal 12 Chapter 4. Contents

all the changes you may need to make. 1. The biggest change is the variables DMP attaches to the request have been moved to an object, available as request.dmp. This causes less namespace pollution of the request and allows easier changes going forward. The following are the old to new adjustments you may need. We recommend moving from urlparams to automatic view parameter conversion, although this is likely a significant change (there are no plans to remove urlparams, so this isn t required). Old New (DMP 4.4) request.dmp_router_app request.dmp.app request.dmp_router_page request.dmp.page request.dmp_router_function request.dmp.function request.dmp_router_module request.dmp.module request.dmp_router_class request.dmp.class_obj request._dmp_router_callable request.dmp.function_obj request.urlparams request.dmp.urlparams request.dmp_render request.dmp.render request.dmp_render_to_string request.dmp.render_to_string Important: As noted in the table above, search your codebase for request.dmp_render and replace with request.dmp.render. 2. Static files (CSS/JS): MakoCssProvider, MakoJsProvider, link_css, link_js, link_template_css, link_template_js are removed. Instad, use ${ django_mako_plus.links() } once in the <head> section of your base page. 3. RedirectException: Optional parameters permanent and as_javascript are removed. Use the subclasses by these names instead. 4. SCSS Compiling: The entire sass.py file is removed, including functions check_template_scss, compile_scss_file, compile_scssm_file. Instead, use the Sass compile provider. See providers for more information. 5. The parameter keys in urls.py has changed. You only need to adjust your urls.py if you have custom patterns. For those doing it the normal way (including DMP s urls.py), no change is necessary. Old New (DMP 4.4) dmp_router_app dmp_app dmp_router_page dmp_page dmp_router_function dmp_function urlparams dmp_urlparams 6. Rendering: render_to_string_shortcut_deprecated and render_to_response_shortcut_deprecated are removed, but this shouldn t affect anyone because they are internal function. 4.2.1 4.3.1 - November, 2017 tl;dr for existing projects: 1. Add dmp-common.js to your site s base template (add above any DMP calls). 2. Search for django_mako_plus.link_css and change to django_mako_plus.links. 3. Search for django_mako_plus.link_js and simply remove. 4. Search for django_mako_plus.link_template_css and change to django_mako_plus. template_links. 5. Search for django_mako_plus.link_template_js and remove. 4.2. Upgrade Notes 13

6. (optional) Change deprecated.cssm files to.css and.jsm files to.js. This one may take some work. Be sure to read the docs on what needs to be done. We added provider classes, which creates a customizable system for linking static files. Default settings for the providers will handle everything for you, but note that you can add CONTENT_PROVIDERS to your settings file to customize how links are created in templates. DMP now requires inclusion of dmp-common.js in your base template(s). This is included in the base template of new projects, but existing projects need to link to the file. See the installation guide for more info. link_css and link_js functions are deprecated but still work for now. Your base template should now have a single call to django_mako_plus.links(self) in the <head> section. To switch over, simply replace link_css with links and delete the reference to link_js. Both style and script links are returned by the new function because best practices no longer recommend placing scripts at the end of your page (async/defer in modern browsers make it unnecessary). In similar fashion, link_template_css and link_template_js is now one call to template_links. *.cssm files are deprecated but still work for now. Few users seemed to use this. If you are using them, move the dynamic parts to your templates and convert to a normal css file. *.jsm files are deprecated but still work for now. These were of great use to many, but jscontext gives a new, improved way to do dynamic JS. Convert all.jsm files to regular.js files, and follow the pattern given in the tutorial. The new method still allows you to easily send variables to your JS but doesn t need any rendering. You ll need to convert code in your JS from if (${ somebool }) to if (context.somebool). Note that the Mako codes are gone, and the new code is pure JS that uses a context dictionary that exists in the JS namespace. Compilation of Scss has been moved to a provider class, and a new provider for Less is now available. In fact, the CompileProvider can compile any type of file (using the settings in CONTENT_PROVIDERS). Check out the Transcrypt example in the topic on CSS and JS. 4.3 Installation The easiest way to install DMP is by creating a new project. This section shows how to install DMP with a new project as well as an existing project. What kind of project do you have? Contents Installation New Project * Install Django, Mako, and DMP * Create a Django project * Create a DMP-Style App * Load it Up! Existing Project * Install Django, Mako, and DMP * Create a DMP-Style App * Load it Up! 14 Chapter 4. Contents

* Not a designated DMP app? Subdirectory: /mysite/ 4.3.1 New Project Install Python and ensure you can run python3 (or python) at the command prompt. The framework requires Python 3.4+. Install Django, Mako, and DMP DMP 3 works with Django 1.9+ and Mako 1.0+. It will support Django 2.0 when it is released. Install with the python installer: pip3 install django-mako-plus Note that on Windows machines, pip3 may need to be replaced with pip: pip install django-mako-plus Create a Django project Create a Django project, and specify that you want a DMP-style project layout: python3 -m django startproject --template=http://cdn.rawgit.com/doconix/django-mako- plus/master/project_template.zip mysite In addition to giving you the DMP project directories, this command automatically adds the required pieces to your settings.py and urls.py files. You can, of course, name your project anything you want, but in the sections below, I ll assume you called your project mysite. Don t forget to migrate to synchronize your database and create a superuser: cd mysite python3 manage.py migrate python3 manage.py createsuperuser Create a DMP-Style App Change to your project directory in the terminal/console, then create a new Django-Mako-Plus app with the following: python3 manage.py startapp --template=http://cdn.rawgit.com/doconix/django-mako-plus/ master/app_template.zip --extension=py,htm,html homepage After the new homepage app is created, add your new app to the INSTALLED_APPS list in settings.py: INSTALLED_APPS = [... 'homepage', ] 4.3. Installation 15

Congratulations. You re ready to go! Load it Up! Start your web server with the following: python3 manage.py runserver If you get a message about unapplied migrations, ignore it for now and continue. Open your web browser to http://localhost:8000/. You should see a message welcoming you to the homepage app. If everything is working, skip ahead to the tutorial. 4.3.2 Existing Project Install Python and ensure you can run python3 (or python) at the command prompt. The framework requires Python 3.4+. Install Django, Mako, and DMP DMP 3 works with Django 1.9+ and Mako 1.0+. It will support Django 2.0 when it is released. Install with the python installer: pip3 install django-mako-plus Note that on Windows machines, pip3 may need to be replaced with pip: pip install django-mako-plus If you need to add DMP to an existing Django project, you have two options: 1. Convert your project to the DMP structure. This switches your project over to the layout of a DMP-style project. 2. Keep your existing Django-style structure with minimal changes. This section describes Option 1, which gives you the full benefit of the automatic DMP router and midleware. If you need Option 2, jump to Rending Templates the Standard Way: render() <#rending-templates-the-standard-wayrender>. Edit Your settings.py File: Add django_mako_plus to the end of your INSTALLED_APPS list: INSTALLED_APPS = [... 'django_mako_plus', ] Add django_mako_plus.requestinitmiddleware to your MIDDLEWARE list: 16 Chapter 4. Contents

MIDDLEWARE = [... 'django_mako_plus.requestinitmiddleware',... ] Add a logger to help you debug (optional but highly recommended!): DEBUG_PROPAGATE_EXCEPTIONS = DEBUG # SECURITY WARNING: never set this True on a live site LOGGING = { 'version': 1, 'disable_existing_loggers': False, 'formatters': { 'dmp_simple': { 'format': '%(levelname)s::dmp %(message)s' }, }, 'handlers': { 'dmp_console':{ 'level':'debug', 'class':'logging.streamhandler', 'formatter': 'dmp_simple' }, }, 'loggers': { 'django_mako_plus': { 'handlers': ['dmp_console'], 'level': 'DEBUG', 'propagate': False, }, }, } Add the Django-Mako-Plus engine to the TEMPLATES list. Note that a standard Django project already has the TEMPLATES = line. TEMPLATES = [ { 'NAME': 'django_mako_plus', 'BACKEND': 'django_mako_plus.makotemplates', 'OPTIONS': { # functions to automatically add variables to the params/context before templates are rendered 'CONTEXT_PROCESSORS': [ 'django.template.context_processors.static', # adds "STATIC_URL" from settings.py 'django.template.context_processors.debug', # adds debug and sql_queries 'django.template.context_processors.request', # adds "request" object 'django.contrib.auth.context_processors.auth', # adds "user" and "perms" objects 'django.contrib.messages.context_processors.messages', # adds messages from the messages framework "settings" dictionary ], 'django_mako_plus.context_processors.settings', # adds 4.3. Installation 17

# identifies where the Mako template cache will be stored, relative to each template directory 'TEMPLATES_CACHE_DIR': '.cached_templates', # the default app and page to render in Mako when the url is too short # if None (no default app), DMP will not capture short URLs 'DEFAULT_APP': 'homepage', 'DEFAULT_PAGE': 'index', # the default encoding of template files 'DEFAULT_TEMPLATE_ENCODING': 'utf-8', # imports for every template 'DEFAULT_TEMPLATE_IMPORTS': [ # import DMP (required) 'import django_mako_plus', # uncomment this next line to enable alternative syntax blocks within your Mako templates # 'from django_mako_plus import django_syntax, jinja2_syntax, alternate_syntax templates ], # the next two lines are just examples of including common imports in # 'from datetime import datetime', # 'import os, os.path, re, json', # whether to send the custom DMP signals -- set to False for a slight speed-up in router processing # determines whether DMP will send its custom signals during the process 'SIGNALS': False, ] }, }, # see the DMP online tutorial for information about this setting # it can normally be empty 'TEMPLATES_DIRS': [ # '/var/somewhere/templates/', ], Add the following to serve your static files. Note that a standard Django project already has the first STATIC_URL = line. STATIC_URL = '/static/' # you probably already have this STATICFILES_DIRS = ( # SECURITY WARNING: this next line must be commented out at deployment BASE_DIR, ) STATIC_ROOT = os.path.join(base_dir, 'static') Clean out all the cached template files. This should be done anytime you make a DMP change in settings.py: python manage.py dmp_cleanup 18 Chapter 4. Contents

Enable the Django-Mako-Plus Router Add the Django-Mako-Plus router in your urls.py file (the default admin is also included here for completeness). from django.conf.urls import url, include urlpatterns = [ # urls for any third-party apps go here ] # adds all DMP-enabled apps url('', include('django_mako_plus.urls')), Create a DMP-Style App Change to your project directory in the terminal/console, then create a new Django-Mako-Plus app with the following: python3 manage.py startapp --template=http://cdn.rawgit.com/doconix/django-mako-plus/ master/app_template.zip --extension=py,htm,html homepage After the new homepage app is created, add your new app to the INSTALLED_APPS list in settings.py: INSTALLED_APPS = [... 'homepage', ] Congratulations. You re ready to go! Load it Up! Start your web server with the following: python3 manage.py runserver If you get a message about unapplied migrations, ignore it for now and continue. Open your web browser to http://localhost:8000/. You should see a message welcoming you to the homepage app. If everything is working, skip ahead to the tutorial. Not a designated DMP app? If DMP tells you that an app you re trying to access is not a designated DMP app, you missed something above. Rather than go above and trying again, go on to the next section on converting existing apps for a summary of everything needed to make a valid DMP app. You re likely missing something in this list, and by going through this next section, you ll ensure all the needed pieces are in place. I ll bet you didn t set the DJANGO_MAKO_PLUS = True part in your app s init file. Another possible reason is you didn t list homepage as one of your INSTALLED_APPS as described above. 4.3. Installation 19

4.3.3 Subdirectory: /mysite/ This section is for those that need Django is a subdirectory, such as /mysite. If your Django installation is at the root of your domain, skip this section. In other words, suppose your Django site isn t the only thing on your server. Instead of the normal url pattern, http:/ /www.yourdomain.com/, your Django installation is at http://www.yourdomain.com/mysite/. All apps are contained within this mysite/ directory. This is accomplished in the normal Django way. Adjust your urls.py file to include the prefix: url('^mysite/', include('django_mako_plus.urls')), 4.4 Tutorial These five tutorial pages are the best way to learn about DMP. Assuming you have gone through the installation instructions, this is your jumping off point. 4.4.1 T1: Meet DMP Contents T1: Meet DMP For the Impatient Your New App Goodbye, urls.py I ll assume you ve just installed Django-Mako-Plus according to the installation instructions. You should have a dmp_test project directory that contains a homepage app. I ll further assume you know how to open a terminal/console and cd to the dmp_test directory. Most of the commands below are typed into the terminal in this directory. Quick Start: You already have a default page in the new app, so fire up your server with python3 manage.py runserver and go to http://localhost:8000/homepage/index/. You should see a congratulations page. If you don t, go back to the installation section and walk through the steps again. Your console might have valuable error messages to help troubleshoot things. For the Impatient If you are an experienced web developer and just want to get going, check out the example files in your new app: homepage/template/base.htm homepage/template/index.htm homepage/styles/index.css homepage/scripts/index.js These files contain example code that follows the primary patterns of DMP. 20 Chapter 4. Contents

Your New App Let s explore the directory structure of your new app: homepage/ media/ scripts/ index.js styles/ base.css index.css templates/ base_ajax.htm base.htm index.html views/ init.py init.py apps.py models.py tests.py The directories should be fairly self-explanatory. Note they are different than a traditional Django app structure. In short, put images and other support files in media/, Javascript in scripts/, CSS in styles/, html files in templates/, and Django views in views/. Note that a common pattern among Django developers is converting several files to directories: models. py to models/ and tests.py to tests/, but that s a discussion outside of DMP. The following setting is automatically done when you created your app, but if you created your app structure manually, DMP-enabled apps must have the following in the appname/ init.py file: DJANGO_MAKO_PLUS = True Let s start with the two primary html template files: base.htm and index.html. index.html is pretty simple: <%inherit file="base.htm" /> <%block name="content"> <div class="content"> <h3>congratulations -- you've successfully created a new django-mako-plus app!</ h3> <h4>next Up: Go through the django-mako-plus tutorial and add Javascript, CSS, and urlparams to this page.</h4> <h4 class="utc-time">current time in UTC: ${ utc_time }</h4> </div> </%block> If you are familiar with Django templates, you ll recognize the template inheritance in the <%inherit/> tag. However, this is Mako code, not Django code, so the syntax is a little different. The file defines a single block, called content, that is plugged into the block by the same name in the code below. The real HTML is kept in the base.htm file. It looks like this: ## this is the skeleton of all pages on in this app - it defines the basic html tags <!DOCTYPE html> <html> 4.4. Tutorial 21

<meta charset="utf-8"> <head> <title>homepage</title> ## add any site-wide scripts or CSS here; for example, jquery: <script src="http://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"> </script> </head> <body> </body> </html> ## render the static file links with the same name as this template <script src="/django_mako_plus/dmp-common.min.js"></script> ${ django_mako_plus.links(self) } <header> <h1>welcome to the homepage app!<h1> </header> <main> <%block name="content"> Site content goes here in sub-templates. </%block> </main> Pay special attention to the <%block name="content"> section, which is overridden in index.html. The page given to the browser will look exactly like base.htm, but the content block will come from index.html rather than the one defined in the supertemplate. The purpose of the inheritance from base.htm is to get a consistent look, menu, etc. across all pages of your site. When you create additional pages, simply override the content block, similar to the way index.html does it. Don t erase anything in the base.htm file. In particular, django_mako_plus.links() and the dmp-common.min.js script are important. As much as you probably want to clean up the mess, try your best to leave these alone. Undefined object has no attribute get_static : If you get this error, you might need to update a setting in settings.py. Ensure that DMP is imported in the DEFAULT_TEMPLATE_IMPORTS list: 'DEFAULT_TEMPLATE_IMPORTS': [ 'import django_mako_plus', ] Then clear out the compiled templates caches: python manage.py dmp_cleanup DMP_CONTEXT is not defined If you get this error, the /django_mako_plus/dmp-common.min.js script is not being loaded. Check the following: Is the <script> tag for this file in your base.htm? If there, did it get moved below the links() call? This 22 Chapter 4. Contents

script must be loaded on every page of your site (i.e. in the base template), and it must be loaded before DMP calls are made. Is the url pattern for this file working? Check your urls.py file for include('django_mako_plus. urls'). The DMP urls.py file contains a direct pattern for this file that allows Django to find it. Goodbye, urls.py In the installation procedures above, you set your urls.py file to look something like the following: from django.conf.urls import url, include from django.contrib import admin urlpatterns = [ # the built-in Django administrator url(r'^admin/', admin.site.urls), # urls for any third-party apps go here ] # adds all DMP-enabled apps url('', include('django_mako_plus.urls')), Rather than listing every. single. page. on. your. site. in the urls.py file, the router figures out the destination via a convention. The first url part is taken as the app to go to, and the second url part is taken as the view to call. See the advanced topics if you want to customize this behavior. For example, the url /homepage/index/ routes as follows: The first url part homepage specifies the app that will be used. The second url part index specifies the view or html page within the app. In our example: The router first looks for homepage/views/index.py. In this case, it fails because we haven t created it yet. It then looks for homepage/templates/index.html. It finds the file, so it renders the html through the Mako templating engine and returns it to the browser. The above illustrates the easiest way to show pages: simply place.html files in your templates/ directory. This is useful for pages that don t have any work to do. Examples might be the About Us and Terms of Service pages. There s usually no functionality or permissions issues with these pages, so no view function is required. You might be wondering about default URLs, such as http://www.yourserver.com/. When the url doesn t contain the app and the page, DMP uses the default app and page specified in your settings. Read more on this at Default App and Page. 4.4.2 T2:.py View Files Contents T2:.py View Files The Render Functions But That s Not Django! 4.4. Tutorial 23

Further Reading Let s add some work to the process by adding the current server time to the index page. Empty out homepage/ views/index.py and copy this code into it: from django.conf import settings from django_mako_plus import view_function from datetime import datetime @view_function def process_request(request): context = { 'now': datetime.now(), } return request.dmp.render('index.html', context) Reload your server and browser page, and you should see the exact same page. It might look the same, but something very important happened in the routing. Rather than going straight to the index.html page, processing went to your new index.py file. At the end of the process_request function above, we manually render the index.html file. In other words, we re now doing extra work before the rendering. This is the place to do database connections, modify objects, prepare and handle forms, etc. It keeps complex code out of your html pages. Let me pause for a minute and talk about log messages. If you enabled the logger in the installation, you should see the following in your console: DEBUG::DMP variables set by urls.py: ['dmp_app', 'dmp_page', 'urlparams']; variables set by defaults: ['dmp_function']. INFO::DMP processing: app=homepage, page=index, module=homepage.views.index, func=process_request, urlparams=[''] INFO::DMP calling view function homepage.views.index.process_request DEBUG::DMP rendering template /Users/conan/Documents/data/teaching/2017/IS 411-413/ fomoproject/homepage/templates/index.html These debug statements are incredibly helpful in figuring out why pages aren t routing right. If your page didn t load right, you ll probably see why in these statements. In my log above, the first line lists what named parameters were matched in urls.py. The second line shows the how these named (or defaulted) parameters translated into the app, page, module, and function. The third line shows the controller found the index.py view, and it called the process_request function successfully. This is important the process_request function is the default view function. This web-accessible function must be decorated with @view_function. This decoration with @view_function is done for security. If the framework were to allow browsers specify any old function, end users could invoke any function of any module on your system! By requiring the decorator, the framework limits end users to one specifically-named function. You can have multiple decorators on your function, such as a permissions check and view_function. The order isn t important unless the other decorators don t wrap the function correctly. If @view_function is listed first, you won t have to worry. @view_function @permission_required('can_vote') def process_request(request):... 24 Chapter 4. Contents

Later in the tutorial, we ll describe another way to call other functions within your view Even though process_request is the default function, you can actually have multiple web-accessible functions within a single.py file. As stated earlier, we explicitly call the Mako renderer at the end of the process_request function. The context (the third parameter of the call) is a dictionary containing variables to be passed to the template. Let s use the now variable in our index.html template: <%inherit file="base.htm" /> <%block name="content"> <div class="content"> <h3>congratulations -- you've successfully created a new django-mako-plus app!</ h3> <h4>next Up: Go through the django-mako-plus tutorial and add Javascript, CSS, and urlparams to this page.</h4> <p class="server-time">the current server time is ${ now }.</p> <p class="browser-time">the current browser time is...</p> </div> </%block> The ${ varname } code is Mako syntax and is described more fully on the Mako web site. Right now, it s most important that you see how to send data from the view to the template. If you already know Django templates, it should be familiar. Reload your web page and ensure the new view is working correctly. You should see the server time printed on the screen. Each time you reload the page, the time changes. The Render Functions This section explains the two render functions included with DMP. If you just want to get things working, skip over this section. You can always come back later for an explanation of how things are put together. In the example above, we used the dmp_render function to render our template. It s the DMP equivalent of Django s render shortcut function. The primary difference between the two functions (other than, obviously, the names) is DMP s function is coupled to the current app. In contrast, Django searches for templates in a flat list of directories while your apps might have templates in them, Django just searches through them in order. DMP s structure is logically app-based: each of your apps contains a templates directory, and DMP always searches the current app directly. With DMP, there are no worries about template name clashes or finding issues. At the beginning of each request, DMP s middleware determines the current app (i.e. the first item in the url) and adds two render functions to the request object. These are available throughout your request, with no imports needed. As long as you are rendering a template in the request s current app, DMP knows where to find the template file. DMP provides a second function, dmp_render_to_string. This is nearly the same as dmp_render, but dmp_render_to_string returns a string rather than an HttpResponse object. You really don t need to worry about any of this. Templates are rendered in the current app 99% of the time, so just use this code unless you are in a special use case: from django.conf import settings from django_mako_plus import view_function from datetime import datetime @view_function 4.4. Tutorial 25

def process_request(request): context = { 'now': datetime.now(), } return request.dmp.render('index.html', context) But That s Not Django! In the above code, you may have noticed that we didn t use the normal Django shortcuts like render and render_to_response. DMP provides the shortcuts like dmp_render because its renderers are tied to apps (which is different than Django). But that doesn t mean you can t use the standard Django shortcuts, TemplateResponse, and SimpleTemplateResponse with DMP. There s a full page devoted to the topic, so take a side trip to the topic on Django Template Functions if you want to stick to the normal Django API. Further Reading The advanced topic on templates expands with the following topics: Templates in other apps Templates in other directories, even outside the project Controlling content types and HTTP codes Convenience functions 4.4.3 T3: URL Parameters Contents T3: URL Parameters What About Django Path Converters? At a Glance A New View Function Signature For More Information Django is all about pretty URLs. In keeping with that philosophy, we present URL parameters. You ve already used the beginning parts of the URL: the first specifies the app, the second specifies the view/template. URL parameters are the third part, fourth part, and so on. In traditional web links, we specify parameters using key=value pairs, as in /homepage/index? product=144&model=a58ux. That s ugly, and it s certainly not the Django way. What About Django Path Converters? One of the big changes in Django 2.0 (late 2017) is simplified URLs, including automatic parameter conversion. You might be wondering how the two relate to one another. 26 Chapter 4. Contents

DMP first included automatic parameter conversion in early 2017, and it wasn t influenced by Django s design; the two developed separately. DMP s parameter conversion is different in the following ways: DMP discovers parameters and type hints from your view function signatures; Django uses your patterns in urls.py. Type hints and parameter defaults in DMP are specified the standard Python way. Django uses a custom URL syntax. DMP has more built-in converters: DateTime, Decimal, all Django models, etc. Converters in DMP match using isinstance; converters in Django match by regex match. The conversion method in DMP matches well with its goal of convention-over-configuration. Django s method matches well with its enumerate all urls design. You can use both in the same project; DMP apps do it the DMP way, other apps do it the Django way. At a Glance Compare the old vs. the new: This: /homepage/index? product=144&model=a58ux Longer More difficult to text or email Less search engine friendly A face only a programmer could love... Becomes This: /homepage/index/144/a58ux/ Shorter Easier to text or email More search engine friendly URL parameters don t take the place of form parameters. You ll still use GET and POST parameters to submit forms. You ll still use name/value pairs when it makes sense, such as on a search page. URL parameters are best used for object ids and other simple items that pages need to display, such as the product id in the previous example. DMP sends extra parameters (411 and A58UX above) to your view function. You only need to add variables for these parameters to your view function signature. In addition, DMP automatically converts values into ints, booleans, and even your Models. A New View Function Signature Let s modify homepage/views/index.py to support adjusting the current date by a certain amount of time. We ll specify the hours, minutes, and direction in the URL: from django.conf import settings from django_mako_plus import view_function from datetime import datetime, timedelta @view_function def process_request(request, hrs, mins, forward='+'): delta = timedelta(hours=int(hrs), minutes=int(mins)) if forward == '+': now = datetime.now() + delta else: now = datetime.now() - delta context = { 'now': now, 4.4. Tutorial 27

} return request.dmp.render('index.html', context) We ll use the homepage/templates/index.html file we created in previous tutorial parts: <%inherit file="base.htm" /> <%block name="content"> <div class="content"> <p class="server-time">the current server time is ${ now }.</p> </div> </%block> Take your browser to http://localhost:8000/homepage/index/6/30/+. It shows a time 6:30 in the future by evaluating the values in the URL. Try different values to adjust the hours, minutes, and direction. Since forward has a default value, it can be omitted: http://localhost:8000/homepage/index/6/30. This first example shows how DMP sends URL parts into view functions. It separates the URL parts by the slash /, and positionally matches them to functions. In this simplest of view function signatures, the parameters are strings. If you are using multiple decorators on your endpoints, you can save a lot of trouble by checking that your decorators are wrapping correctly. Adding Type Hints But what if you need integers, booleans, or even Model instances, such as a User object, Purchase object, or Question object? By adding type hints (yes, they re in the standard Python langauge), we can have them converted to the right type automatically. Add the following type hints to your process_request function, and remove the typecasting calls: from django.conf import settings from django_mako_plus import view_function from datetime import datetime, timedelta @view_function def process_request(request, hrs:int, mins:int, forward:bool=true): delta = timedelta(hours=hrs, minutes=mins) if forward: now = datetime.now() + delta else: now = datetime.now() - delta context = { 'now': now, } return request.dmp.render('index.html', context) DMP casts the parameters by inspecting the method signature of process_request which specifies the parameter name, a color, and the type. If a conversion error occurs, the default converter raises Http404. All of this is configurable and extensible (read on). Automatic Model Conversion DMP converts all of the Model classes in your project. Suppose we have an model called storefront.purchase. If we list this type as the type hint, DMP will pull the object from the database automatically: 28 Chapter 4. Contents

from django_mako_plus import view_function from storefront.models import Purchase @view_function def process_request(request, purchase:purchase): # the `purchase` variable has already been pulled from the database In the above code, one of two outcomes will occur: If a Purchase record with primary key 1501 exists in the database, it is sent into the function. If it doesn t exist, DMP raises Http404. For More Information The advanced topic on conversion expands the topics above. Come back later if you want to continue the discussion on parameter conversion. 4.4.4 T4: zip(html, JS, CSS) Contents T4: zip(html, JS, CSS) A Bit of Style Javascript Javascript in Context Bundlers like Webpack, Browserify, etc. Behind the CSS and JS Curtain Modern web pages are made up of three primary parts: HTML, CSS, and Javascript (media might be a fourth, but we ll go with three for now). Since all of your pages need these three components, this framework combines them intelligently for you. All you have to do is name the.html, the css., and the.js files correctly, and DMP will insert the <link> and <script> tags automatically for you. Convention over configuration. Just like a slice of home-baked apple pie. A Bit of Style To style our index.html file, open homepage/styles/index.css and copy the following into it:.server-time { font-size: 2em; color: red; } When you refresh your page, the server time should be styled with large, red text. If you view the html source in your browser, you ll see a new <link...> near the top of your file. It s as easy as naming the files the same and placing the.css file in the styles/ directory. 4.4. Tutorial 29

The framework knows how to follow template inheritance. For example, since index.html extends from base. htm, we can actually put our CSS in either: index.css or base.css. Place your CSS styles in the appropriate file, depending on where the HTML elements are located. For example, let s style our header a little. Since the <header> element is in base.htm, open homepage/styles/base.css and check for the following: html, body { margin: 0; padding: 0; } header { background-color: #147871; padding: 15px 20px; border-top: 4px solid #606060; border-bottom: 4px solid #606060; } header h1 { color: #FFFFFF; margin: 0; padding: 0; } main { margin: 0; padding: 15px; } Since base.htm will be the parent page of nearly every HTML page on your site, these common styles will apply to all pages. If you view source in the browser, you ll see the CSS files were included as follows: <link rel="stylesheet" type="text/css" href="/static/homepage/styles/base.css?33192040 " /> <link rel="stylesheet" type="text/css" href="/static/homepage/styles/index.css? 33192040" /> Note that base.css is included first because it s at the top of the hierarchy. Styles from index.css override any conflicting styles from base.css, which makes sense because index.html is the final template in the inheritance chain. You might be wondering about the big number after the html source <link>. That s the file modification time, in minutes since 1970. This is included because browsers don t automatically download new CSS files (I m looking at you here Chrome!). They use their cached versions until a specified date, often far in the future (this duration is set by your web server). By adding a number to the end of the file, browsers think the CSS files are new because the filename changes whenever you change the file. Trixy browserses... Javascript Javascript files work the same way as CSS files, so if you skipped the CSS sections above, you might want to go read through them. Javascript files are placed in the scripts/ directory and, of course, end with *.js extension. Let s add a client-side, Javascript-based timer. Create the file homepage/scripts/index.js and place the following JQuery code into it: $(function() { // update the time every 1 seconds 30 Chapter 4. Contents

}); window.setinterval(function() { $('.browser-time').text('the current browser time is ' + new Date() + '.'); }, 1000); Refresh your browser page, and you should see the browser time updating each second. Congratulations, you ve now got a modern, HTML5 web page. Javascript in Context What if we need to get a value from our Python view code, such as the server time, into the index.js file? DMP handles this too. Lets compare the server time with the browser time allows us to calculate the time zone difference between the two. To send a variable to the JS environment, tag it with jscontext(). Change your index.py file to the following: from django.conf import settings from django_mako_plus import view_function, jscontext from datetime import datetime @view_function def process_request(request): context = { jscontext('now'): datetime.now(), } return request.dmp.render('index.html', context) Reload your browser, and then right-click and Inspect to see your DOM. The <script> tag now looks like this: <script type="text/javascript" src="/static/homepage/scripts/index.js?1509480811" data-context="u5a8240023befacbc327df447012720"></script> When you tag a context key with jscontext('now'), DMP adds it to a context object and connects it via data-context. Note that variables sent via jscontext must be serializable by Django s django.core. serializers.json.djangojsonencoder (although you can set a custom encoder if needed). The default encoder includes all the typical types, plus datetime, date, time, timedelta, Decimal, and UUID. Let s use the variable in index.js: $(function(context) { return function() { console.log(context) var servertime = new Date(context.now) // server time (from DMP_CONTEXT) var browsertime = new Date() // browser time var hours = Math.round(Math.abs(serverTime - browsertime) / 36e5) $('.browser-time').text('the current browser is ' + hours + ' hours off of the server time zone.') } }(DMP_CONTEXT.get())) Reload your browser, and you should see the calculation of hours. The context is sent to the script via a data attribute on the <script> element. The closure surrounding everything keeps the variable local to this script. Read more about this in the topic on CSS and JS. Also, see providers for the es6 arrow-style syntax for this closure. 4.4. Tutorial 31

Bundlers like Webpack, Browserify, etc. If you are using JS bundles, DMP files can go right in the bundles. See bundling in Rendering CSS and JS for more information. Behind the CSS and JS Curtain After reading about automatic CSS and JS inclusion, you might want to know how it works. It s all done in the templates (base.htm now, and base_ajax.htm in a later section below) you are inheriting from. Open base.htm and look at the following code: ## render the static file links for this template <script src="/django_mako_plus/dmp-common.min.js"></script> ${ django_mako_plus.links(self) } The calls to links() include the <link> and <script> tags for the template name and all of its supertemplates. These links are placed at the end of your <head> section. (Just a few years ago, common practice was to place script tags at the end of the body, but modern browsers with asyncronous and deferred scripts have put them back in the body.) This all works because the index.html template extends from the base.htm template. If you fail to inherit from base.htm or base_ajax.htm, DMP won t be able to include the support files. Read more about providers in Rendering CSS and JS. 4.4.5 T5: Ajax Contents T5: Ajax A Simple Example Really, a Whole New File for Ajax? What would the modern web be without Ajax? Truthfully... a lot simpler. :) In fact, if we reinvented the web with today s requirements, we d probably end up at a very different place than our current web. Even the name ajax implies the use of xml which we don t use much in ajax anymore. Most ajax calls return json or html these days! But regardless of web history, ajax is required on most pages today. I ll assume you understand the basics of ajax and focus specifically on the ways this framework supports it. A Simple Example Suppose we want to reload the server time every few seconds, but we don t want to reload the entire page. Let s start with the client side of things. Let s place a refresh button in homepage/templates/index.html: <%inherit file="base.htm" /> <%block name="content"> <div class="content"> <h3>congratulations -- you've successfully created a new django-mako-plus app!</ h3> <h4>next Up: Go through the django-mako-plus tutorial and add Javascript, CSS, and urlparams to this page.</h4> 32 Chapter 4. Contents