SlideShare a Scribd company logo
Lightweight Django 1st Edition Julia Elman pdf
download
https://ebookgate.com/product/lightweight-django-1st-edition-
julia-elman/
Get Instant Ebook Downloads – Browse at https://ebookgate.com
Instant digital products (PDF, ePub, MOBI) available
Download now and explore formats that suit you...
Mastering Django Core 1st Edition Nigel George
https://ebookgate.com/product/mastering-django-core-1st-edition-nigel-
george/
ebookgate.com
Pro Django 2nd Edition Marty Alchin
https://ebookgate.com/product/pro-django-2nd-edition-marty-alchin/
ebookgate.com
Web Development with Django Cookbook Bendoraitis
https://ebookgate.com/product/web-development-with-django-cookbook-
bendoraitis/
ebookgate.com
Beginning Django E Commerce 1st Edition Jim Mcgaw (Auth.)
https://ebookgate.com/product/beginning-django-e-commerce-1st-edition-
jim-mcgaw-auth/
ebookgate.com
The Lightweight Treated Soil Method 1st Edition Takashi
Tsuchida
https://ebookgate.com/product/the-lightweight-treated-soil-method-1st-
edition-takashi-tsuchida/
ebookgate.com
Superworm Julia Donaldson
https://ebookgate.com/product/superworm-julia-donaldson/
ebookgate.com
Flexible Manufacture of Lightweight Frame Structures
Proceedings Kleiner
https://ebookgate.com/product/flexible-manufacture-of-lightweight-
frame-structures-proceedings-kleiner/
ebookgate.com
Radiology Strategies 1st Edition Julia Fielding
https://ebookgate.com/product/radiology-strategies-1st-edition-julia-
fielding/
ebookgate.com
Nature Anatomy Julia Rothman
https://ebookgate.com/product/nature-anatomy-julia-rothman/
ebookgate.com
Lightweight Django 1st Edition Julia Elman
Julia Elman & Mark Lavin
Lightweight
Django
USING REST, WEBSOCKETS & BACKBONE
PYTHON/WEB DEVELOPMENT
Lightweight Django
ISBN: 978-1-491-94594-0
US $39.99 CAN $41.99
“A great resource for
going beyond traditional
apps and learning how
Django can power the
backend of single-page
web applications.”
—Aymeric Augustin
Django core developer, CTO, oscaro.com
“Such a good idea—I think
this will lower the barrier
of entry for developers
even more… the more
I read, the more excited
I am!” —Barbara Shaurette
Python Developer, Cox Media Group
Twitter: @oreillymedia
facebook.com/oreilly
Howcanyoutakeadvantageof theDjangoframework tointegratecomplex
client-side interactions and real-time features into your web applications?
Through a series of rapid application development projects, this hands-on
book shows experienced Django developers how to include REST APIs,
WebSockets, and client-side MVC frameworks such as Backbone.js into
new or existing projects.
Learn how to make the most of Django’s decoupled design by choosing
the components you need to build the lightweight applications you want.
Once you finish this book, you’ll know how to build single-page applications
that respond to interactions in real time. If you’re familiar with Python and
JavaScript, you’re good to go.
■
■ Learn a lightweight approach for starting a new Django project
■
■ Break reusable applications into smaller services that
communicate with one another
■
■ Create a static, rapid prototyping site as a scaffold for websites
and applications
■
■ Build a REST API with django-rest-framework
■
■ Learn how to use Django with the Backbone.js MVC framework
■
■ Create a single-page web application on top of your REST API
■
■ Integrate real-time features with WebSockets and the Tornado
networking library
■
■ Use the book’s code-driven examples in your own projects
Julia Elman, a frontend developer and tech education advocate, started learning
Django in 2008 while working at World Online. She is one of the co-founders for
Girl Develop It RDU and PyLadies RDU, organizations that have helped over 850
women learn to program.
Mark Lavin is Technical Director at Caktus Consulting Group in Durham, North
Carolina. He came to Python web development after years of pricing derivatives
on Wall Street. Mark maintains several open source projects related to Django
development.
Lightweight
Django
Elman
&
Lavin
Julia Elman & Mark Lavin
Lightweight
Django
USING REST, WEBSOCKETS & BACKBONE
Julia Elman and Mark Lavin
Lightweight Django
Lightweight Django
by Julia Elman and Mark Lavin
Copyright © 2015 Julia Elman and Mark Lavin. All rights reserved.
Printed in the United States of America.
Published by O’Reilly Media, Inc., 1005 Gravenstein Highway North, Sebastopol, CA 95472.
O’Reilly books may be purchased for educational, business, or sales promotional use. Online editions are
also available for most titles (http://safaribooksonline.com). For more information, contact our corporate/
institutional sales department: 800-998-9938 or corporate@oreilly.com.
Editor: Meghan Blanchette
Production Editor: Colleen Lobner
Copyeditor: Rachel Monaghan
Proofreader: Sonia Saruba
Indexer: Wendy Catalano
Cover Designer: Ellie Volckhausen
Interior Designer: David Futato
Illustrator: Rebecca Demarest
November 2014: First Edition
Revision History for the First Edition:
2014-10-24: First release
See http://oreilly.com/catalog/errata.csp?isbn=9781491945940 for release details.
The O’Reilly logo is a registered trademark of O’Reilly Media, Inc. Lightweight Django, the cover image, and
related trade dress are trademarks of O’Reilly Media, Inc.
Many of the designations used by manufacturers and sellers to distinguish their products are claimed as
trademarks.Wherethosedesignationsappearinthisbook,andO’ReillyMedia,Inc.wasawareofatrademark
claim, the designations have been printed in caps or initial caps.
While the publisher and the authors have used good faith efforts to ensure that the information and in‐
structions contained in this work are accurate, the publisher and the authors disclaim all responsibility for
errors or omissions, including without limitation responsibility for damages resulting from the use of or
reliance on this work. Use of the information and instructions contained in this work is at your own risk. If
any code samples or other technology this work contains or describes is subject to open source licenses or
the intellectual property rights of others, it is your responsibility to ensure that your use thereof complies
with such licenses and/or rights.
ISBN: 978-1-491-94594-0
LSI
Table of Contents
Preface. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . vii
Prerequisites. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . xiii
1. The World’s Smallest Django Project. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1
Hello Django 1
Creating the View 2
The URL Patterns 2
The Settings 3
Running the Example 4
Improvements 5
WSGI Application 6
Additional Configuration 7
Reusable Template 10
2. Stateless Web Application. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13
Why Stateless? 13
Reusable Apps Versus Composable Services 14
Placeholder Image Server 14
Views 16
URL Patterns 16
Placeholder View 17
Image Manipulation 18
Adding Caching 20
Creating the Home Page View 23
Adding Static and Template Settings 23
Home Page Template and CSS 24
Completed Project 26
iii
3. Building a Static Site Generator. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31
Creating Static Sites with Django 31
What Is Rapid Prototyping? 32
Initial Project Layout 32
File/Folder Scaffolding 32
Basic Settings 33
Page Rendering 35
Creating Our Base Templates 35
Static Page Generator 36
Basic Styling 39
Prototype Layouts and Navigation 41
Generating Static Content 46
Settings Configuration 46
Custom Management Command 47
Building a Single Page 49
Serving and Compressing Static Files 50
Hashing Our CSS and JavaScript Files 50
Compressing Our Static Files 51
Generating Dynamic Content 54
Updating Our Templates 54
Adding Metadata 56
4. Building a REST API. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 61
Django and REST 61
Scrum Board Data Map 62
Initial Project Layout 63
Project Settings 64
No Django Admin? 66
Models 66
Designing the API 69
Sprint Endpoints 69
Task and User Endpoints 71
Connecting to the Router 74
Linking Resources 74
Testing Out the API 77
Using the Browsable API 77
Adding Filtering 81
Adding Validations 86
Using a Python Client 89
Next Steps 91
iv | Table of Contents
5. Client-Side Django with Backbone.js. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 93
Brief Overview of Backbone 94
Setting Up Your Project Files 95
JavaScript Dependencies 96
Organization of Your Backbone Application Files 98
Connecting Backbone to Django 100
Client-Side Backbone Routing 102
Creating a Basic Home Page View 102
Setting Up a Minimal Router 103
Using _.template from Underscore.js 104
Building User Authentication 107
Creating a Session Model 107
Creating a Login View 111
Generic Form View 117
Authenticating Routes 120
Creating a Header View 121
6. Single-Page Web Application. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 131
What Are Single-Page Web Applications? 131
Discovering the API 132
Fetching the API 132
Model Customizations 133
Collection Customizations 134
Building Our Home Page 135
Displaying the Current Sprints 135
Creating New Sprints 138
Sprint Detail Page 141
Rendering the Sprint 141
Routing the Sprint Detail 143
Using the Client State 144
Rendering the Tasks 146
AddTaskView 153
CRUD Tasks 156
Rendering Tasks Within a Sprint 156
Updating Tasks 160
Inline Edit Features 163
7. Real-Time Django. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 167
HTML5 Real-Time APIs 167
Websockets 168
Server-Sent Events 168
WebRTC 169
Table of Contents | v
Websockets with Tornado 169
Introduction to Tornado 170
Message Subscriptions 175
Client Communication 178
Minimal Example 179
Socket Wrapper 182
Client Connection 185
Sending Events from the Client 187
Handling Events from the Client 193
Updating Task State 195
8. Communication Between Django and Tornado. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 199
Receiving Updates in Tornado 199
Sending Updates from Django 201
Handling Updates on the Client 203
Server Improvements 204
Robust Subscriptions 204
Websocket Authentication 208
Better Updates 212
Secure Updates 214
Final Websocket Server 217
Index. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 223
vi | Table of Contents
Preface
Since the creation of Django, a plethora of web frameworks have been created in various
open source communities. Frontend-focused web frameworks such as Angular.js, Em‐
ber.js, and Backbone.js have come out of the JavaScript community and become fore‐
runners in modern web development. Where does Django fit into all of this? How can
we integrate these client-side MVC frameworks into our current Django infrastructure?
Lightweight Django teaches you how to take advantage of Django’s Pythonic “batteries
included” philosophy. Its aim is to guide you through misconceptions that Django is
too “heavy” for rapid application development. From creating the world’s smallest
DjangoapplicationtobuildingaRESTfulAPI,LightweightDjangowillwalkyouthrough
how to take advantage of this popular Python web framework.
Why This Book?
We wanted to write this book primarily because we love Django. The community is
amazing, and there are so many resources to learn about Django and to develop appli‐
cations using it. However, we also felt like many of these resources, including the official
Django documentation, put too much emphasis on the power of Django and not on its
decoupled design. Django is a well-written framework, with numerous utilities for
building web applications included. What we want this book to highlight is how you
can break apart and potentially replace these components to pick and choose what best
suits the application you want to build. Similarly, we wanted to break down the typical
structure of Django projects and applications. Our goal is to get you to stop asking “how
do I do X in Django?” and instead ask “does Django provide anything to help me do X,
and if not, is something available in the community?”
In addition, we wanted to answer questions about where Django fits in a Web in which
more applications are built with heavy client-side interactions and real-time compo‐
nents, and paired with native mobile applications. As a framework, Django is agnostic
about the client, which leaves some users feeling like Django doesn’t have an answer for
vii
building these types of applications. We hope that this book can help shape how the
community approaches these types of problems. We want to see Django and its com‐
munity continue to grow, and we want to be a part of it for many more years to come.
Who Should Read This Book?
If you are interested in reading this book, you are most likely an intermediate Django
user. You’ve gone through the Django polls tutorial, as well as written a few basic
Django web applications, and are now wondering what the next steps are. Lightweight
Django serves as that next step to help outline how to utilize Django’s utilities and
simplicity.
Or you might be currently working on a Django project and wondering how to integrate
something like Backbone.js into your project. Lightweight Django will teach you some
best practices for integration and will give you a jumping-off point for building content-
rich web applications.
Who Should Not Read This Book?
While we feel that Lightweight Django is beneficial to developers from many back‐
grounds, there might be certain people who won’t find this book interesting. For those
of you who do not find writing Python and/or JavaScript pleasurable, this book is most
likely not for you. All of the concepts and examples revolve around these languages,
and they will be heavily used throughout each chapter. We also don’t recommend this
book for those who are brand new to Django.
About the Examples
Each of the example projects has been carefully crafted under the theme of rapid ap‐
plication development. In each chapter, you’ll learn how to build projects that assist
withprojectmanagement,tools,andteamcollaboration.Wewantedourreaderstobuild
projects that they find useful and can customize for their own use. In general, if example
code is offered with this book, you may use it in your programs and documentation.
You do not need to contact us for permission unless you’re reproducing a significant
portion of the code. For example, writing a program that uses several chunks of code
from this book does not require permission. Selling or distributing a CD-ROM of ex‐
amples from O’Reilly books does require permission. Answering a question by citing
this book and quoting example code does not require permission. Incorporating a sig‐
nificant amount of example code from this book into your product’s documentation
does require permission.
The code samples for this title can be found here: https://github.com/lightweightdjango/
examples.
viii | Preface
We appreciate, but do not require, attribution. An attribution usually includes the title,
author,publisher,andISBN.Forexample:“LightweightDjangobyJuliaElmanandMark
Lavin (O’Reilly). Copyright 2015 Julia Elman and Mark Lavin, 978-1-491-94594-0.”
If you feel your use of code examples falls outside fair use or the permission given above,
feel free to contact us at permissions@oreilly.com.
Organization of This Book
Chapter 1, The World’s Smallest Django Project
Creating lightweight and simple web applications is the core concept in this book.
In this chapter, you’ll be building a runnable, single-file “Hello World” Django
application.
Chapter 2, Stateless Web Application
Ever wonder how placeholder image services are created? Chapter 2 walks you
through how to build a stateless web application to generate placeholder image
URLs.
Chapter 3, Building a Static Site Generator
Rapid prototyping is a useful technique for creating and scaffolding web applica‐
tions. We’ll review the purposes of this technique by creating a static site generator
to help scaffold your team’s project.
Chapter 4, Building a REST API
RESTAPIsareanimportantpartofcreatingwebapplicationswithrichandrelevant
content. This is the chapter in which we start building out a large-scale Scrum board
application by using the django-rest-framework.
Chapter 5, Client-Side Django with Backbone.js
Chapter 5 continues with what we built in Chapter 4 by walking you through cre‐
ating a Backbone.js application that works with our newly made RESTful API. We’ll
touch on each component that creates a new Backbone application and how to sync
up this client-side framework with Django.
Chapter 6, Single-Page Web Application
Single-page web applications are a way in which we can create enriching client-side
web applications. In this chapter we’ll return to our simple Backbone application
and continue our progress by making it a robust single-page application.
Chapter 7, Real-Time Django
Creating web applications that respond to interactions in real time provides instant
gratification for our users. To complete our project from the previous two chapters,
we’lladdareal-timecomponenttoourScrumboardusingwebsocketsandTornado,
an asynchronous networking library written in Python.
Preface | ix
Chapter 8, Communication Between Django and Tornado
ConnectingthepowerofDjangototherobustbehaviorsofTornadoisanimportant
measure in creating scalable, real-time Django applications. In this chapter, we’ll
expand on our usage of the Tornado server by integrating the ability to work with
Django to create a secure and interactive relationship.
Conventions Used in This Book
The following typographical conventions are used in this book:
Italic
Indicates new terms, URLs, email addresses, filenames, and file extensions.
Constant width
Used for program listings, as well as within paragraphs to refer to program elements
such as variable or function names, databases, data types, environment variables,
statements, and keywords.
Constant width bold
Shows commands or other text that should be typed literally by the user.
Constant width italic
Shows text that should be replaced with user-supplied values or by values deter‐
mined by context.
Throughout the code examples, we will use an ellipsis (…) to denote that some of the
previously displayed content has been skipped to shorten long code examples or to skip
to the most relevant section of the code.
This element signifies a tip or suggestion.
This element signifies a general note.
This element indicates a warning or caution.
x | Preface
How to Contact Us
Please address comments and questions concerning this book to the publisher:
O’Reilly Media, Inc.
1005 Gravenstein Highway North
Sebastopol, CA 95472
800-998-9938 (in the United States or Canada)
707-829-0515 (international or local)
707-829-0104 (fax)
We have a web page for this book, where we list errata, examples, and any additional
information. You can access this page at http://www.oreilly.com/catalog/
0636920032502.
To comment or ask technical questions about this book, send email to
lightweightdjango@gmail.com.
For more information about our books, courses, conferences, and news, see our website
at http://www.oreilly.com.
Find us on Facebook: http://facebook.com/oreilly
Follow us on Twitter: http://twitter.com/oreillymedia
Watch us on YouTube: http://www.youtube.com/oreillymedia
Acknowledgments
Therearenumerouspeopletothankandwithoutwhomthisbookwouldnotbepossible.
We received amazing support from our editor, Meghan Blanchette.
Thank you to our technical reviewers—Aymeric Augustin, Jon Banafato, Barbara
Shaurette, and Marie Selvanadin— for your comments, both positive and negative,
which helped to shape and focus the book. Also thank you to Heather Scherer for shep‐
herding the technical review.
We are grateful to all the open source developers and contributors whose endless hours
of work were needed to make these tools available for us to use and write about.
Thank you to our early release readers for taking a chance on our unfinished work,
dealing with typos and poor formatting, and giving feedback and correcting mistakes.
Julia
Iwouldliketothankmywonderfulfamilyandclosefriendsfortheirsupportthroughout
the course of writing this book. To my husband, Andrew, for believing in my abilities,
Preface | xi
and for his constant encouragement and steadfast support during this long and bumpy
journey. To my daughter, Hannah, who is my inspiration and from whom I can always
grow my strength every step of the way. To my mother, Katherine, for pushing me
beyond what I ever thought I was capable of doing. To my stepfather, Tom, for teaching
me how to use a cordless drill, changing the oil in my car, and instilling in me the value
of hard work. Thank you to my brother, Alex, and sister, Elizabeth, for always cheering
me on from the sidelines. Thank you to my best friend, Jenny, for her constant love and
lifelong friendship.
Also, thank you to my wonderful coauthor, Mark, for his brilliance and friendship; he
is one of the most talented developers I have ever collaborated with. We made it to this
finish line together, and I cannot imagine going through this book writing journey with
anyone else.
I’d also like to thank the Python community and a few specific members who have
inspired, encouraged, and/or mentored me throughout my career: James Bennett, Sean
Bleier, Nathan Borror, Colin Copeland, Matt Croydon, Katie Cunningham, Selena
Deckelmann, Jacob Kaplan-Moss, Jessica McKellar, Jesse Noller, Christian Metts, Lynn
Root, Caleb Smith, Paul Smith, Karen Tracey, Malcolm Tredinnick, Ben Turner, and
Simon Willison.
Mark
First and foremost, this book would not be possible without the love and support of my
family. My wife, Beth, and daughter, Kennedy, put up with long hours and a grumpier
and more stressed version of me than they deserve. Also thanks to my brother, Matt,
for his insight and early feedback. Thank you to my parents and my brother James for
their lifetime of support.
Thank you to my coauthor, Julia. Our collaboration is a celebration of our friendship
and mutual respect. I will forever cherish our ability to work together to create some‐
thing greater than the sum of our contributions.
Finally, thank you to my coworkers at Caktus Group for your support in time, feedback,
and encouragement.
xii | Preface
Prerequisites
Before we dive in, this chapter is an outline of the knowledge and software requirements
you’ll need to follow the examples in this book.
Python
This book is aimed at developers with at least some previous Python experience, and in
this book we are using Python 3. In particular, the examples have been tested to run on
Python 3.3 and 3.4. Those familiar enough with Python may be able to work through
this book using Python 2.7, converting the example code as needed, though it is not
recommended. To read more about what is new in these versions of Python and to find
installation instructions for your system, visit https://www.python.org/downloads/.
We expect that you have Python installed on your local development machine, know
how to edit Python files, and know how to run them. Throughout this book, when we
reference Python on the command line, we will use python, though some systems or
installations may require using python3 or the full version, such as python3.3 or
python3.4. Similarly, when installing new packages, the examples will use pip, though
some installations may require using pip3. For this book, and Python development in
general, it is recommended that you create an isolated Python environment for each
project using virtualenv. Without an isolated environment, installing new Python
packages with pip may require root access or administrative rights on your computer.
We’ll assume that if this is the case, you will prefix the pip command with sudo or any
other commands you may need to gain such rights, but those prefixes will not be shown
in the examples.
xiii
Python Packages
The only Python package that is required before you start this book is Django. All of
the examples have been tested and written to work with Django 1.7. It is recommended
that you install with pip:
hostname $ pip install Django==1.7
As of August 2014, Django 1.7 was still in a release candidate phase.
If the preceding installation does not work, you can install the 1.7 pre-
release from the development branch with pip install https://
github.com/django/django/archive/stable/1.7.x.zip.
To read more about what is new in this version of Django, visit https://docs.djangopro
ject.com/en/dev/releases/1.7/. For additional installation instructions, you can also see
the Django guide on installation.
Additional packages will be installed throughout the chapters. Chapters 1, 2, and 3 are
each independent projects and can be treated as separate virtual environments, again
with Django being the only prerequisite. Chapters 4 through 8 comprise one large
project, and the same virtual environment should be used for those chapters.
Web Development
As Django is a web framework, this book assumes you have some basic knowledge of
HTML and CSS. The JavaScript examples are more in depth, and the expected level of
knowledgeisdetailedmoreinthefollowingsection.AbasicunderstandingoftheHTTP
protocol, in particular the usage and purpose of the various HTTP verbs (GET, POST,
PUT, DELETE, etc.), is helpful.
JavaScript
The later chapters in this book make heavy use of JavaScript. You should also be familiar
withwritingJavaScript/jQuery.AdeveloperexperienceddoingDOMmanipulationand
makingAJAXcallswithjQueryshouldbeabletofollowtheexamplesusingBackbone.js.
If you are familiar with another client-side framework such as Angular.js, Ember.js, or
Knockout.js, you will be ahead of the game. This is not meant to be a definitive guide
on Backbone.js. If you are not familiar with working with JavaScript, and Backbone.js
MVC architecture in particular, here are some recommended O’Reilly titles for you to
read:
xiv | Prerequisites
• JavaScript: The Definitive Guide, by David Flanagan (2011)
• JavaScript: The Good Parts, by Douglas Crockford (2008)
• JavaScript Patterns, by Stoyan Stefanov (2010)
• Speaking JavaScript, by Axel Rauschmayer (2014)
• Developing Backbone.js Applications, by Addy Osmani (2013)
Browser Support
The examples in this book make use of relatively new HTML5 and CSS3 APIs, and
expectamodernbrowser.Anythingbelowtheseversionshasnotbeentestedthoroughly
and/or may not support the technology that we use in the examples:
• IE 10+
• Firefox 28.0+
• Chrome 33.0+
Youshouldbefamiliarwithusingthedevelopertoolsinyourpreferredbrowsertodebug
potential errors, see network requests, and use the JavaScript console.
Additional Software
Later chapters will make use of two popular databases: PostgreSQL and Redis. Brief
installation instructions are noted in the chapters where needed, but you should refer
to the official documentation for a more complete guide for your system.
PostgreSQL is an open source relational database system that has strong support in the
Django community. Any version of PostgreSQL supported by Django will work for this
book. Django 1.7 supports PostgreSQL 8.4 and higher.
Redis is an open source key/value cache. This book makes use of the pub/sub features
of Redis and requires 2.0 and higher.
Prerequisites | xv
Lightweight Django 1st Edition Julia Elman
CHAPTER 1
The World’s Smallest Django Project
How many of our journeys into using Django have begun with the official polls tutorial?
For many it seems like a rite of passage, but as an introduction to Django it is a fairly
daunting task. With various commands to run and files to generate, it is even harder to
tell the difference between a project and an application. For new users wanting to start
building applications with Django, it begins to feel far too “heavy” as an option for a
web framework. What are some ways we can ease these new users’ fears to create a clean
and simple start?
Let’s take a moment to consider the recommended tasks for starting a Django project.
The creation of a new project generally starts with the startproject command. There
is no real magic to what this command does; it simply creates a few files and directories.
While the startproject command is a useful tool, it is not required in order to start a
Django project. You are free to lay out your project however you like based on what you
want to do. For larger projects, developers benefit from the code organization provided
by the startproject command. However, the convenience of this command shouldn’t
stop you from understanding what it does and why it is helpful.
In this chapter we’ll lay out an example of how to create a simple project using Django’s
basicbuildingblocks.Thislightweight“HelloWorld”projectwillcreateasimpleDjango
application using a single-file approach.
Hello Django
Building a “Hello World” example in a new language or framework is a common first
project.We’veseenthissimplestarterprojectexamplecomeoutoftheFlaskcommunity
to display how lightweight it is as a microframework.
In this chapter, we’ll start by using a single hello.py file. This file will contain all of the
code needed to run our Django project. In order to have a full working project, we’ll
1
need to create a view to serve the root URL and the necessary settings to configure the
Django environment.
Creating the View
Django is referred to as a model-template-view (MTV) framework. The view portion
typically inspects the incoming HTTP request and queries, or constructs, the necessary
data to send to the presentation layer.
Inourexamplehello.pyfile,let’screateasimplewaytoexecutea“HelloWorld”response.
from django.http import HttpResponse
def index(request):
return HttpResponse('Hello World')
In a larger project, this would typically be in a views.py file inside one of your apps.
However, there is no requirement for views to live inside of apps. There is also no
requirementthatviewsliveinafilecalledviews.py.Thisispurelyamatterofconvention,
but not a requirement on which to base our project’s structure.
The URL Patterns
In order to tie our view into the site’s structure, we’ll need to associate it with a URL
pattern.Forthisexample,theserverrootcanservetheviewonitsown.Djangoassociates
views with their URL by pairing a regular expression to match the URL and any callable
arguments to the view. The following is an example from hello.py of how we make this
connection.
from django.conf.urls import url
from django.http import HttpResponse
def index(request):
return HttpResponse('Hello World')
urlpatterns = (
url(r'^$', index),
)
Now this file combines both a typical views.py file and the root urls.py file. Again, it is
worth noting that there is no requirement for the URL patterns to be included in a
urls.py file. They can live in any importable Python module.
Let’s move on to our Django settings and the simple lines we’ll need to make our project
runnable.
2 | Chapter 1: The World’s Smallest Django Project
The Settings
Django settings detail everything from database and cache connections to internation‐
alization features and static and uploaded resources. For many developers just getting
started, the settings in Django are a major point of confusion. While recent releases have
worked to trim down the default settings’ file length, it can still be overwhelming.
This example will run Django in debugging mode. Beyond that, Django merely needs
to be configured to know where the root URLs can be found and will use the value
defined by the urlpatterns variable in that module. In this example from hello.py, the
root URLs are in the current module and will use the urlpatterns defined in the pre‐
vious section.
from django.conf import settings
settings.configure(
DEBUG=True,
SECRET_KEY='thisisthesecretkey',
ROOT_URLCONF=__name__,
MIDDLEWARE_CLASSES=(
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
),
)
...
This example includes a nonrandom SECRET_KEY setting, which
should not be used in a production environment. A secret key must
be generated for the default session and cross-site request forgery
(CSRF) protection. It is important for any production site to have a
random SECRET_KEY that is kept private. To learn more, go to the
documentation at https://docs.djangoproject.com/en/1.7/topics/sign
ing/.
We need to configure the settings before making any additional imports from Django,
as some parts of the framework expect the settings to be configured before they are
imported. Normally, this wouldn’t be an issue since these settings would be included in
their own settings.py file. The file generated by the default startproject command
would also include settings for things that aren’t used by this example, such as the in‐
ternationalization and static resources.
Hello Django | 3
Running the Example
Let’s take a look at what our example looks like during runserver. A typical Django
project contains a manage.py file, which is used to run various commands such as cre‐
ating database tables and running the development server. This file itself is a total of 10
lines of code. We’ll be adding in the relevant portions of this file into our hello.py to
create the same abilities manage.py has:
import sys
from django.conf import settings
settings.configure(
DEBUG=True,
SECRET_KEY='thisisthesecretkey',
ROOT_URLCONF=__name__,
MIDDLEWARE_CLASSES=(
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
),
)
from django.conf.urls import url
from django.http import HttpResponse
def index(request):
return HttpResponse('Hello World')
urlpatterns = (
url(r'^$', index),
)
if __name__ == "__main__":
from django.core.management import execute_from_command_line
execute_from_command_line(sys.argv)
Now you can start the example in the command line:
hostname $ python hello.py runserver
Performing system checks...
System check identified no issues (0 silenced).
August 06, 2014 - 19:15:36
Django version 1.7c2, using settings None
4 | Chapter 1: The World’s Smallest Django Project
Starting development server at http://7.0.0.1:8000/
Quit the server with CONTROL-C.
and visit http://localhost:8000/ in your favorite browser to see “Hello World,” as seen in
Figure 1-1.
Figure 1-1. Hello World
Now that we have a very basic file structure in place, let’s move on to adding more
elements to serve up our files.
Improvements
This example shows some of the fundamental pieces of the Django framework: writing
views, creating settings, and running management commands. At its core, Django is a
PythonframeworkfortakingincomingHTTPrequestsandreturningHTTPresponses.
What happens in between is up to you.
Django also provides additional utilities for common tasks involved in handling HTTP
requests, such as rendering HTML, parsing form data, and persisting session state.
While not required, it is important to understand how these features can be used in
Improvements | 5
your application in a lightweight manner. By doing so, you gain a better understanding
of the overall Django framework and true capabilities.
WSGI Application
Currently, our “Hello World” project runs through the runserver command. This is a
simple server based on the socket server in the standard library. It has helpful utilities
for local development such as auto–code reloading. While it is convenient for local
development, runserver is not appropriate for production deployment security.
The Web Server Gateway Interface (WSGI) is the specification for how web servers
communicate with application frameworks such as Django, and was defined by PEP
333 and improved in PEP 3333. There are numerous choices for web servers that speak
WSGI, including Apache via mod_wsgi, Gunicorn, uWSGI, CherryPy, Tornado, and
Chaussette.
Each of these servers needs a properly defined WSGI application to be used. Django has
an easy interface for creating this application through get_wsgi_application.
...
from django.conf.urls import url
from django.core.wsgi import get_wsgi_application
from django.http import HttpResponse
...
application = get_wsgi_application()
if __name__ == "__main__":
from django.core.management import execute_from_command_line
execute_from_command_line(sys.argv)
This would normally be contained within the wsgi.py file created by the startproject
command. The name application is merely a convention used by most WSGI servers;
each provides configuration options to use a different name if needed.
Now our simple Django project is ready for the WSGI server. Gunicorn is a popular
choice for a pure-Python WSGI application server; it has a solid performance record,
is easy to install, and also runs on Python 3. Gunicorn can be installed via the Python
Package Index (pip).
hostname $ pip install gunicorn
Once Gunicorn is installed, you can run it fairly simply by using the gunicorn com‐
mand.
hostname $ gunicorn hello --log-file=-
[2014-08-06 19:17:26 -0400] [37043] [INFO] Starting gunicorn 19.1.1
[2014-08-06 19:17:26 -0400] [37043] [INFO]
Listening at: http://127.0.0.1:8000 (37043)
6 | Chapter 1: The World’s Smallest Django Project
[2014-08-06 19:17:26 -0400] [37043] [INFO] Using worker: sync
[2014-08-06 19:17:26 -0400] [37046] [INFO] Booting worker with pid: 37046
As seen in the output, this example is running using Gunicorn version 19.1.1. The
timestamps shown contain your time zone offset, which may differ depending on your
locale. The process IDs for the arbiter and the worker will also be different.
As of R19, Gunicorn no longer logs to the console by default. Adding
the --log-file=- option ensures that the output will be logged to the
console. You can read more about Gunicorn settings at http://
docs.gunicorn.org/en/19.1/.
As with runserver in Django, the server is listening on http://127.0.0.1:8000/. This
works out nicely and makes an easier configuration for us to work with.
Additional Configuration
While Gunicorn is a production-ready web server, the application itself is not yet pro‐
duction ready, as DEBUG should never be enabled in production. As previously noted,
the SECRET_KEY is also nonrandom and should be made random for additional security.
For more information on the security implications of the DEBUG and
SECRET_KEY settings, please refer to the official Django documenta‐
tion.
This leads to a common question in the Django community: how should the project
manage different settings for development, staging, and production environments?
Django’s wiki contains a long list of approaches, and there are a number of reusable
applications that aim to tackle this problem. A comparison of those applications can be
found on Django Packages. While many of these options can be ideal in some cases,
such as converting the settings.py into a package and creating modules for each envi‐
ronment, they do not line up well with our example’s current single-file setup.
The Twelve Factor App is a methodology for building and deploying HTTP service
applications. This methodology recommends separating configuration and code as well
as storing configurations in environment variables. This makes the configuration easy
to change on the deployment and makes the configuration OS-agnostic.
Improvements | 7
Let’s apply this methodology to our hello.py example. There are only two settings that
are likely to change between environments: DEBUG and SECRET_KEY.
import os
import sys
from django.conf import settings
DEBUG = os.environ.get('DEBUG', 'on') == 'on'
SECRET_KEY = os.environ.get('SECRET_KEY', os.urandom(32))
settings.configure(
DEBUG=DEBUG,
SECRET_KEY=SECRET_KEY,
ROOT_URLCONF=__name__,
MIDDLEWARE_CLASSES=(
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
),
)
As you may notice, the default for DEBUG is True, and the SECRET_KEY will be randomly
generated each time the application is loaded if it is not set. That will work for this toy
example,butiftheapplicationwereusingapieceofDjangothatrequirestheSECRET_KEY
to remain stable, such as the signed cookies, this would cause the sessions to be fre‐
quently invalidated.
Let’s examine how this translates to launching the application. To disable the DEBUG
setting, we need to set the DEBUG environment variable to something other than on. In
a UNIX-derivative system, such as Linux, OS X, or FreeBSD, environment variables are
set on the command line with the export command. On Windows, you’d use set.
hostname $ export DEBUG=off
hostname $ python hello.py runserver
CommandError: You must set settings.ALLOWED_HOSTS if DEBUG is False.
As you can see from the error, the ALLOWED_HOSTS setting isn’t configured by our ap‐
plication. ALLOWED_HOSTS is used to validate incoming HTTP HOST header values and
should be set to a list of acceptable values for the HOST. If the application is meant to
serve example.com, then ALLOWED_HOSTS should allow only for clients that are request‐
ing example.com. If the ALLOWED_HOSTS environment variable isn’t set, then it will allow
requests only for localhost. This snippet from hello.py illustrates.
import os
import sys
from django.conf import settings
8 | Chapter 1: The World’s Smallest Django Project
DEBUG = os.environ.get('DEBUG', 'on') == 'on'
SECRET_KEY = os.environ.get('SECRET_KEY', os.urandom(32))
ALLOWED_HOSTS = os.environ.get('ALLOWED_HOSTS', 'localhost').split(',')
settings.configure(
DEBUG=DEBUG,
SECRET_KEY=SECRET_KEY,
ALLOWED_HOSTS=ALLOWED_HOSTS,
ROOT_URLCONF=__name__,
MIDDLEWARE_CLASSES=(
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
),
)
With our ALLOWED_HOSTS variable set, we now have validation for our incoming HTTP
HOST header values.
For a complete reference on the ALLOWED_HOSTS setting, see the offi‐
cial Django documentation.
Outside the development environment, the application might need to serve multiple
hosts, such as localhost and example.com, so the configuration allows us to specify
multiple hostnames separated by commas.
hostname $ export DEBUG=off
hostname $ export ALLOWED_HOSTS=localhost,example.com
hostname $ python hello.py runserver
...
[06/Aug/2014 19:45:53] "GET / HTTP/1.1" 200 11
This gives us a flexible means of configuration across environments. While it would be
slightly more difficult to change more complex settings, such as INSTALLED_APPS or
MIDDLEWARE_CLASSES, that is in line with the overall methodology, which encourages
minimal differences between environments.
If you want to make complex changes between environments, you
should take time to consider what impact that will have on the testa‐
bility and deployment of the application.
Improvements | 9
We can reset DEBUG to the default by removing the environment variable from the shell
or by starting a new shell.
hostname $ unset DEBUG
Reusable Template
So far this example has centered on rethinking the layout created by Django’s
startproject command. However, this command also allows for using a template to
provide the layout. It isn’t difficult to transform this file into a reusable template to start
future projects using the same base layout.
A template for startproject is a directory or zip file that is rendered as a Django
template when the command is run. By default, all of the Python source files will be
rendered as a template. The rendering is passed project_name, project_directory,
secret_key, and docs_version as the context. The names of the files will also be ren‐
dered with this context. To transform hello.py into a project template (project_name/
project_name.py), the relevant parts of the file need to be replaced by these variables.
import os
import sys
from django.conf import settings
DEBUG = os.environ.get('DEBUG', 'on') == 'on'
SECRET_KEY = os.environ.get('SECRET_KEY', '{{ secret_key }}')
ALLOWED_HOSTS = os.environ.get('ALLOWED_HOSTS', 'localhost').split(',')
settings.configure(
DEBUG=DEBUG,
SECRET_KEY=SECRET_KEY,
ALLOWED_HOSTS=ALLOWED_HOSTS,
ROOT_URLCONF=__name__,
MIDDLEWARE_CLASSES=(
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
),
)
from django.conf.urls import url
from django.core.wsgi import get_wsgi_application
from django.http import HttpResponse
def index(request):
return HttpResponse('Hello World')
10 | Chapter 1: The World’s Smallest Django Project
urlpatterns = (
url(r'^$', index),
)
application = get_wsgi_application()
if __name__ == "__main__":
from django.core.management import execute_from_command_line
execute_from_command_line(sys.argv)
Nowlet’ssavethisfileasproject_name.pyinadirectorycalledproject_name.Also,rather
than using os.urandom for the SECRET_KEY default, this code will generate a random
secret to be the default each time a new project is created. This makes the SECRET_KEY
default stable at the project level while still being sufficiently random across projects.
To use the template with startproject, you can use the --template argument.
hostname $ django-admin.py startproject foo --template=project_name
This should create a foo.py inside a foo directory, which is now ready to run just like the
original hello.py.
As outlined in this example, it is certainly possible to write and run a Django project
withouthavingtousethe startproject command.Thedefaultsettingsandlayoutused
by Django aren’t appropriate for every project. The --template option for
startproject can be used to either expand on these defaults or to trim them down, as
you’ve seen in this chapter.
AswithanyPythonproject,therecomesapointwhereorganizingthecodeintomultiple
modules is an important part of the process. For a sufficiently focused site, with only a
handful of URLs, our “Hello World” example may be a reasonable approach.
What is also interesting about this approach is that it isn’t immediately obvious that
Django has a templating engine or an object-relational mapper (ORM) built in. It is
clear that you are free to choose whatever Python libraries you think best solve your
problem.YounolongerhavetousetheDjangoORM,astheofficialtutorialmightimply.
Instead, you get to use the ORM if you want. The project in the next chapter will expand
on this single-file example to provide a simple HTTP service and make use of more of
the utilities that come with Django.
Improvements | 11
Lightweight Django 1st Edition Julia Elman
CHAPTER 2
Stateless Web Application
Most Django applications and tutorials center on some variety of user-generated con‐
tent, such as to-do lists, blogs, and content management systems. This isn’t surprising
given Django’s original roots in journalism.
In 2005, Django was originally developed at World Online in Lawrence, Kansas, as a
way for reporters to quickly create content for the Web. Since then, it has been used by
publishing organizations such as the Washington Post, the Guardian, PolitiFact, and
the Onion. This aspect of Django may give the impression that its main purpose is
content publishing, or that Django itself is a content management system. With large
organizations such as NASA adopting Django as their framework of choice, however,
Django has obviously outgrown its original purpose.
In the previous chapter we created a minimal project that made use only of Django’s
coreHTTPhandlingandURLrouting.Inthischapterwewillexpanduponthatexample
to create a stateless web application that uses more of Django’s utilities, such as input
validation, caching, and templates.
Why Stateless?
HTTP itself is a stateless protocol, meaning each request that comes to the server is
independent of the previous request. If a particular state is needed, it has to be added
at the application layer. Frameworks like Django use cookies and other mechanisms to
tie together requests made by the same client.
Alongwithapersistentsessionstoreontheserver,theapplicationcanthenhandletasks,
such as holding user authentication across requests. With that comes a number of chal‐
lenges, as this consistent state reads, and potentially writes, on every request in a dis‐
tributed server architecture.
13
As you can imagine, a stateless application does not maintain this consistent state on a
server. If authentication or other user credentials are required, then they must be passed
by the client on every request. This often makes scaling, caching, and load balancing
with stateless applications much easier. You can also make stateless applications easily
linkable because the URL can convey most of these states. There are two options we can
take, which we’ll outline in the next section: reusable apps and composable services.
Reusable Apps Versus Composable Services
Much of the focus in the Django community is about building reusable applications
that can be installed and configured into any Django project. However, large applica‐
tions with different components often have a fairly complex architectural structure.
An approach to combat this complexity is to break large websites into composable
services—that is, smaller services that communicate with one another. This doesn’t
mean that they can’t and won’t share code at some point. It does mean, however, that
each service can then be configured and built separately.
Stateless components, such as REST APIs, are great candidates for breaking out into
separate Django projects that can be deployed and tuned independently. Let’s build on
our Chapter 1 project by creating a placeholder image server using the two techniques
just described with Django.
Placeholder Image Server
Placeholder images are frequently used in application prototypes, example projects, or
testing environments. A typical placeholder image service will take a URL that indicates
the size of the image and generate that image. The URL may contain additional infor‐
mation, such as the color of the image or text to display within the image. Since every‐
thing that is needed to construct the requested image is contained within the URL, and
there’s little need for authentication, this makes a good candidate for a stateless appli‐
cation.
Start by creating a new project called placeholder with the startproject using the
project_name template created in Chapter 1.
hostname $ django-admin.py startproject placeholder --template=project_name
This will generate a placeholder.py file for us to begin building our service. If you have
used the project template correctly, placeholder.py should look like this:
import os
import sys
from django.conf import settings
DEBUG = os.environ.get('DEBUG', 'on') == 'on'
14 | Chapter 2: Stateless Web Application
SECRET_KEY = os.environ.get('SECRET_KEY',
'%jv_4#hoaqwig2gu!eg#^ozptd*a@88u(aasv7z!7xt^5(*i&k')
ALLOWED_HOSTS = os.environ.get('ALLOWED_HOSTS', 'localhost').split(',')
settings.configure(
DEBUG=DEBUG,
SECRET_KEY=SECRET_KEY,
ALLOWED_HOSTS=ALLOWED_HOSTS,
ROOT_URLCONF=__name__,
MIDDLEWARE_CLASSES=(
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
),
)
from django.conf.urls import url
from django.core.wsgi import get_wsgi_application
from django.http import HttpResponse
def index(request):
return HttpResponse('Hello World')
urlpatterns = (
url(r'^$', index),
)
application = get_wsgi_application()
if __name__ == "__main__":
from django.core.management import execute_from_command_line
execute_from_command_line(sys.argv)
The SECRET_KEY setting will be different from this published ver‐
sion, as it is randomly generated by the startproject command.
With our initial settings in place, we can now begin to write our views and start building
out the pages to create these responses.
Placeholder Image Server | 15
Views
Since this application will be simple, we will need only two views to generate our re‐
sponses. The first view will render the placeholder images based on their requested
width and height. The other view will render the home page content, which explains
how the project works and renders a few example images. Because we used Django’s --
template flag when running the startproject command, the index has already been
generated (as shown in this snippet from placeholder.py) and will need to be adapted
later.
...
def placeholder(request, width, height):
# TODO: Rest of the view will go here
return HttpResponse('Ok')
def index(request):
return HttpResponse('Hello World')
...
With these simple views in place, we should now think about the URL structure for
displaying our placeholders.
URL Patterns
When opening your generated placeholder.py file, you’ll notice that there is a URL pat‐
tern for the server root. We’ll also need a route to the placeholder view we just created.
The stub of the placeholder view will take two arguments: width and height. As men‐
tioned previously, those parameters will be captured by the URL and passed to the view.
Since they will only ever be integers, we’ll want to make sure to enforce them by the
URL. Since URL patterns in Django use regular expressions to match the incoming
URL, we’ll be able to easily pass in those parameters.
Captured pattern groups are passed to the view as positional arguments, and named
groups are passed as keyword arguments. Named groups are captured using the ?P
syntax, and any digit characters are matched by using [0-9].
This snippet from placeholder.py shows how your URL patterns will be laid out to gen‐
erate those values:
...
urlpatterns = (
url(r'^image/(?P<width>[0-9]+)x(?P<height>[0-9]+)/$', placeholder,
name='placeholder'),
url(r'^$', index, name='homepage'),
)
...
16 | Chapter 2: Stateless Web Application
Withthesepatternsinplace,incomingrequeststotheURL/image/30x25/willberouted
totheplaceholder viewandpassinthosevalues(e.g.,width=30 andheight=25).Along
with the new route for the placeholder view, the name homepage has been added to the
index router. We will also see how naming these URL patterns, while a good practice in
general, will be especially useful when we begin to build the templates later.
Placeholder View
Along with the original HTTP request, the placeholder view should accept two integer
arguments for the image’s height and width values. Though the regular expression will
ensure that the height and width consist of digits, they will be passed to the view as
strings. The view will need to convert them and may also want to validate that they are
a manageable size. We can easily do this by validating user input with Django forms.
Typically forms are used to validate POST and GET content, but they can also be used
tovalidateparticularvaluesfromtheURL,orthosestoredincookies.Hereisanexample
from placeholder.py of a simple form to validate the height and width of an image:
...
from django import forms
from django.conf.urls import url
...
class ImageForm(forms.Form):
"""Form to validate requested placeholder image."""
height = forms.IntegerField(min_value=1, max_value=2000)
width = forms.IntegerField(min_value=1, max_value=2000)
def placeholder(request, width, height):
...
As you can see, the first thing the view should do is validate the requested image size.
Iftheformisvalid,thentheheightandwidthcanbeaccessedintheform’scleaned_data
attribute. At this point, the height and width will be converted to integers, and the view
can be sure that the values are between 1 and 2000. We’ll also need to add validation to
the form to send an error message if the values are incorrect, as shown in this excerpt
from placeholder.py.
...
from django import forms
from django.conf.urls import url
from django.core.wsgi import get_wsgi_application
from django.http import HttpResponse, HttpResponseBadRequest
class ImageForm(forms.Form):
"""Form to validate requested placeholder image."""
Placeholder View | 17
height = forms.IntegerField(min_value=1, max_value=2000)
width = forms.IntegerField(min_value=1, max_value=2000)
def placeholder(request, width, height):
form = ImageForm({'height': height, 'width': width})
if form.is_valid():
height = form.cleaned_data['height']
width = form.cleaned_data['width']
# TODO: Generate image of requested size
return HttpResponse('Ok')
else:
return HttpResponseBadRequest('Invalid Image Request')
...
If the form isn’t valid, the view will send an error response to the client. Here the view
returns an HttpResponseBadRequest, which is a subclass of HttpResponse, and sends
a 400 Bad Request response.
Image Manipulation
The view now has the ability to accept and clean the height and width requested by the
client, but it does not yet generate the actual image. To handle image manipulation in
Python, you need to have Pillow installed as follows:
hostname $ pip install Pillow
By default, the install will try to compile Pillow from the source. If
you do not have a compiler installed for your environment, or you
are missing the necessary headers, it can fail to install. For installa‐
tion notes on various platforms, visit https://
pillow.readthedocs.org/en/latest/installation.html.
Creating an image with Pillow requires two arguments: the color mode and the size as
a tuple. This view from placeholder.py will use the RGB mode and the size from the form’s
cleaned data values. There is a third argument, which is not required, that sets the color
of the image. By default in Pillow, every pixel of the image will be black.
...
from io import BytesIO
from PIL import Image
...
class ImageForm(forms.Form):
"""Form to validate requested placeholder image."""
height = forms.IntegerField(min_value=1, max_value=2000)
width = forms.IntegerField(min_value=1, max_value=2000)
18 | Chapter 2: Stateless Web Application
def generate(self, image_format='PNG'):
"""Generate an image of the given type and return as raw bytes."""
height = self.cleaned_data['height']
width = self.cleaned_data['width']
image = Image.new('RGB', (width, height))
content = BytesIO()
image.save(content, image_format)
content.seek(0)
return content
def placeholder(request, width, height):
form = ImageForm({'height': height, 'width': width})
if form.is_valid():
image = form.generate()
return HttpResponse(image, content_type='image/png')
else:
return HttpResponseBadRequest('Invalid Image Request')
...
A new generate method has been added to the ImageForm to encapsulate the
logic of building the image. It takes one argument for the image format, which
defaults to PNG, and returns the image contents as bytes.
Using the width and height given by the URL and validated by the form, a new
image is constructed using the Image class from Pillow.
The view calls form.generate to get the constructed image, and the bytes for
the image are then used to construct the response body.
The form then validates the size to prevent requesting too large of an image and con‐
suming too many resources on the server. Once the image has been validated, the view
successfully returns the PNG image for the requested width and height. The image
content is sent to the client without writing it to the disk.
However, an all-black image, with no sizing information, is not a very stylish or useful
placeholder.WithPillow wecanaddthistexttotheimageusingtheImageDraw module,
as shown in this snippet from placeholder.py.
...
from PIL import Image, ImageDraw
...
class ImageForm(forms.Form):
...
def generate(self, image_format='PNG'):
"""Generate an image of the given type and return as raw bytes."""
height = self.cleaned_data['height']
width = self.cleaned_data['width']
image = Image.new('RGB', (width, height))
Placeholder View | 19
draw = ImageDraw.Draw(image)
text = '{} X {}'.format(width, height)
textwidth, textheight = draw.textsize(text)
if textwidth < width and textheight < height:
texttop = (height - textheight) // 2
textleft = (width - textwidth) // 2
draw.text((textleft, texttop), text, fill=(255, 255, 255))
content = BytesIO()
image.save(content, image_format)
content.seek(0)
return content
...
generate now uses ImageDraw to add a text overlay if it will fit.
Using ImageDraw, the form uses the current image to create text showing the width and
height on the image,
Now that we have our valid placeholder image in place, let’s add some caching to help
minimize requests to the server.
Adding Caching
The placeholder image view currently regenerates the image and serves it each time the
view is requested. Since the width and height of the image are set via the original, we
are constantly making unnecessary requests to our server.
One way to avoid this repetition is to use caching. There are two options to think about
when you’re determining how to utilize caching for this service: server-side and client-
side. For server-side caching, you can easily use Django’s cache utilities. This will trade
memory usage to store the cached values while saving the CPU cycles required to gen‐
erate the images, as shown in this excerpt from placeholder.py.
...
from django.conf.urls import url
from django.core.cache import cache
...
class ImageForm(forms.Form):
...
def generate(self, image_format='PNG'):
"""Generate an image of the given type and return as raw bytes."""
height = self.cleaned_data['height']
width = self.cleaned_data['width']
key = '{}.{}.{}'.format(width, height, image_format)
content = cache.get(key)
if content is None:
image = Image.new('RGB', (width, height))
draw = ImageDraw.Draw(image)
text = '{} X {}'.format(width, height)
textwidth, textheight = draw.textsize(text)
20 | Chapter 2: Stateless Web Application
if textwidth < width and textheight < height:
texttop = (height - textheight) // 2
textleft = (width - textwidth) // 2
draw.text((textleft, texttop), text, fill=(255, 255, 255))
content = BytesIO()
image.save(content, image_format)
content.seek(0)
cache.set(key, content, 60 * 60)
return content
A cache key is generated that depends on the width, height, and image format.
Before a new image is created, the cache is checked to see if the image is already
stored.
When there is a cache miss and a new image is created, the image is cached using
the key for an hour.
Django defaults to using a process-local, in-memory cache, but you could use a different
backend—such as Memcached or the file system—by configuring the CACHES setting.
A complementary approach is to focus on the client-side behavior and make use of the
browser’s built-in caching. Django includes an etag decorator for generating and using
theETagheadersfortheview.Thedecoratortakesasingleargument,whichisafunction
to generate the ETag header from the request and view arguments. Here is an example
from placeholder.py of how we would add that to our view:
import hashlib
import os
...
from django.http import HttpResponse, HttpResponseBadRequest
from django.views.decorators.http import etag
...
def generate_etag(request, width, height):
content = 'Placeholder: {0} x {1}'.format(width, height)
return hashlib.sha1(content.encode('utf-8')).hexdigest()
@etag(generate_etag)
def placeholder(request, width, height):
...
generate_etag is a new function that takes the same arguments as the
placeholder view. It uses hashlib to return an opaque ETag value, which will
vary based on the width and height values.
The generate_etag function will be passed to the etag decorator on the
placeholder view.
Placeholder View | 21
With this decorator in place, the server will need to generate the image the first time
the browser requests it. On subsequent requests, if the browser makes a request with
the matching ETag, the browser will receive a 304 Not Modified response for the image.
The browser will use the image from the cache and save bandwidth and time to regen‐
erate the HttpResponse.
This view generates an image based only on the width and height. If
other features were added, such as the background color or the im‐
age text, then the ETag generation would also need to be updated to
take these into account.
The django.middleware.common.CommonMiddleware, which is enabled in the
MIDDLEWARE_CLASSES setting, also has support for generating and using ETags if the
USE_ETAGS setting is enabled. However, there is a difference between how the middle‐
ware and the decorator work. The middleware will calculate the ETag based on the md5
hash of the response content. That requires the view to do all the work to generate the
content in order to calculate the hash. The result is the same in that the browser will
receive a 304 Not Modified response and the bandwidth will be saved. Using the etag
decorator has the advantage of calculating the ETag prior to the view being called, which
will also save on the processing time and resources.
The following is the completed placeholder view for placeholder.py, along with the
form and decorator functions:
...
class ImageForm(forms.Form):
"""Form to validate requested placeholder image."""
height = forms.IntegerField(min_value=1, max_value=2000)
width = forms.IntegerField(min_value=1, max_value=2000)
def generate(self, image_format='PNG'):
"""Generate an image of the given type and return as raw bytes."""
height = self.cleaned_data['height']
width = self.cleaned_data['width']
key = '{}.{}.{}'.format(width, height, image_format)
content = cache.get(key)
if content is None:
image = Image.new('RGB', (width, height))
draw = ImageDraw.Draw(image)
text = '{} X {}'.format(width, height)
textwidth, textheight = draw.textsize(text)
if textwidth < width and textheight < height:
texttop = (height - textheight) // 2
textleft = (width - textwidth) // 2
draw.text((textleft, texttop), text, fill=(255, 255, 255))
content = BytesIO()
22 | Chapter 2: Stateless Web Application
image.save(content, image_format)
content.seek(0)
cache.set(key, content, 60 * 60)
return content
def generate_etag(request, width, height):
content = 'Placeholder: {0} x {1}'.format(width, height)
return hashlib.sha1(content.encode('utf-8')).hexdigest()
@etag(generate_etag)
def placeholder(request, width, height):
form = ImageForm({'height': height, 'width': width})
if form.is_valid():
image = form.generate()
return HttpResponse(image, content_type='image/png')
else:
return HttpResponseBadRequest('Invalid Image Request')
...
With our placeholder view ready, let’s go back and build out our home page view to
complete our application.
Creating the Home Page View
The home page will render a basic HTML template to explain how the project works
and include some sample images. Up to this point, Django has not been configured to
render templates. It also has not been configured to serve static resources, such as Java‐
Script,CSS,andtemplates.Let’saddthenecessarysettingstoservethosestaticresources:
TEMPLATE_DIRS and STATICFILES_DIRS.
Adding Static and Template Settings
Django’s template loader will automatically discover templates and static resources in‐
sidetheinstalledapps.SincethisprojectdoesnotincludeanyDjangoapplications,these
locations need to be configured with the TEMPLATE_DIRS and STATICFILES_DIRS set‐
tings. django.contrib.staticfiles will also need to be added to the IN
STALLED_APPS for the {% static %} tag and collectstatic commands to be available.
Here is an example of how your directory structure should look at this point:
placeholder/
placeholder.py
The templates and static resources would fit nicely in directories next to placehold‐
er.py, as in:
placeholder/
placeholder.py
Creating the Home Page View | 23
templates/
home.html
static/
site.css
To avoid hardcoding these paths, we’ll be constructing them relative to the placehold‐
er.py file using the os module from the Python standard library.
import hashlib
import os
import sys
from django.conf import settings
DEBUG = os.environ.get('DEBUG', 'on') == 'on'
SECRET_KEY = os.environ.get('SECRET_KEY',
'%jv_4#hoaqwig2gu!eg#^ozptd*a@88u(aasv7z!7xt^5(*i&k')
BASE_DIR = os.path.dirname(__file__)
settings.configure(
DEBUG=DEBUG,
SECRET_KEY=SECRET_KEY,
ROOT_URLCONF=__name__,
MIDDLEWARE_CLASSES=(
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
),
INSTALLED_APPS=(
'django.contrib.staticfiles',
),
TEMPLATE_DIRS=(
os.path.join(BASE_DIR, 'templates'),
),
STATICFILES_DIRS=(
os.path.join(BASE_DIR, 'static'),
),
STATIC_URL='/static/',
...
Now let’s add a simple template structure to finish out this example project with a clean
frontend interface.
Home Page Template and CSS
The purpose of the home page for this application is to demonstrate how to use the
placeholder images with some brief documentation and examples. It should be saved
24 | Chapter 2: Stateless Web Application
as templates/home.html next to placeholder.py. We’ll also add in the src reference to our
placeholder route to request those images.
{% load staticfiles %}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Django Placeholder Images</title>
<link rel="stylesheet" href="{% static 'site.css' %}" type="text/css">
</head>
<body>
<h1>Django Placeholder Images</h1>
<p>This server can be used for serving placeholder
images for any web page.</p>
<p>To request a placeholder image of a given width and height
simply include an image with the source pointing to
<b>/placeholder/&lt;width&gt;x&lt;height&gt;/</b>
on this server such as:</p>
<pre>
&lt;img src="{{ example }}" &gt;
</pre>
<h2>Examples</h2>
<ul>
<li><img src="{% url 'placeholder' width=50 height=50 %}"></li>
<li><img src="{% url 'placeholder' width=100 height=50 %}"></li>
<li><img src="{% url 'placeholder' width=50 height=100 %}"></li>
<ul>
</body>
</html>
Here are some simple styles to add to site.css to help create a clean layout. Also, don’t
forget to save this file in your static/ folder, as previously outlined in your
STATICFILES_DIRS setting:
body {
text-align: center;
}
ul {
list-type: none;
}
li {
display: inline-block;
}
Creating the Home Page View | 25
You should save this as static/site.css next to placeholder.py, as outlined in the previous
section. Finally, we need to update the index view in placeholder.py to render this tem‐
plate:
...
from django.core.cache import cache
from django.core.urlresolvers import reverse
from django.core.wsgi import get_wsgi_application
from django.http import HttpResponse, HttpResponseBadRequest
from django.shortcuts import render
from django.views.decorators.http import etag
...
def index(request):
example = reverse('placeholder', kwargs={'width': 50, 'height':50})
context = {
'example': request.build_absolute_uri(example)
}
return render(request, 'home.html', context)
...
The updated index view builds an example URL by reversing the placeholder
view, and passes it to the template context.
The home.html template is rendered using the render shortcut.
Completed Project
Now you should have a completed placeholder.py file that looks similar to the following
one. Along with home.html and site.css from the previous section, it completes our
simple placeholder image service using Django:
import hashlib
import os
import sys
from io import BytesIO
from PIL import Image, ImageDraw
from django.conf import settings
DEBUG = os.environ.get('DEBUG', 'on') == 'on'
SECRET_KEY = os.environ.get('SECRET_KEY',
'%jv_4#hoaqwig2gu!eg#^ozptd*a@88u(aasv7z!7xt^5(*i&k')
ALLOWED_HOSTS = os.environ.get('ALLOWED_HOSTS', 'localhost').split(',')
BASE_DIR = os.path.dirname(__file__)
settings.configure(
DEBUG=DEBUG,
26 | Chapter 2: Stateless Web Application
SECRET_KEY=SECRET_KEY,
ALLOWED_HOSTS=ALLOWED_HOSTS,
ROOT_URLCONF=__name__,
MIDDLEWARE_CLASSES=(
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
),
INSTALLED_APPS=(
'django.contrib.staticfiles',
),
TEMPLATE_DIRS=(
os.path.join(BASE_DIR, 'templates'),
),
STATICFILES_DIRS=(
os.path.join(BASE_DIR, 'static'),
),
STATIC_URL='/static/',
)
from django import forms
from django.conf.urls import url
from django.core.cache import cache
from django.core.urlresolvers import reverse
from django.core.wsgi import get_wsgi_application
from django.http import HttpResponse, HttpResponseBadRequest
from django.shortcuts import render
from django.views.decorators.http import etag
class ImageForm(forms.Form):
"""Form to validate requested placeholder image."""
height = forms.IntegerField(min_value=1, max_value=2000)
width = forms.IntegerField(min_value=1, max_value=2000)
def generate(self, image_format='PNG'):
"""Generate an image of the given type and return as raw bytes."""
height = self.cleaned_data['height']
width = self.cleaned_data['width']
key = '{}.{}.{}'.format(width, height, image_format)
content = cache.get(key)
if content is None:
image = Image.new('RGB', (width, height))
draw = ImageDraw.Draw(image)
text = '{} X {}'.format(width, height)
textwidth, textheight = draw.textsize(text)
if textwidth < width and textheight < height:
texttop = (height - textheight) // 2
textleft = (width - textwidth) // 2
draw.text((textleft, texttop), text, fill=(255, 255, 255))
content = BytesIO()
Creating the Home Page View | 27
Another Random Scribd Document
with Unrelated Content
choir of young voices, and bid all prepare. A sacrifice will be offered
to Mitzor; the Great White Glory must be appeased.”
Alan and Sir John were very mystified over the whole scene. These
Jovians did not seem to understand Death—yet they spoke of
sacrifice!
“I am sorry, my son,” said the Jkak. “I can save nothing for you. All
must be burnt and offered to Mitzor. Come now, I will draw a ring
around the contaminated spot, and we will witness the destruction
from without.”
Sir John and Alan were both loth to have the Argenta burnt—but
being dependent on the Jovians for their entire future, they were
unable to demur. With a silent prayer for the friend who had given
his life for them, they left the ship and stood some way off. After an
interminable time of waiting, a mighty blast of music burst on their
ears, and they saw a procession of etheric bhors coming towards
them. The first stopped, and Misrath the High Priest alighted,
followed by priests and acolytes in quaint garments of ecclesiastical
cut.
A procession formed—two acolytes with censers led the way, and
wafted the glorious perfume from side to side. Then followed one of
the most mystical and picturesque ceremonies it was possible to
imagine. Almost of Mosaic grandeur, it thrilled the watchers. They
were unable to understand what was being said—all was in the
language of the Keemarnians—but the meaning was plain. The High
Priest offered the Argenta and its contents to Mitzor, the Great White
Glory. He offered it, with its fine workmanship, its precious metals—
and its body of sin. He asked that through the mediation of the
sacrifice, any evil might be averted, that the entrance of Death might
bring. He consecrated the Argenta to Mitzor—he consecrated the
ground it contaminated. He poured the “waters of purity” across its
bow, and named it “Meeka,” the Bringer of Knowledge.
Then the Argenta was sprayed from stem to stern with a milky
fluid that dried like little curds all over the vessel. A torch was lighted
and applied to the ship. Little flames ran along meeting each other
until they merged into one great whole; there was a roar and a noise
like thunder, and the Argenta, the hobby of a life time, the fruit of
patient labour, was no more!
Sir John watched with a set face, but as the fire died out, and he
saw that the whole had been swallowed up, had consumed itself
entirely,—he crumpled up, and lay inert upon the ground.
CHAPTER VI
THE SACRAMENT OF SCHLERIK-ITATA
Alan bent over his uncle, but the High Priest waved him away.
“Touch him not,” said he sternly, and such command rang in his
tones, that Alan stepped back involuntarily.
Again the scene was repeated—Sir John was prayed over, sprayed
with the “waters of purity,” and incensed. As the sweet fumes found
their way up his nostrils, he stirred. Alan rushed to him and
embraced him. “It was only foolishness, Alan,” said he brokenly. “But
the Argenta—my ship—I was so proud of her. Masters, you know how
I felt? She was my all in my days of sorrow. And in my days of joy,
when reunited we sailed in her, she was my joy.”
“I understand, Uncle John. But try not to mind—when one is in
Rome—you know the rest. We are in Jupiter and we must do as the
Jovians wish.”
Persoph the Jkak, came up to them. “Nay, grieve not,” said he
kindly. “We have cleared this place of sin. An air bird to take the
place of the one that has gone shall be placed at your disposal. Go
you home. Cards will be brought you for the Sacrament of Schlerik-
itata. I beg of you all—attend it. Nay, I command you. We will meet
again within eight Kymos. Farewell. Farewell.”
Waz-Y-Kjesta, motioned to their bhor. “Come, my friend,” said he.
“I will drive you back another way—we will drive along the shores of
the secti, and watch the breakers roll in.” The sea shore was
wonderful; the sea was blue, a deep, deep blue, and the breakers,
flecked with foam, rolled in to a golden shore. They passed bays,
promontories, caves and rocks—and they found the drive of
bewildering beauty.
Alan asked, “What is the Sacrament of Sch—”
“Schlerik-itata?” supplemented the Waz.
“Yes.”
“My friend, you must wait until you witness it. You will understand
us more fully when you have been to the home of Ak-Marn. Now to-
night, there is a small party being given by Kulmervan and his fellow
students at the Observatory. I have been asked to bring you all. Will
you come?”
“With pleasure,” said Alan.
“The Jkak is sending you all a complete outfit, my friend. Your
clothes are old, travel-stained and torn—they are sombre too. If you
accept his present, wear to-night your brightest garments.”
“Will you help me to adjust them?” asked Alan.
The Waz drew himself up with a haughty air, but it as soon passed.
“I was forgetting, my friend, that you know not our customs. The
serving men will assist you. When you reach home, you will find your
house fully staffed, and Quori, a most efficient steward and adviser.”
“What about meeting to-night for the party?”
“I will call for you as the Kymo sinks. You will have bhors sufficient
for your use.”
When they reached home they found a note awaiting them from
Mavis, asking them to come over and have lunch with her and
Desmond, and they walked through the garden to the other house.
Mavis was waiting for them, her cheeks dimpling and her eyes
sparkling. “It’s a wonderful country,” said she. “I’ve nothing to do all
day; the cooking and cleaning seem to go by clockwork. Morkaba is
Baby’s personal attendant and mine; she has arranged my frock.
How do you like it?” and she twirled round on one foot showing the
soft draperies of Keemarnian dress.
It was of a soft green, embroidered with coloured silks and her hair
was left loose flowing around her shoulders, and caught above her
ears by a narrow fillet of gold that gleamed as she tossed her head.
“I like it much better than the frumpy old English fashions,” said
she. “Desmond is not quite ready yet—he will look splendid.”
“We shall change later,” said Sir John, “and I shall be glad to get
out of these stuffy and dirty garments. All the same I don’t fancy
myself a cross between an imitation gladiator and a stained glass
twelfth century saint.”
They thoroughly enjoyed their meal; eggs served in a wonderful
salad of fruit and vegetables proved to be the staple part, and this
course was followed by a baked grain, similar to barley, but of a
bright green colour, deliciously creamy and sweet. There was milk to
drink, and plenty of heavy cream.
“They seem to be almost vegetarians here,” said Mavis, “for
although we have had plenty of milk, eggs and cream, I have not seen
a sign of fish or meat.”
“All the better,” said Sir John, “after all that tinned stuff while we
were on the Argenta—ugh!”
They drove in state to the students’ party. The Waz had constituted
himself their guide, and they were very thankful for his services. The
large ground floor of the Observatory had been converted into a
veritable bower of roses. At one end, almost hidden by flowers, were
the musicians—playing dreamy music on soft-toned, stringed
instruments.
The Host in Chief, Kulmervan, with Waiko, stood on a raised dais
at one end and received their guests, who were all announced by an
usher who wore a kilt-like shirt and a flowing cape. As the strangers
entered he announced from a card they gave him, first in his own
language and then in English, “Sir John, Alan, Desmond, Masters,
and Mavis.” No surnames were known on Jupiter, and so far they
possessed no Keemarnian title. To Sir John they gave his prefix,
although they did not quite understand it.
A great silence reigned when the announcement was made—
Kulmervan left the dais and advanced toward his guests, and this
mark of homage was acknowledged by clamorous cheers from all the
others who were present.
“Welcome,” said he. “I witnessed your descent upon our land.
Indeed, it was I who helped to focus our ray of attraction upon your
vessel and helped to draw you into our atmosphere.”
“What are your rays?” asked Alan. “Surely you had never any cause
to use one before?”
“Indeed, yes, my friend. Some time ago, some of our Keemarnians,
while experimenting in the Heavens, found themselves outside our
atmosphere. They never returned. Across the roadway between the
red planet ‘Mydot’—Mars I think you call it—and ourselves, are many
rapidly moving meteoric bodies. We fear that our gallant brothers
met one of these, and were destroyed. Many men of science went
after these lost ones but none ever returned. Through our wonderful
glass, we saw one of our air birds in space; it was unable to reach
home. Then was the great magnetic ray discovered. In the shortest
space of time it was perfected, and played on the silent air bird.
Gradually it was drawn nearer and nearer to our shores until it was
within our atmosphere, and was able to land in safety. Since that
time, if air birds venture too high, we have nearly always been able to
save the adventurous spirits, and in your case, we brought you safely
here.”
“It’s a wonderful invention,” said Sir John, “and I can imagine
would have been of immense value to our airmen on earth.”
Kulmervan then presented them to Waiko, and Mavis was led to a
seat of honour on the dais.
They spent a most enjoyable time, and the whole entertainment
was very like what they were accustomed to on earth. Games were
played,—games with balls and racquets, and balls and hoops, and
between the games there was singing and dancing.
Refreshments were served in a hall adjoining, and consisted
mainly of luscious fruits and dainty cakes and pastries. The many
Keemarnians they met, invited them in turn to parties and
entertainments, and they felt they had more invitations than they
could safely accept. “Never accept,” whispered Waz-Y-Kjesta to them
all, “unless you mean to honour your host with your presence. A
refusal never offends, but to accept and then to disappoint, is
unforgivable.” Suddenly in the middle of the dancing a trumpet blew
loud and clear. The band ceased and the couples stood still. Then
rang out a fanfare of royal welcome, and the guests rushed to the
entrance hall in great excitement, waving and cheering. “It must be
some one of importance who is coming,” said Desmond. “Perhaps it
is the Rorka,” suggested Mavis. There was a roll of drums, and then,
on a litter carried by six stalwart men, entered a girl of perhaps
eighteen years. The cortége stopped and Kulmervan bent low before
her, and kissed her proffered hand. She bowed ever so slightly, and
he assisted her from her cushioned throne. She stood beside him,
and proved to be quite small, not more than five feet in height, but of
a beauty almost indescribable. She was very fair and fragile. Her eyes
were purple-blue fringed with long, black lashes. Her fillet was of
gold, and was enriched with gems the colour of her eyes, while her
robe of blue hung in folds about her. Perhaps it was her lips that
impressed the watchers most. A perfect bow—they were of a vivid
scarlet that contrasted strangely with the delicate pink flush of her
cheeks. Self possessed, calm and regal she looked as she graciously
acknowledged the plaudits of the guests.
“Who is she, Alan?” asked Mavis. But he was unconscious of her
question, he could only gaze and gaze at the beautiful apparition who
had come so unexpectedly upon the scene.
Waiko bent in turn before the stranger who whispered something
to him. Immediately he came toward Mavis. “We are honoured to-
night,” said he. “The Ipso-Rorka Chlorie has journeyed from Pyrmo
to welcome you. She heard of your presence and came at once.”
“Who is she?” asked Mavis.
“Why the highest lady in the land—the only child of our Rorka.”
Mavis went toward where the girl stood, and the Ipso-Rorka held
out both her hands to the English girl. “Welcome,” said she, in a
voice musical and low. “I hear you start soon to honour the Rorka,
my father, with a visit. May I welcome you first?” In turn the others
were presented to her, but her attention was all for Mavis—it was
Mavis the woman she wanted to know.
And Alan? He had seen his ideal! Years before, he wondered
whether he would ever meet her—and now he had. And a King’s
daughter! And he a stranger in a strange world! How dare he even lift
his eyes toward her. Yet he dared—and his pulses leapt madly as his
eyes feasted on her beauty. Not once did she address him—not once
did she even seem to notice him. Chlorie put her hand lightly on
Desmond’s arm. “I will dance with you,” said she smiling, and Alan
watched them lead the merry throng of dancing couples. The demon
of jealousy, earth jealousy, was in his heart.
“Why are you looking so—how can I put it—so sad?” asked
Kulmervan.
Alan laughed. “He has a wife,” he muttered. “Why does he take her
from others?”
“But she has honoured him. It is not for us to choose for the Ipso-
Rorka,” said Kulmervan.
“Yes, but she is so beautiful, so sweet, so glorious,” began Alan.
Then he stopped suddenly. “Oh,” he continued, “what do you people
of Jupiter know of love or hate? Your lives are too quiet, too
humdrum to know aught of passion—”
“Teach me! Teach me!” cried Kulmervan leaning toward him.
“Your face is drawn—your eye hard. Yet you look as if you could
battle with the world. What is it?”
“Love and hate,” said Alan grimly. Then he laughed. “What a fool I
am. Desmond is my cousin; we love each other like brothers. He has
won Mavis—why should he not dance with the Ipso-Rorka? Mavis
does not mind.”
But Kulmervan turned away in silence. Knowledge had come to
him in a curious way. He saw passion, love, hatred, anger, jealousy
all raging within a human heart. Unconsciously the feelings were
photographed upon his too sensitive mind. Love that had only
smouldered was now born in all its fury for the Princess Chlorie, the
fair. And with love was born the twin, hate—hate for Alan, the man
he feared might supplant him.
It seemed as if death, although burned and purified, had brought
into Keemar unrest and sin. The prayers of the High Priest himself
were unable to wash it away, until scourged and purified the earth
folk themselves became less material and more godlike and true.
The day for the Sacrament of Schlerik-itata arrived at last and the
strangers found themselves on the way to Ak-Marn’s palace.
Although the Aks had no administrative powers, as had the Jkaks,
they were held in the highest esteem, for they were princes of royal
blood.
Ak-Marn greeted them warmly. They saw that his dress was
different from the usual male costume. He was in unrelieved white,
and wore neither jewel nor ornament. The material of his robe,
which hung with a long cloak to the ground, was almost like plush
and there was something almost bridal about the costume. Yet Ak-
Marn was an old man, with a beard of white, and grandchildren in
plenty. Surely Schlerik-itata could not be the same as matrimony,
thought Mavis.
The guests were eight thousand in number, and all wore their
brightest jewels and their finest raiment.
There was singing and dancing and much gay chatter, and the
whole scene was one of wonderful gaiety and joy. Refreshments were
brought in, and Ak-Marn began to speak. The English people could
now understand the Keemarnian language fairly well. It was easy, its
grammar simple, and its pronunciation almost Latin.
“Friends,” said Ak-Marn. “I break bread with you. Two and ten
Kymos have sunk since I quenched my thirst or satisfied my hunger.
I’ve prayed to Mitzor, the Great White Glory and Tower of Help, to
prepare me for my journey. My call came eighty and five Kymos since
—I saw the figures in fire. I heard my call, and am prepared. I go with
hope in my heart—with joy in my breast. I am to be envied, my
friends, for my days have been long upon Keemar. I leave my loved
one, Viok, and our children, and our children’s children in your care,
my friends. When I am gone, cheer her with loving words—help her
with kind counsel. I leave you with love in my heart. I leave you with
the knowledge that our parting is not for long. Soon you will join me
in the home of the Tower of Help. Remember that the eternities of
time cannot be measured.”
Then bread was broken, and there followed the “Feast of the
Sacrament,” and the most intimate friends of Ak-Marn drank to his
“future”—drank to his coming “joy.” And Alan and Sir John were no
longer mystified. They realized that what they in their materialism
knew as “Death” was nigh—but not Death, the slayer of happiness,
Death, the dread reaper, but Death in a kindly form, a death that
gave life—a death that was glorious.
“I thought at first that the Jovians were of a finer nature than
ours,” said Alan.
“If they have conquered Death, they must indeed be high,” said Sir
John thoughtfully.
“Who is Mitzor?” asked Mavis.
“The God of our Fathers, my dear. The God of Abraham and the
God of the New Testament. Whatever their religion and ritual is, they
worship the same God as we do,” said Alan.
“Are you sure?”
“Quite.”
When the feast was ended, the guests, one by one, bade farewell to
their host. It was a long tedious business, as no one was permitted to
pass without at least a few personal words from Ak-Marn who was
seated on a raised chair near the doorway. And as each woman
passed out, she was crowned with a wreath of beautiful, freshly cut
flowers, from which hung a filmy white veil, while the men were
given long white cloaks with hoods which they drew over their bare
heads. Mavis bent her knee, and held out her hands to the kindly old
man. “My child,” said he. “Our beautiful ceremony is so far
meaningless to you. Go home—pray to Mitzor the Mighty that He
may refine and cleanse you, that when your time comes you may be
reincarnated to Him, through the medium of his Sacrament.
Farewell.”
To Alan he spoke long and quietly. “My son,” said he, “you are in a
strange world, you are young, you are carnal. Ah,” as Alan would
have protested, “we of Keemar, my Alan, are not as of your world. We
know not sin as you know it. Our first parents, Menlin and Jorlar,
were placed in a garden—” Alan started—“Yes, my friend, as your
parents were. They succumbed not to temptation—so they lived in
happy solitude for many years. Then Mitzor in His great kindness
gave them the knowledge of Love—Love without sin. They mated.
Their love grew. Children of love were born sinless into our world.
Child bearing was a glory; motherhood the highest estate. They knew
neither sin nor sorrow, and so in love our populace grew.”
“Do you mean to say you are sinless here?” asked Alan
incredulously.
“My son, it is not an estate for us to glory in, for the merits do not
belong to us, but to our first parents. No—real sin has never entered
here, but we live in dread of its coming. In a far off country—in
Fyjipo—there is built a large palace behind high walls. If anger, or
lust, or impatience is shown by any one of us, an order is given and
the offender is taken to the Hall of Sorrows to purge away his sins.
Should a madness come upon us, for such we reckon these failings to
be—we are kept safe until it has passed, and until we can no longer
contaminate our fellow creatures.”
“It’s a wonderful country,” said Alan. “Where we come from, is all
sin and misery and—”
“Nay, tell me not. I go on a journey. I shall face my Mitzor. I charge
you, should you or your friends feel this madness coming on you,
hide yourselves, I beg, in the Hall of Sorrows. Stay there until it has
passed, and preserve the purity and happiness of this land.
Farewell.” The cloak was fastened round Alan’s shoulders, and he too
left the kindly presence.
Waz-Y-Kjesta was waiting for them at the outer hall. “Go home,”
he whispered. “Your bhor awaits you. I beg of you, eat no more this
night, but in the early dawn, while Kymo still sleeps, put on your
cloaks, and the Lady Mavis her veil, and go you to the Temple of
Mitzor. Farewell.” It was a very solemn party that retired to their
rooms that night, yet the full mystery of the Sacrament had not been
unfolded to them.
It was dark when they arose, and in a dim twilight they drove to
the Temple. They had never before been inside it, and it was with
much trepidation that they waited on the threshold. It was a very
beautiful building of pale blue marble—the colour of the sky. An
enormous dome rose up in the centre of the square body of the
Temple, and at the four corners, minarets with gilded tops finished
the picture. A flight of fifty steps led up to the doors which were of a
burnished metal, and studded with precious gems. Just inside was an
antechamber, where the guests waited in silence until they were
ushered to the seats that were allotted to them. The inside was
wonderful. Mosaic walls representing allegorical tales gleamed in the
dim light; the roof was of gold, and marble pillars supported it down
the long aisle. An enormous altar rose up at the further end upon
which were carved in marble cherubim and seraphim. In the
sanctuary, if such it could be called, was a small white throne of
marble, with heavy, white curtains draped at either side. It was
placed in such a position that although it did not intercept the view
of the altar, which was high above the nave, yet it could be seen by
every one in the building.
The seats allotted to Alan and his party were very near the front
where rails of gold separated the Sanctuary from the people’s part of
the Temple. Music floated on the air—soft like babbling brooks and
the song of birds; now bursting out into thunderous praise and
mighty worship.
Suddenly there came a solemn hush; a bell tinkled; the organ
played softly, and there came the sound of boys’ sweet voices raised
in ecstasy: from a door at the side of the choir a dozen acolytes
walked dressed in their garments of white. The procession started
down the nave. After these boys came priests and deacons, and then
Misrath, the High Priest walked in front of a raised throne. On this
sat Ak-Marn, his eyes closed and his hands clasped in prayer. Behind
him walked his wife and their children. Their faces were radiant, it is
true; yet there was a touch of sadness in his wife’s gait. Then followed
more priests and acolytes, all singing hymns of joy.
The procession wound round the Temple, and back through the
middle aisle, and through the rails into the Sanctuary. Ak-Marn was
led to the marble throne; his wife alone of his family had followed
close behind, and now his arms were around her. Their lips met in
one long kiss, then with a bowed head she left his side, and took her
place with her family in the very front seats.
The organ thundered. Voices rang in a mighty pæan of praise.
Then silence! Misrath came forward and offered prayers to Mitzor—
prayers of offering, prayers of supplication. A mighty wreath of
freshly cut flowers was placed upon the altar. It was to be a burnt
offering, and as the smoke of the sacrifice arose on the air, the white
curtains were drawn around the figure of Ak-Marn and he was
hidden from view. Then singing rent the air; the acolytes incensed
the throne, until it was entirely covered by the perfumed smoke,
covered like a pall.
Alan watched in wonder. The grandeur of the prayers, the singing,
the mystic curtains drawn around Ak-Marn appalled him. Misrath’s
voice rose above the music.
“Children of Keemar,” he intoned. “One more brother has been
caught by the mantle of Mitzor, and has left this world for ever. He
has gone to Glory, gone to Happiness—gone to Mitzor Himself. Peace
be unto his house. Peace be unto his wife. Peace be unto his seed for
ever. We bid him—farewell.”
There was a great silence. The censers were stilled. Gradually the
smoke of the incense cleared away from the marble throne, now
gleaming in the rising rays of the Kymo.
Misrath touched the cords of the enveloping curtain, and drew
them back. The little white throne was empty! Ak-Marn had returned
to the bosom of his Creator! But stay! On the floor, as if shed in the
hurried flight of its owner, lay the bridal robe of Ak-Marn. The High
Priest raised it, blessed it, sprinkled it with the waters of purity, and
Ak-Marn’s wife received it in her arms. Then the mighty
congregation rose and sang one last song of praise, and at the end,
quietly left the building. And the last view Alan had of Ak-Marn’s
wife was of a solitary figure, dressed like a bride, clasping the little
white throne that was the last resting place of her loved one.
“I don’t understand,” whispered Mavis hoarsely, as they were
being driven back to their home.
“My dear, he is dead,” said Sir John.
“Dead? If that is Death, then it is something to welcome and not to
dread,” she answered softly. There was a faraway look in her eyes.
“What a wonderful Sacrament! Death that is no sorrow—only a
parting for a little while, and then—reunion.” She clasped her
husband’s hand. “Belovèd,” she murmured, “if Death comes to us
like that, then can we have no real sorrow any more. Its shadow
cannot cause us pain or grief. What do you think, Alan?”
But Alan did not answer. He was thinking of two deep blue eyes, a
laughing mouth, wilful golden curls that flirted on two soft, pink
cheeks. He was longing to crush the lithe and sweet body close to his,
and smother her roses with kisses. The knowledge and fear of Death
had lapsed; Jupiter had eradicated it,—but with its extinction had
come love. Love, stronger a thousandfold than Death. He looked
upward to where the Sun, Kymo in all his glory, was shining. The
whole world was bathed in a glory of light. Yes, Jupiter had
conquered death, and before him lay life and love!
CHAPTER VII
HATRED ON KEEMAR
Marlinok, the Jkak’s majordomo, called on Sir John and Alan a
few days after they had witnessed the Sacrament of Schlerik-itata.
“Will you be ready,” he asked them, “when the Kymo is at the full, to
start on your journey to Hoormoori to render homage to the Rorka?”
“Are we all to go?” asked Alan.
“But one of you need go,” he answered. “The Rorka will visit
Minniviar later, and then the other strangers may make their bows.”
“I am glad of that,” said Sir John, “for I should like to stay here in
quietness and retirement for a little while. I am beginning to feel the
burden of my age, and am worn out with the strain of the last few
years.”
“I will go to Hoormoori,” announced Alan, “I can start at whatever
time the Jkak thinks best.”
“He has prepared incense and jewels for you to take as gifts from
the absent ones,” said Marlinok, “if you will now see Waz-Y-Kjesta all
your arrangements can be made.”
“I’ll go now,” said Alan.
Alan was going down a pretty lane toward where the air birds were
housed when he suddenly became aware of footsteps behind him. He
turned—immediately the footsteps ceased, and he could see no one.
Thinking he must be mistaken, and fearing nothing from the
Keemarnians, he went on his way blithely. The air was deliciously
warm, and the fresh breeze, balmy with the scent of flowers,
tempered it. Still the footsteps followed with monotonous regularity;
as he hastened, so they became quicker; as his died down, so they
ceased altogether. Yet he had no sense of fear, no feeling of
impending evil; the thought of peril on Keemar was impossible to
imagine. The Keemarnians were of a breed as different from the
earth to which he belonged, as he was from Heaven! He passed
delightful homely fields, gleaming with buttercups and daisies.
Friendly cows chewed the cud in sleepy enjoyment. They did not rise
as he drew near, but only raised their sleepy heads, and looked at
him out of their liquid eyes with interest and friendliness. A pig
grunted in a corner as she suckled her squealing young; a donkey
brayed; a couple of goats were nibbling the grass while their kids
frolicked near them. He saw strange animals too. There was the
gorwa of the deer family, a beautiful creature, the colour of a Scottish
stag, and its counterpart in miniature, but with none of its brother’s
timidity. All the animals on Keemar were of a smaller build than
those he had been accustomed to. The cows were even smaller then
the little fawn Jerseys so valued in England. He had seen terriers and
bull dogs, dalmatians and spaniels in this strange world, and the
bigger breeds were all represented on a smaller scale. The Jkak had a
dog—a Borzoi, Alan would have called it, yet perhaps it was no bigger
than a small Irish terrier; but strangely enough, its beauty was not
diminished by its minuteness. So Alan went on. The way was strange
to him, but he was enjoying the calmness of the scene, and he knew
his excellent bump of locality would sooner or later lead him to Y-
Kjesta. Again the footsteps beat time with his own, and anxious for
companionship, he stepped into the shadow of a tree, and hoped to
waylay a shy, but friendly stranger. A second passed. The footsteps
had ceased—then came a rustling, and the head of Kulmervan the
Student appeared over a honeysuckle bush. Silently he came
forward, alert and watchful until he was on a level with Alan.
“Hullo!” said Alan amiably. “Where are you going, Kulmervan?”
The effect was magical! Kulmervan jumped as though he had been
struck, and his face whitened. He remained silent. “I’m going to see
Waz-Y-Kjesta,” went on Alan. “Are you coming my way?”
Kulmervan did not reply, but a baleful light gleamed in his eyes,
and his mouth twitched.
“What’s the matter?” asked Alan curiously.
Suddenly Kulmervan spoke, and there was a wealth of passion in
his tones. “Why did you come here, you strangers? I was happy until
you came. I was contented. You have made me want—want the
unknown. You have stirred my heart and filled it with longings that I
cannot yet fathom. Why have you come to stir up misery among a
happy and contented race?”
“I don’t know what you mean,” said Alan, “I have done nothing.”
“You’ve done everything. You dared to raise your eyes to the level
of Chlorie, our Ipso-Rorka. You put thoughts about her into my head.
Oh—” as Alan would have broken in—“I read your thoughts, it was
easy, my friend. You dared to think of her as a woman—even your
woman. It was an impertinence, I tell you. I love Chlorie with my
whole soul, and before Mitzor the Mighty, I’ll carry her away into
some far off land, before she can look with a favourable eye on a
man, not only of another world, but a man of a coarser nature than
our own.”
Kulmervan was breathless when he finished, for his words had
come thick and fast, tumbling over themselves in his great
excitement. Alan was speechless, and looked as he felt, absolutely
uncomfortable and ill at ease. “Why your very pose proves guilt,”
continued Kulmervan.
“Why should I not love Chlorie?” demanded Alan, “Why should my
love for her cause strife between us?”
“Because, my stranger, I am a Prince of the Rorka’s House. I am
not only Kulmervan the Student; but Taz-Ak of the House of Pluthoz.
Why else would Chlorie have honoured my party—why else come to
the dance of a student? There are but four Keemarnians that Chlorie
can marry, and I rank second.”
Alan wondered at the time why the Princess should come in so
natural a manner to the Student’s reception. He wondered at the
time at her familiarity with Kulmervan. She had patted his hand,
smiled into his eyes, and had honoured him more than once with a
dance.
But Alan, too, was in love. Idiotically, insanely in love with a
woman who had not even troubled to raise her eyes to his, at his
presentation. His pulses throbbed at the remembrance of the touch
of her fingertips as he raised them to his lips. He loved her, and in
that moment was born a desire to overcome all obstacles, and
princess or no princess, to win her. But he knew too that in this
pleasant land of Keemar an enmity had come upon him, and
wondered whether the Curse of Death had brought it. He wondered
whether the dead and decomposed body of their faithful Murdoch
had indeed brought sorrow to this fair land.
“I’ve spoken to your Ipso-Rorka only once,” said he. “The night of
your party. She has called on my uncle and Mavis. Mavis has been
out driving with her several times. But I, unfortunately, have missed
her each time. Surely you are not jealous because I—”
“Because you love her? I am,” said Kulmervan thickly, “and I say
this—if you so much as dare to raise your eyes to her, if you dare to
address her, I’ll make you suffer for it—aye, even though I also suffer
eternally for it,” and with that he turned on his heel and walked
quickly away.
Alan was very perturbed about this meeting, and felt inclined to
tell the story of it to Waz-Y-Kjesta,—yet the sacred feeling he had for
Chlorie was not to be spoken of, or bandied about from man to man.
No, he would keep it to himself, and trust to time and common sense
to cure Kulmervan of his strange hatred.
He walked quickly on, and already could see the air birds in the
distance, circling above their houses. The little lane turned quickly at
right angles—there was a steep descent, and hedges rose at either
side to a height of six or seven feet, while the overhanging branches
of the trees met in the middle and formed a leafy arch. The grassy
banks were carpeted with flowers, and the scent hung sweet on the
air. Again the narrow path turned sharply to the right, and before
Alan realized it, there almost at his feet, stretched across almost the
full width of the path, lay a lion, full grown, with his shaggy mane
stirring in the breeze. Alan stopped suddenly, and his heart beat
quickly. The lion’s eyes were closed—he was sleeping.
The Englishman was almost afraid to move lest the savage beast
should spring upon him and devour him. He looked round to the
right, the bough of a tree hung low over the path. He leapt up the
bank, and with one mighty spring caught hold of it, and swarmed up
to a topmost branch.
He was safe—but the sudden sound had startled the lion, who rose
up and with a low growl prowled backward and forward beneath the
tree.
It was an uncomfortable position to be in—the tree bough was very
thin, and bent and twisted and crackled ominously. Still the King of
Beasts remained sentinel underneath. Alan felt the perspiration on
his face as the limb shivered and bent, yet there was no other to
which he could move. Still the animal remained near, his quickened
senses no doubt wondering at the noise he heard, and waiting to see
what had caused it.
The minutes dragged by—the branch was weakening perceptibly—
he could already see the white of the inside where the branch was
gradually tearing away from the parent trunk. There was no one in
sight, and still the lion walked restlessly to and fro.
The Kymo was sinking rapidly. It was already low down on the
horizon, and Alan knew he had been about two English hours in his
perilous position. He saw a branch above his head, and he wormed
his way along to see if he could in any way reach it. Carefully he went
—slowly—suddenly with a scream and a crash the branch gave way,
and Alan felt himself being hurled to the ground.
The distance was not great, and he landed in the centre of some
sweet-smelling, soft bushes. He was dazed, and wondered when the
lion would pounce. He knew he was powerless to help himself. He
heard the pad, pad, of its feet; he could hear the sharp intake of its
breath—then the thing was upon him. He shut his eyes and waited.—
Nothing happened but the snuffing of the wild beast, and a gentle
nosing as it examined the stranger.
Alan opened his eyes. The animal was sitting on its haunches
surveying him, and he felt there was amusement in the beast’s eyes
as it watched him. He moved slightly—still the beast watched
motionless. He raised himself up from the encircling bushes and
clambered down. He knew he would have to face the inevitable.
Suddenly a voice hailed him, and he saw Waz-Y-Kjesta coming
round the bend in the lane. “Stand back,” he cried. “There’s a lion
here—he may spring!” But the Waz came on fearlessly. Alan was
petrified, his tongue was parched, no sound came from his lips. He
watched the Waz in frozen horror.
The Keemarnian was smiling. “Where have you been, my friend?
You are late—very late. I thought you had missed your way, so I came
to seek you.” He was now within three feet of the lion. “What is the
matter? Why are you so grave? Has aught affrighted you?”
Alan pointed to the tawny beast. His hand was shaking. Surely the
farce must end soon, the lion spring, and tragedy culminate the play.
“Why Maquer,” said the Waz affectionately, “what are you doing
here? You seldom visit us, you know.”
The lion moved toward him, and rubbed his great head against the
Keemarnian’s leg, while Y-Kjesta talked to him and petted him.
“He’s tame then?” gasped Alan with a rush of relief. “You know
him?”
“No, my friend. I’ve never seen this Maquer before—they generally
stay in rocky places.”
“But he is so friendly.”
“All beasts are friendly here, my Alan. What—would Maquer have
hurt you on your Earth?”
And Alan laughingly told of his fright at the lion. He had learnt one
more truth about Keemar—there were no savage animals upon it. Of
a truth, it was a perfect land!
Waz-Y-Kjesta was highly amused at his friend’s story, and together
they went toward the air birds. The Keemarnian airships were indeed
wonderful creations. White and gold, they were shaped like swans,
with graceful wings outspread, gleaming in the light. They were
made of a mixture of wood and metal, and contained
accommodation for perhaps forty passengers, as well as the Waz in
command, and a staff of ten. Although not as big as the ill-fated
Argenta, the Keemarnian airship was possessed of a speed nearly
thrice as great.
“This is the Chlorie,” said Y-Kjesta, “and our fastest bird. The Jkak
has given orders that you are to choose your own vessel, so perhaps
you would like to see over some others?”
“No,” said Alan, looking at the blue hangings, and seeing in them
the reflection of his love’s eyes. “No, this one will do beautifully.” And
the Waz was impressed by the easy way in which his friend was
pleased. He little realized that it was the name of the vessel—the
Chlorie—that attracted him. And in the strangeness of it Alan tried to
read his fate.
“We’ll go for a short cruise,” said the Waz, “and go back to the
landing stage Minniviar.”
There was not a cloud in the sky, and the warmth from the sun’s
rays was pleasant.
“I can’t understand how you benefit so considerably from the sun,
your Kymo,” said Alan. “Let me see, you must be at least five times
further away from the sun than we were on our earth, yet instead of
your light and heat being reduced to about one twenty-fifth of our
supply, you appear to benefit to exactly the same degree.”
“Ah, my friend, that is easy to explain. Dark clouds hover outside
our globe—”
“Yes, bands of vapour,” corrected Alan.
“Well—vapour. These bands completely encircle our world. They
are saturated with a composition of gas, sulphuric ether I think you
would call it. Well, this gas acts as a trap to the sun’s rays. It admits
the solar rays to our planet but prevents their withdrawal. Therefore
it permits the heat to enter, but prevents its escape.”
“Well?”
“Consequently we get the maximum of light, and an equable
temperature.”
“Do you then, have no seasons here?”
“Seasons?”
“Yes, Spring or Winter.”
“Oh yes, it is cold at the poles—very cold, but as we get nearer to
the equator it becomes warmer, and hardly varies. You see, my Alan,
our world differs from yours. The axis of rotation is almost
perpendicular to our orbit, consequently we are not subject to
seasons as you were in Quilphis.”
“I didn’t know that before.”
“We too, are more flattened at each end—indeed, there are many
differences between our world that is, and yours that was.”
“Do you ever have rain here?”
“Yes, my Alan. How else would plants live and crops thrive? But
again, we do not suffer from excesses.”
“But don’t you have hurricanes that last from six to seven weeks?
Surely those are excesses.”
“Hurricanes? I do not know the word.”
Welcome to Our Bookstore - The Ultimate Destination for Book Lovers
Are you passionate about books and eager to explore new worlds of
knowledge? At our website, we offer a vast collection of books that
cater to every interest and age group. From classic literature to
specialized publications, self-help books, and children’s stories, we
have it all! Each book is a gateway to new adventures, helping you
expand your knowledge and nourish your soul
Experience Convenient and Enjoyable Book Shopping Our website is more
than just an online bookstore—it’s a bridge connecting readers to the
timeless values of culture and wisdom. With a sleek and user-friendly
interface and a smart search system, you can find your favorite books
quickly and easily. Enjoy special promotions, fast home delivery, and
a seamless shopping experience that saves you time and enhances your
love for reading.
Let us accompany you on the journey of exploring knowledge and
personal growth!
ebookgate.com
Ad

More Related Content

Similar to Lightweight Django 1st Edition Julia Elman (20)

Developing Backbone js Applications Addy Osmani
Developing Backbone js Applications Addy OsmaniDeveloping Backbone js Applications Addy Osmani
Developing Backbone js Applications Addy Osmani
leitaduminy
 
[Ebooks PDF] download AngularJS 1st Edition Brad Green full chapters
[Ebooks PDF] download AngularJS 1st Edition Brad Green full chapters[Ebooks PDF] download AngularJS 1st Edition Brad Green full chapters
[Ebooks PDF] download AngularJS 1st Edition Brad Green full chapters
kiciunonge
 
Developing Android Applications with Adobe AIR 1st Edition Véronique Brossier
Developing Android Applications with Adobe AIR 1st Edition Véronique BrossierDeveloping Android Applications with Adobe AIR 1st Edition Véronique Brossier
Developing Android Applications with Adobe AIR 1st Edition Véronique Brossier
joicyikoi
 
Exam Ref 70 486 Developing ASP NET MVC 4 Web Applications William Penberthy
Exam Ref 70 486 Developing ASP NET MVC 4 Web Applications William PenberthyExam Ref 70 486 Developing ASP NET MVC 4 Web Applications William Penberthy
Exam Ref 70 486 Developing ASP NET MVC 4 Web Applications William Penberthy
zeemetapa
 
Full Stack Serverless 1st Edition Nader Dabit
Full Stack Serverless 1st Edition Nader DabitFull Stack Serverless 1st Edition Nader Dabit
Full Stack Serverless 1st Edition Nader Dabit
ibokocazim
 
Full Stack Serverless 1st Edition Nader Dabit
Full Stack Serverless 1st Edition Nader DabitFull Stack Serverless 1st Edition Nader Dabit
Full Stack Serverless 1st Edition Nader Dabit
gwapateyei
 
Learning the iPhone SDK for JavaScript Programmers Create Native Apps with Ob...
Learning the iPhone SDK for JavaScript Programmers Create Native Apps with Ob...Learning the iPhone SDK for JavaScript Programmers Create Native Apps with Ob...
Learning the iPhone SDK for JavaScript Programmers Create Native Apps with Ob...
matbarnargis59
 
Programming iOS 4 Fundamentals of iPhone iPad and iPod Touch Development 1st ...
Programming iOS 4 Fundamentals of iPhone iPad and iPod Touch Development 1st ...Programming iOS 4 Fundamentals of iPhone iPad and iPod Touch Development 1st ...
Programming iOS 4 Fundamentals of iPhone iPad and iPod Touch Development 1st ...
assangkaoua
 
A Functional Approach to Java: Augmenting Object-Oriented Java Code with Func...
A Functional Approach to Java: Augmenting Object-Oriented Java Code with Func...A Functional Approach to Java: Augmenting Object-Oriented Java Code with Func...
A Functional Approach to Java: Augmenting Object-Oriented Java Code with Func...
romergalbowx
 
Learning Swift Building Apps for OSX, iOS, and Beyond Jon Manning
Learning Swift Building Apps for OSX, iOS, and Beyond Jon ManningLearning Swift Building Apps for OSX, iOS, and Beyond Jon Manning
Learning Swift Building Apps for OSX, iOS, and Beyond Jon Manning
batyegrocez1
 
Introduction to Django
Introduction to DjangoIntroduction to Django
Introduction to Django
Ahmed Salama
 
Mobile app development with Ionic cross platform apps with Ionic Angular and ...
Mobile app development with Ionic cross platform apps with Ionic Angular and ...Mobile app development with Ionic cross platform apps with Ionic Angular and ...
Mobile app development with Ionic cross platform apps with Ionic Angular and ...
sestayobstk2
 
Web Development in Django
Web Development in DjangoWeb Development in Django
Web Development in Django
Lakshman Prasad
 
Learning the iOS 4 SDK for JavaScript Programmers Create Native Apps with Obj...
Learning the iOS 4 SDK for JavaScript Programmers Create Native Apps with Obj...Learning the iOS 4 SDK for JavaScript Programmers Create Native Apps with Obj...
Learning the iOS 4 SDK for JavaScript Programmers Create Native Apps with Obj...
thoramenzab0
 
Learning Swift 3 Early release 3rd Edition Jonathan Manning
Learning Swift 3 Early release 3rd Edition Jonathan ManningLearning Swift 3 Early release 3rd Edition Jonathan Manning
Learning Swift 3 Early release 3rd Edition Jonathan Manning
nieysaiotti
 
Angular Up and Running Learning Angular Step by Step 1st Edition Shyam Seshadri
Angular Up and Running Learning Angular Step by Step 1st Edition Shyam SeshadriAngular Up and Running Learning Angular Step by Step 1st Edition Shyam Seshadri
Angular Up and Running Learning Angular Step by Step 1st Edition Shyam Seshadri
maneskortyjt
 
Using Docker Developing and Deploying Software with Containers 1st Edition Ad...
Using Docker Developing and Deploying Software with Containers 1st Edition Ad...Using Docker Developing and Deploying Software with Containers 1st Edition Ad...
Using Docker Developing and Deploying Software with Containers 1st Edition Ad...
abucdaroga
 
Final gatsby + wagtail - Inclusive product week
Final gatsby + wagtail - Inclusive product weekFinal gatsby + wagtail - Inclusive product week
Final gatsby + wagtail - Inclusive product week
Dawn Wages
 
Using Docker Developing and Deploying Software with Containers 1st Edition Ad...
Using Docker Developing and Deploying Software with Containers 1st Edition Ad...Using Docker Developing and Deploying Software with Containers 1st Edition Ad...
Using Docker Developing and Deploying Software with Containers 1st Edition Ad...
eljantnezar
 
Programming ASP NET MVC 4 Developing Real World Web Applications with ASP NET...
Programming ASP NET MVC 4 Developing Real World Web Applications with ASP NET...Programming ASP NET MVC 4 Developing Real World Web Applications with ASP NET...
Programming ASP NET MVC 4 Developing Real World Web Applications with ASP NET...
barbuhalahdl
 
Developing Backbone js Applications Addy Osmani
Developing Backbone js Applications Addy OsmaniDeveloping Backbone js Applications Addy Osmani
Developing Backbone js Applications Addy Osmani
leitaduminy
 
[Ebooks PDF] download AngularJS 1st Edition Brad Green full chapters
[Ebooks PDF] download AngularJS 1st Edition Brad Green full chapters[Ebooks PDF] download AngularJS 1st Edition Brad Green full chapters
[Ebooks PDF] download AngularJS 1st Edition Brad Green full chapters
kiciunonge
 
Developing Android Applications with Adobe AIR 1st Edition Véronique Brossier
Developing Android Applications with Adobe AIR 1st Edition Véronique BrossierDeveloping Android Applications with Adobe AIR 1st Edition Véronique Brossier
Developing Android Applications with Adobe AIR 1st Edition Véronique Brossier
joicyikoi
 
Exam Ref 70 486 Developing ASP NET MVC 4 Web Applications William Penberthy
Exam Ref 70 486 Developing ASP NET MVC 4 Web Applications William PenberthyExam Ref 70 486 Developing ASP NET MVC 4 Web Applications William Penberthy
Exam Ref 70 486 Developing ASP NET MVC 4 Web Applications William Penberthy
zeemetapa
 
Full Stack Serverless 1st Edition Nader Dabit
Full Stack Serverless 1st Edition Nader DabitFull Stack Serverless 1st Edition Nader Dabit
Full Stack Serverless 1st Edition Nader Dabit
ibokocazim
 
Full Stack Serverless 1st Edition Nader Dabit
Full Stack Serverless 1st Edition Nader DabitFull Stack Serverless 1st Edition Nader Dabit
Full Stack Serverless 1st Edition Nader Dabit
gwapateyei
 
Learning the iPhone SDK for JavaScript Programmers Create Native Apps with Ob...
Learning the iPhone SDK for JavaScript Programmers Create Native Apps with Ob...Learning the iPhone SDK for JavaScript Programmers Create Native Apps with Ob...
Learning the iPhone SDK for JavaScript Programmers Create Native Apps with Ob...
matbarnargis59
 
Programming iOS 4 Fundamentals of iPhone iPad and iPod Touch Development 1st ...
Programming iOS 4 Fundamentals of iPhone iPad and iPod Touch Development 1st ...Programming iOS 4 Fundamentals of iPhone iPad and iPod Touch Development 1st ...
Programming iOS 4 Fundamentals of iPhone iPad and iPod Touch Development 1st ...
assangkaoua
 
A Functional Approach to Java: Augmenting Object-Oriented Java Code with Func...
A Functional Approach to Java: Augmenting Object-Oriented Java Code with Func...A Functional Approach to Java: Augmenting Object-Oriented Java Code with Func...
A Functional Approach to Java: Augmenting Object-Oriented Java Code with Func...
romergalbowx
 
Learning Swift Building Apps for OSX, iOS, and Beyond Jon Manning
Learning Swift Building Apps for OSX, iOS, and Beyond Jon ManningLearning Swift Building Apps for OSX, iOS, and Beyond Jon Manning
Learning Swift Building Apps for OSX, iOS, and Beyond Jon Manning
batyegrocez1
 
Introduction to Django
Introduction to DjangoIntroduction to Django
Introduction to Django
Ahmed Salama
 
Mobile app development with Ionic cross platform apps with Ionic Angular and ...
Mobile app development with Ionic cross platform apps with Ionic Angular and ...Mobile app development with Ionic cross platform apps with Ionic Angular and ...
Mobile app development with Ionic cross platform apps with Ionic Angular and ...
sestayobstk2
 
Web Development in Django
Web Development in DjangoWeb Development in Django
Web Development in Django
Lakshman Prasad
 
Learning the iOS 4 SDK for JavaScript Programmers Create Native Apps with Obj...
Learning the iOS 4 SDK for JavaScript Programmers Create Native Apps with Obj...Learning the iOS 4 SDK for JavaScript Programmers Create Native Apps with Obj...
Learning the iOS 4 SDK for JavaScript Programmers Create Native Apps with Obj...
thoramenzab0
 
Learning Swift 3 Early release 3rd Edition Jonathan Manning
Learning Swift 3 Early release 3rd Edition Jonathan ManningLearning Swift 3 Early release 3rd Edition Jonathan Manning
Learning Swift 3 Early release 3rd Edition Jonathan Manning
nieysaiotti
 
Angular Up and Running Learning Angular Step by Step 1st Edition Shyam Seshadri
Angular Up and Running Learning Angular Step by Step 1st Edition Shyam SeshadriAngular Up and Running Learning Angular Step by Step 1st Edition Shyam Seshadri
Angular Up and Running Learning Angular Step by Step 1st Edition Shyam Seshadri
maneskortyjt
 
Using Docker Developing and Deploying Software with Containers 1st Edition Ad...
Using Docker Developing and Deploying Software with Containers 1st Edition Ad...Using Docker Developing and Deploying Software with Containers 1st Edition Ad...
Using Docker Developing and Deploying Software with Containers 1st Edition Ad...
abucdaroga
 
Final gatsby + wagtail - Inclusive product week
Final gatsby + wagtail - Inclusive product weekFinal gatsby + wagtail - Inclusive product week
Final gatsby + wagtail - Inclusive product week
Dawn Wages
 
Using Docker Developing and Deploying Software with Containers 1st Edition Ad...
Using Docker Developing and Deploying Software with Containers 1st Edition Ad...Using Docker Developing and Deploying Software with Containers 1st Edition Ad...
Using Docker Developing and Deploying Software with Containers 1st Edition Ad...
eljantnezar
 
Programming ASP NET MVC 4 Developing Real World Web Applications with ASP NET...
Programming ASP NET MVC 4 Developing Real World Web Applications with ASP NET...Programming ASP NET MVC 4 Developing Real World Web Applications with ASP NET...
Programming ASP NET MVC 4 Developing Real World Web Applications with ASP NET...
barbuhalahdl
 

Recently uploaded (20)

World war-1(Causes & impacts at a glance) PPT by Simanchala Sarab(BABed,sem-4...
World war-1(Causes & impacts at a glance) PPT by Simanchala Sarab(BABed,sem-4...World war-1(Causes & impacts at a glance) PPT by Simanchala Sarab(BABed,sem-4...
World war-1(Causes & impacts at a glance) PPT by Simanchala Sarab(BABed,sem-4...
larencebapu132
 
apa-style-referencing-visual-guide-2025.pdf
apa-style-referencing-visual-guide-2025.pdfapa-style-referencing-visual-guide-2025.pdf
apa-style-referencing-visual-guide-2025.pdf
Ishika Ghosh
 
How to track Cost and Revenue using Analytic Accounts in odoo Accounting, App...
How to track Cost and Revenue using Analytic Accounts in odoo Accounting, App...How to track Cost and Revenue using Analytic Accounts in odoo Accounting, App...
How to track Cost and Revenue using Analytic Accounts in odoo Accounting, App...
Celine George
 
How to Customize Your Financial Reports & Tax Reports With Odoo 17 Accounting
How to Customize Your Financial Reports & Tax Reports With Odoo 17 AccountingHow to Customize Your Financial Reports & Tax Reports With Odoo 17 Accounting
How to Customize Your Financial Reports & Tax Reports With Odoo 17 Accounting
Celine George
 
The ever evoilving world of science /7th class science curiosity /samyans aca...
The ever evoilving world of science /7th class science curiosity /samyans aca...The ever evoilving world of science /7th class science curiosity /samyans aca...
The ever evoilving world of science /7th class science curiosity /samyans aca...
Sandeep Swamy
 
Exploring-Substances-Acidic-Basic-and-Neutral.pdf
Exploring-Substances-Acidic-Basic-and-Neutral.pdfExploring-Substances-Acidic-Basic-and-Neutral.pdf
Exploring-Substances-Acidic-Basic-and-Neutral.pdf
Sandeep Swamy
 
Introduction to Vibe Coding and Vibe Engineering
Introduction to Vibe Coding and Vibe EngineeringIntroduction to Vibe Coding and Vibe Engineering
Introduction to Vibe Coding and Vibe Engineering
Damian T. Gordon
 
Handling Multiple Choice Responses: Fortune Effiong.pptx
Handling Multiple Choice Responses: Fortune Effiong.pptxHandling Multiple Choice Responses: Fortune Effiong.pptx
Handling Multiple Choice Responses: Fortune Effiong.pptx
AuthorAIDNationalRes
 
Understanding P–N Junction Semiconductors: A Beginner’s Guide
Understanding P–N Junction Semiconductors: A Beginner’s GuideUnderstanding P–N Junction Semiconductors: A Beginner’s Guide
Understanding P–N Junction Semiconductors: A Beginner’s Guide
GS Virdi
 
To study Digestive system of insect.pptx
To study Digestive system of insect.pptxTo study Digestive system of insect.pptx
To study Digestive system of insect.pptx
Arshad Shaikh
 
Biophysics Chapter 3 Methods of Studying Macromolecules.pdf
Biophysics Chapter 3 Methods of Studying Macromolecules.pdfBiophysics Chapter 3 Methods of Studying Macromolecules.pdf
Biophysics Chapter 3 Methods of Studying Macromolecules.pdf
PKLI-Institute of Nursing and Allied Health Sciences Lahore , Pakistan.
 
Geography Sem II Unit 1C Correlation of Geography with other school subjects
Geography Sem II Unit 1C Correlation of Geography with other school subjectsGeography Sem II Unit 1C Correlation of Geography with other school subjects
Geography Sem II Unit 1C Correlation of Geography with other school subjects
ProfDrShaikhImran
 
Sinhala_Male_Names.pdf Sinhala_Male_Name
Sinhala_Male_Names.pdf Sinhala_Male_NameSinhala_Male_Names.pdf Sinhala_Male_Name
Sinhala_Male_Names.pdf Sinhala_Male_Name
keshanf79
 
Stein, Hunt, Green letter to Congress April 2025
Stein, Hunt, Green letter to Congress April 2025Stein, Hunt, Green letter to Congress April 2025
Stein, Hunt, Green letter to Congress April 2025
Mebane Rash
 
Presentation of the MIPLM subject matter expert Erdem Kaya
Presentation of the MIPLM subject matter expert Erdem KayaPresentation of the MIPLM subject matter expert Erdem Kaya
Presentation of the MIPLM subject matter expert Erdem Kaya
MIPLM
 
Social Problem-Unemployment .pptx notes for Physiotherapy Students
Social Problem-Unemployment .pptx notes for Physiotherapy StudentsSocial Problem-Unemployment .pptx notes for Physiotherapy Students
Social Problem-Unemployment .pptx notes for Physiotherapy Students
DrNidhiAgarwal
 
CBSE - Grade 8 - Science - Chemistry - Metals and Non Metals - Worksheet
CBSE - Grade 8 - Science - Chemistry - Metals and Non Metals - WorksheetCBSE - Grade 8 - Science - Chemistry - Metals and Non Metals - Worksheet
CBSE - Grade 8 - Science - Chemistry - Metals and Non Metals - Worksheet
Sritoma Majumder
 
Presentation on Tourism Product Development By Md Shaifullar Rabbi
Presentation on Tourism Product Development By Md Shaifullar RabbiPresentation on Tourism Product Development By Md Shaifullar Rabbi
Presentation on Tourism Product Development By Md Shaifullar Rabbi
Md Shaifullar Rabbi
 
P-glycoprotein pamphlet: iteration 4 of 4 final
P-glycoprotein pamphlet: iteration 4 of 4 finalP-glycoprotein pamphlet: iteration 4 of 4 final
P-glycoprotein pamphlet: iteration 4 of 4 final
bs22n2s
 
Operations Management (Dr. Abdulfatah Salem).pdf
Operations Management (Dr. Abdulfatah Salem).pdfOperations Management (Dr. Abdulfatah Salem).pdf
Operations Management (Dr. Abdulfatah Salem).pdf
Arab Academy for Science, Technology and Maritime Transport
 
World war-1(Causes & impacts at a glance) PPT by Simanchala Sarab(BABed,sem-4...
World war-1(Causes & impacts at a glance) PPT by Simanchala Sarab(BABed,sem-4...World war-1(Causes & impacts at a glance) PPT by Simanchala Sarab(BABed,sem-4...
World war-1(Causes & impacts at a glance) PPT by Simanchala Sarab(BABed,sem-4...
larencebapu132
 
apa-style-referencing-visual-guide-2025.pdf
apa-style-referencing-visual-guide-2025.pdfapa-style-referencing-visual-guide-2025.pdf
apa-style-referencing-visual-guide-2025.pdf
Ishika Ghosh
 
How to track Cost and Revenue using Analytic Accounts in odoo Accounting, App...
How to track Cost and Revenue using Analytic Accounts in odoo Accounting, App...How to track Cost and Revenue using Analytic Accounts in odoo Accounting, App...
How to track Cost and Revenue using Analytic Accounts in odoo Accounting, App...
Celine George
 
How to Customize Your Financial Reports & Tax Reports With Odoo 17 Accounting
How to Customize Your Financial Reports & Tax Reports With Odoo 17 AccountingHow to Customize Your Financial Reports & Tax Reports With Odoo 17 Accounting
How to Customize Your Financial Reports & Tax Reports With Odoo 17 Accounting
Celine George
 
The ever evoilving world of science /7th class science curiosity /samyans aca...
The ever evoilving world of science /7th class science curiosity /samyans aca...The ever evoilving world of science /7th class science curiosity /samyans aca...
The ever evoilving world of science /7th class science curiosity /samyans aca...
Sandeep Swamy
 
Exploring-Substances-Acidic-Basic-and-Neutral.pdf
Exploring-Substances-Acidic-Basic-and-Neutral.pdfExploring-Substances-Acidic-Basic-and-Neutral.pdf
Exploring-Substances-Acidic-Basic-and-Neutral.pdf
Sandeep Swamy
 
Introduction to Vibe Coding and Vibe Engineering
Introduction to Vibe Coding and Vibe EngineeringIntroduction to Vibe Coding and Vibe Engineering
Introduction to Vibe Coding and Vibe Engineering
Damian T. Gordon
 
Handling Multiple Choice Responses: Fortune Effiong.pptx
Handling Multiple Choice Responses: Fortune Effiong.pptxHandling Multiple Choice Responses: Fortune Effiong.pptx
Handling Multiple Choice Responses: Fortune Effiong.pptx
AuthorAIDNationalRes
 
Understanding P–N Junction Semiconductors: A Beginner’s Guide
Understanding P–N Junction Semiconductors: A Beginner’s GuideUnderstanding P–N Junction Semiconductors: A Beginner’s Guide
Understanding P–N Junction Semiconductors: A Beginner’s Guide
GS Virdi
 
To study Digestive system of insect.pptx
To study Digestive system of insect.pptxTo study Digestive system of insect.pptx
To study Digestive system of insect.pptx
Arshad Shaikh
 
Geography Sem II Unit 1C Correlation of Geography with other school subjects
Geography Sem II Unit 1C Correlation of Geography with other school subjectsGeography Sem II Unit 1C Correlation of Geography with other school subjects
Geography Sem II Unit 1C Correlation of Geography with other school subjects
ProfDrShaikhImran
 
Sinhala_Male_Names.pdf Sinhala_Male_Name
Sinhala_Male_Names.pdf Sinhala_Male_NameSinhala_Male_Names.pdf Sinhala_Male_Name
Sinhala_Male_Names.pdf Sinhala_Male_Name
keshanf79
 
Stein, Hunt, Green letter to Congress April 2025
Stein, Hunt, Green letter to Congress April 2025Stein, Hunt, Green letter to Congress April 2025
Stein, Hunt, Green letter to Congress April 2025
Mebane Rash
 
Presentation of the MIPLM subject matter expert Erdem Kaya
Presentation of the MIPLM subject matter expert Erdem KayaPresentation of the MIPLM subject matter expert Erdem Kaya
Presentation of the MIPLM subject matter expert Erdem Kaya
MIPLM
 
Social Problem-Unemployment .pptx notes for Physiotherapy Students
Social Problem-Unemployment .pptx notes for Physiotherapy StudentsSocial Problem-Unemployment .pptx notes for Physiotherapy Students
Social Problem-Unemployment .pptx notes for Physiotherapy Students
DrNidhiAgarwal
 
CBSE - Grade 8 - Science - Chemistry - Metals and Non Metals - Worksheet
CBSE - Grade 8 - Science - Chemistry - Metals and Non Metals - WorksheetCBSE - Grade 8 - Science - Chemistry - Metals and Non Metals - Worksheet
CBSE - Grade 8 - Science - Chemistry - Metals and Non Metals - Worksheet
Sritoma Majumder
 
Presentation on Tourism Product Development By Md Shaifullar Rabbi
Presentation on Tourism Product Development By Md Shaifullar RabbiPresentation on Tourism Product Development By Md Shaifullar Rabbi
Presentation on Tourism Product Development By Md Shaifullar Rabbi
Md Shaifullar Rabbi
 
P-glycoprotein pamphlet: iteration 4 of 4 final
P-glycoprotein pamphlet: iteration 4 of 4 finalP-glycoprotein pamphlet: iteration 4 of 4 final
P-glycoprotein pamphlet: iteration 4 of 4 final
bs22n2s
 
Ad

Lightweight Django 1st Edition Julia Elman

  • 1. Lightweight Django 1st Edition Julia Elman pdf download https://ebookgate.com/product/lightweight-django-1st-edition- julia-elman/ Get Instant Ebook Downloads – Browse at https://ebookgate.com
  • 2. Instant digital products (PDF, ePub, MOBI) available Download now and explore formats that suit you... Mastering Django Core 1st Edition Nigel George https://ebookgate.com/product/mastering-django-core-1st-edition-nigel- george/ ebookgate.com Pro Django 2nd Edition Marty Alchin https://ebookgate.com/product/pro-django-2nd-edition-marty-alchin/ ebookgate.com Web Development with Django Cookbook Bendoraitis https://ebookgate.com/product/web-development-with-django-cookbook- bendoraitis/ ebookgate.com Beginning Django E Commerce 1st Edition Jim Mcgaw (Auth.) https://ebookgate.com/product/beginning-django-e-commerce-1st-edition- jim-mcgaw-auth/ ebookgate.com
  • 3. The Lightweight Treated Soil Method 1st Edition Takashi Tsuchida https://ebookgate.com/product/the-lightweight-treated-soil-method-1st- edition-takashi-tsuchida/ ebookgate.com Superworm Julia Donaldson https://ebookgate.com/product/superworm-julia-donaldson/ ebookgate.com Flexible Manufacture of Lightweight Frame Structures Proceedings Kleiner https://ebookgate.com/product/flexible-manufacture-of-lightweight- frame-structures-proceedings-kleiner/ ebookgate.com Radiology Strategies 1st Edition Julia Fielding https://ebookgate.com/product/radiology-strategies-1st-edition-julia- fielding/ ebookgate.com Nature Anatomy Julia Rothman https://ebookgate.com/product/nature-anatomy-julia-rothman/ ebookgate.com
  • 5. Julia Elman & Mark Lavin Lightweight Django USING REST, WEBSOCKETS & BACKBONE
  • 6. PYTHON/WEB DEVELOPMENT Lightweight Django ISBN: 978-1-491-94594-0 US $39.99 CAN $41.99 “A great resource for going beyond traditional apps and learning how Django can power the backend of single-page web applications.” —Aymeric Augustin Django core developer, CTO, oscaro.com “Such a good idea—I think this will lower the barrier of entry for developers even more… the more I read, the more excited I am!” —Barbara Shaurette Python Developer, Cox Media Group Twitter: @oreillymedia facebook.com/oreilly Howcanyoutakeadvantageof theDjangoframework tointegratecomplex client-side interactions and real-time features into your web applications? Through a series of rapid application development projects, this hands-on book shows experienced Django developers how to include REST APIs, WebSockets, and client-side MVC frameworks such as Backbone.js into new or existing projects. Learn how to make the most of Django’s decoupled design by choosing the components you need to build the lightweight applications you want. Once you finish this book, you’ll know how to build single-page applications that respond to interactions in real time. If you’re familiar with Python and JavaScript, you’re good to go. ■ ■ Learn a lightweight approach for starting a new Django project ■ ■ Break reusable applications into smaller services that communicate with one another ■ ■ Create a static, rapid prototyping site as a scaffold for websites and applications ■ ■ Build a REST API with django-rest-framework ■ ■ Learn how to use Django with the Backbone.js MVC framework ■ ■ Create a single-page web application on top of your REST API ■ ■ Integrate real-time features with WebSockets and the Tornado networking library ■ ■ Use the book’s code-driven examples in your own projects Julia Elman, a frontend developer and tech education advocate, started learning Django in 2008 while working at World Online. She is one of the co-founders for Girl Develop It RDU and PyLadies RDU, organizations that have helped over 850 women learn to program. Mark Lavin is Technical Director at Caktus Consulting Group in Durham, North Carolina. He came to Python web development after years of pricing derivatives on Wall Street. Mark maintains several open source projects related to Django development. Lightweight Django Elman & Lavin Julia Elman & Mark Lavin Lightweight Django USING REST, WEBSOCKETS & BACKBONE
  • 7. Julia Elman and Mark Lavin Lightweight Django
  • 8. Lightweight Django by Julia Elman and Mark Lavin Copyright © 2015 Julia Elman and Mark Lavin. All rights reserved. Printed in the United States of America. Published by O’Reilly Media, Inc., 1005 Gravenstein Highway North, Sebastopol, CA 95472. O’Reilly books may be purchased for educational, business, or sales promotional use. Online editions are also available for most titles (http://safaribooksonline.com). For more information, contact our corporate/ institutional sales department: 800-998-9938 or [email protected]. Editor: Meghan Blanchette Production Editor: Colleen Lobner Copyeditor: Rachel Monaghan Proofreader: Sonia Saruba Indexer: Wendy Catalano Cover Designer: Ellie Volckhausen Interior Designer: David Futato Illustrator: Rebecca Demarest November 2014: First Edition Revision History for the First Edition: 2014-10-24: First release See http://oreilly.com/catalog/errata.csp?isbn=9781491945940 for release details. The O’Reilly logo is a registered trademark of O’Reilly Media, Inc. Lightweight Django, the cover image, and related trade dress are trademarks of O’Reilly Media, Inc. Many of the designations used by manufacturers and sellers to distinguish their products are claimed as trademarks.Wherethosedesignationsappearinthisbook,andO’ReillyMedia,Inc.wasawareofatrademark claim, the designations have been printed in caps or initial caps. While the publisher and the authors have used good faith efforts to ensure that the information and in‐ structions contained in this work are accurate, the publisher and the authors disclaim all responsibility for errors or omissions, including without limitation responsibility for damages resulting from the use of or reliance on this work. Use of the information and instructions contained in this work is at your own risk. If any code samples or other technology this work contains or describes is subject to open source licenses or the intellectual property rights of others, it is your responsibility to ensure that your use thereof complies with such licenses and/or rights. ISBN: 978-1-491-94594-0 LSI
  • 9. Table of Contents Preface. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . vii Prerequisites. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . xiii 1. The World’s Smallest Django Project. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1 Hello Django 1 Creating the View 2 The URL Patterns 2 The Settings 3 Running the Example 4 Improvements 5 WSGI Application 6 Additional Configuration 7 Reusable Template 10 2. Stateless Web Application. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13 Why Stateless? 13 Reusable Apps Versus Composable Services 14 Placeholder Image Server 14 Views 16 URL Patterns 16 Placeholder View 17 Image Manipulation 18 Adding Caching 20 Creating the Home Page View 23 Adding Static and Template Settings 23 Home Page Template and CSS 24 Completed Project 26 iii
  • 10. 3. Building a Static Site Generator. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31 Creating Static Sites with Django 31 What Is Rapid Prototyping? 32 Initial Project Layout 32 File/Folder Scaffolding 32 Basic Settings 33 Page Rendering 35 Creating Our Base Templates 35 Static Page Generator 36 Basic Styling 39 Prototype Layouts and Navigation 41 Generating Static Content 46 Settings Configuration 46 Custom Management Command 47 Building a Single Page 49 Serving and Compressing Static Files 50 Hashing Our CSS and JavaScript Files 50 Compressing Our Static Files 51 Generating Dynamic Content 54 Updating Our Templates 54 Adding Metadata 56 4. Building a REST API. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 61 Django and REST 61 Scrum Board Data Map 62 Initial Project Layout 63 Project Settings 64 No Django Admin? 66 Models 66 Designing the API 69 Sprint Endpoints 69 Task and User Endpoints 71 Connecting to the Router 74 Linking Resources 74 Testing Out the API 77 Using the Browsable API 77 Adding Filtering 81 Adding Validations 86 Using a Python Client 89 Next Steps 91 iv | Table of Contents
  • 11. 5. Client-Side Django with Backbone.js. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 93 Brief Overview of Backbone 94 Setting Up Your Project Files 95 JavaScript Dependencies 96 Organization of Your Backbone Application Files 98 Connecting Backbone to Django 100 Client-Side Backbone Routing 102 Creating a Basic Home Page View 102 Setting Up a Minimal Router 103 Using _.template from Underscore.js 104 Building User Authentication 107 Creating a Session Model 107 Creating a Login View 111 Generic Form View 117 Authenticating Routes 120 Creating a Header View 121 6. Single-Page Web Application. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 131 What Are Single-Page Web Applications? 131 Discovering the API 132 Fetching the API 132 Model Customizations 133 Collection Customizations 134 Building Our Home Page 135 Displaying the Current Sprints 135 Creating New Sprints 138 Sprint Detail Page 141 Rendering the Sprint 141 Routing the Sprint Detail 143 Using the Client State 144 Rendering the Tasks 146 AddTaskView 153 CRUD Tasks 156 Rendering Tasks Within a Sprint 156 Updating Tasks 160 Inline Edit Features 163 7. Real-Time Django. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 167 HTML5 Real-Time APIs 167 Websockets 168 Server-Sent Events 168 WebRTC 169 Table of Contents | v
  • 12. Websockets with Tornado 169 Introduction to Tornado 170 Message Subscriptions 175 Client Communication 178 Minimal Example 179 Socket Wrapper 182 Client Connection 185 Sending Events from the Client 187 Handling Events from the Client 193 Updating Task State 195 8. Communication Between Django and Tornado. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 199 Receiving Updates in Tornado 199 Sending Updates from Django 201 Handling Updates on the Client 203 Server Improvements 204 Robust Subscriptions 204 Websocket Authentication 208 Better Updates 212 Secure Updates 214 Final Websocket Server 217 Index. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 223 vi | Table of Contents
  • 13. Preface Since the creation of Django, a plethora of web frameworks have been created in various open source communities. Frontend-focused web frameworks such as Angular.js, Em‐ ber.js, and Backbone.js have come out of the JavaScript community and become fore‐ runners in modern web development. Where does Django fit into all of this? How can we integrate these client-side MVC frameworks into our current Django infrastructure? Lightweight Django teaches you how to take advantage of Django’s Pythonic “batteries included” philosophy. Its aim is to guide you through misconceptions that Django is too “heavy” for rapid application development. From creating the world’s smallest DjangoapplicationtobuildingaRESTfulAPI,LightweightDjangowillwalkyouthrough how to take advantage of this popular Python web framework. Why This Book? We wanted to write this book primarily because we love Django. The community is amazing, and there are so many resources to learn about Django and to develop appli‐ cations using it. However, we also felt like many of these resources, including the official Django documentation, put too much emphasis on the power of Django and not on its decoupled design. Django is a well-written framework, with numerous utilities for building web applications included. What we want this book to highlight is how you can break apart and potentially replace these components to pick and choose what best suits the application you want to build. Similarly, we wanted to break down the typical structure of Django projects and applications. Our goal is to get you to stop asking “how do I do X in Django?” and instead ask “does Django provide anything to help me do X, and if not, is something available in the community?” In addition, we wanted to answer questions about where Django fits in a Web in which more applications are built with heavy client-side interactions and real-time compo‐ nents, and paired with native mobile applications. As a framework, Django is agnostic about the client, which leaves some users feeling like Django doesn’t have an answer for vii
  • 14. building these types of applications. We hope that this book can help shape how the community approaches these types of problems. We want to see Django and its com‐ munity continue to grow, and we want to be a part of it for many more years to come. Who Should Read This Book? If you are interested in reading this book, you are most likely an intermediate Django user. You’ve gone through the Django polls tutorial, as well as written a few basic Django web applications, and are now wondering what the next steps are. Lightweight Django serves as that next step to help outline how to utilize Django’s utilities and simplicity. Or you might be currently working on a Django project and wondering how to integrate something like Backbone.js into your project. Lightweight Django will teach you some best practices for integration and will give you a jumping-off point for building content- rich web applications. Who Should Not Read This Book? While we feel that Lightweight Django is beneficial to developers from many back‐ grounds, there might be certain people who won’t find this book interesting. For those of you who do not find writing Python and/or JavaScript pleasurable, this book is most likely not for you. All of the concepts and examples revolve around these languages, and they will be heavily used throughout each chapter. We also don’t recommend this book for those who are brand new to Django. About the Examples Each of the example projects has been carefully crafted under the theme of rapid ap‐ plication development. In each chapter, you’ll learn how to build projects that assist withprojectmanagement,tools,andteamcollaboration.Wewantedourreaderstobuild projects that they find useful and can customize for their own use. In general, if example code is offered with this book, you may use it in your programs and documentation. You do not need to contact us for permission unless you’re reproducing a significant portion of the code. For example, writing a program that uses several chunks of code from this book does not require permission. Selling or distributing a CD-ROM of ex‐ amples from O’Reilly books does require permission. Answering a question by citing this book and quoting example code does not require permission. Incorporating a sig‐ nificant amount of example code from this book into your product’s documentation does require permission. The code samples for this title can be found here: https://github.com/lightweightdjango/ examples. viii | Preface
  • 15. We appreciate, but do not require, attribution. An attribution usually includes the title, author,publisher,andISBN.Forexample:“LightweightDjangobyJuliaElmanandMark Lavin (O’Reilly). Copyright 2015 Julia Elman and Mark Lavin, 978-1-491-94594-0.” If you feel your use of code examples falls outside fair use or the permission given above, feel free to contact us at [email protected]. Organization of This Book Chapter 1, The World’s Smallest Django Project Creating lightweight and simple web applications is the core concept in this book. In this chapter, you’ll be building a runnable, single-file “Hello World” Django application. Chapter 2, Stateless Web Application Ever wonder how placeholder image services are created? Chapter 2 walks you through how to build a stateless web application to generate placeholder image URLs. Chapter 3, Building a Static Site Generator Rapid prototyping is a useful technique for creating and scaffolding web applica‐ tions. We’ll review the purposes of this technique by creating a static site generator to help scaffold your team’s project. Chapter 4, Building a REST API RESTAPIsareanimportantpartofcreatingwebapplicationswithrichandrelevant content. This is the chapter in which we start building out a large-scale Scrum board application by using the django-rest-framework. Chapter 5, Client-Side Django with Backbone.js Chapter 5 continues with what we built in Chapter 4 by walking you through cre‐ ating a Backbone.js application that works with our newly made RESTful API. We’ll touch on each component that creates a new Backbone application and how to sync up this client-side framework with Django. Chapter 6, Single-Page Web Application Single-page web applications are a way in which we can create enriching client-side web applications. In this chapter we’ll return to our simple Backbone application and continue our progress by making it a robust single-page application. Chapter 7, Real-Time Django Creating web applications that respond to interactions in real time provides instant gratification for our users. To complete our project from the previous two chapters, we’lladdareal-timecomponenttoourScrumboardusingwebsocketsandTornado, an asynchronous networking library written in Python. Preface | ix
  • 16. Chapter 8, Communication Between Django and Tornado ConnectingthepowerofDjangototherobustbehaviorsofTornadoisanimportant measure in creating scalable, real-time Django applications. In this chapter, we’ll expand on our usage of the Tornado server by integrating the ability to work with Django to create a secure and interactive relationship. Conventions Used in This Book The following typographical conventions are used in this book: Italic Indicates new terms, URLs, email addresses, filenames, and file extensions. Constant width Used for program listings, as well as within paragraphs to refer to program elements such as variable or function names, databases, data types, environment variables, statements, and keywords. Constant width bold Shows commands or other text that should be typed literally by the user. Constant width italic Shows text that should be replaced with user-supplied values or by values deter‐ mined by context. Throughout the code examples, we will use an ellipsis (…) to denote that some of the previously displayed content has been skipped to shorten long code examples or to skip to the most relevant section of the code. This element signifies a tip or suggestion. This element signifies a general note. This element indicates a warning or caution. x | Preface
  • 17. How to Contact Us Please address comments and questions concerning this book to the publisher: O’Reilly Media, Inc. 1005 Gravenstein Highway North Sebastopol, CA 95472 800-998-9938 (in the United States or Canada) 707-829-0515 (international or local) 707-829-0104 (fax) We have a web page for this book, where we list errata, examples, and any additional information. You can access this page at http://www.oreilly.com/catalog/ 0636920032502. To comment or ask technical questions about this book, send email to [email protected]. For more information about our books, courses, conferences, and news, see our website at http://www.oreilly.com. Find us on Facebook: http://facebook.com/oreilly Follow us on Twitter: http://twitter.com/oreillymedia Watch us on YouTube: http://www.youtube.com/oreillymedia Acknowledgments Therearenumerouspeopletothankandwithoutwhomthisbookwouldnotbepossible. We received amazing support from our editor, Meghan Blanchette. Thank you to our technical reviewers—Aymeric Augustin, Jon Banafato, Barbara Shaurette, and Marie Selvanadin— for your comments, both positive and negative, which helped to shape and focus the book. Also thank you to Heather Scherer for shep‐ herding the technical review. We are grateful to all the open source developers and contributors whose endless hours of work were needed to make these tools available for us to use and write about. Thank you to our early release readers for taking a chance on our unfinished work, dealing with typos and poor formatting, and giving feedback and correcting mistakes. Julia Iwouldliketothankmywonderfulfamilyandclosefriendsfortheirsupportthroughout the course of writing this book. To my husband, Andrew, for believing in my abilities, Preface | xi
  • 18. and for his constant encouragement and steadfast support during this long and bumpy journey. To my daughter, Hannah, who is my inspiration and from whom I can always grow my strength every step of the way. To my mother, Katherine, for pushing me beyond what I ever thought I was capable of doing. To my stepfather, Tom, for teaching me how to use a cordless drill, changing the oil in my car, and instilling in me the value of hard work. Thank you to my brother, Alex, and sister, Elizabeth, for always cheering me on from the sidelines. Thank you to my best friend, Jenny, for her constant love and lifelong friendship. Also, thank you to my wonderful coauthor, Mark, for his brilliance and friendship; he is one of the most talented developers I have ever collaborated with. We made it to this finish line together, and I cannot imagine going through this book writing journey with anyone else. I’d also like to thank the Python community and a few specific members who have inspired, encouraged, and/or mentored me throughout my career: James Bennett, Sean Bleier, Nathan Borror, Colin Copeland, Matt Croydon, Katie Cunningham, Selena Deckelmann, Jacob Kaplan-Moss, Jessica McKellar, Jesse Noller, Christian Metts, Lynn Root, Caleb Smith, Paul Smith, Karen Tracey, Malcolm Tredinnick, Ben Turner, and Simon Willison. Mark First and foremost, this book would not be possible without the love and support of my family. My wife, Beth, and daughter, Kennedy, put up with long hours and a grumpier and more stressed version of me than they deserve. Also thanks to my brother, Matt, for his insight and early feedback. Thank you to my parents and my brother James for their lifetime of support. Thank you to my coauthor, Julia. Our collaboration is a celebration of our friendship and mutual respect. I will forever cherish our ability to work together to create some‐ thing greater than the sum of our contributions. Finally, thank you to my coworkers at Caktus Group for your support in time, feedback, and encouragement. xii | Preface
  • 19. Prerequisites Before we dive in, this chapter is an outline of the knowledge and software requirements you’ll need to follow the examples in this book. Python This book is aimed at developers with at least some previous Python experience, and in this book we are using Python 3. In particular, the examples have been tested to run on Python 3.3 and 3.4. Those familiar enough with Python may be able to work through this book using Python 2.7, converting the example code as needed, though it is not recommended. To read more about what is new in these versions of Python and to find installation instructions for your system, visit https://www.python.org/downloads/. We expect that you have Python installed on your local development machine, know how to edit Python files, and know how to run them. Throughout this book, when we reference Python on the command line, we will use python, though some systems or installations may require using python3 or the full version, such as python3.3 or python3.4. Similarly, when installing new packages, the examples will use pip, though some installations may require using pip3. For this book, and Python development in general, it is recommended that you create an isolated Python environment for each project using virtualenv. Without an isolated environment, installing new Python packages with pip may require root access or administrative rights on your computer. We’ll assume that if this is the case, you will prefix the pip command with sudo or any other commands you may need to gain such rights, but those prefixes will not be shown in the examples. xiii
  • 20. Python Packages The only Python package that is required before you start this book is Django. All of the examples have been tested and written to work with Django 1.7. It is recommended that you install with pip: hostname $ pip install Django==1.7 As of August 2014, Django 1.7 was still in a release candidate phase. If the preceding installation does not work, you can install the 1.7 pre- release from the development branch with pip install https:// github.com/django/django/archive/stable/1.7.x.zip. To read more about what is new in this version of Django, visit https://docs.djangopro ject.com/en/dev/releases/1.7/. For additional installation instructions, you can also see the Django guide on installation. Additional packages will be installed throughout the chapters. Chapters 1, 2, and 3 are each independent projects and can be treated as separate virtual environments, again with Django being the only prerequisite. Chapters 4 through 8 comprise one large project, and the same virtual environment should be used for those chapters. Web Development As Django is a web framework, this book assumes you have some basic knowledge of HTML and CSS. The JavaScript examples are more in depth, and the expected level of knowledgeisdetailedmoreinthefollowingsection.AbasicunderstandingoftheHTTP protocol, in particular the usage and purpose of the various HTTP verbs (GET, POST, PUT, DELETE, etc.), is helpful. JavaScript The later chapters in this book make heavy use of JavaScript. You should also be familiar withwritingJavaScript/jQuery.AdeveloperexperienceddoingDOMmanipulationand makingAJAXcallswithjQueryshouldbeabletofollowtheexamplesusingBackbone.js. If you are familiar with another client-side framework such as Angular.js, Ember.js, or Knockout.js, you will be ahead of the game. This is not meant to be a definitive guide on Backbone.js. If you are not familiar with working with JavaScript, and Backbone.js MVC architecture in particular, here are some recommended O’Reilly titles for you to read: xiv | Prerequisites
  • 21. • JavaScript: The Definitive Guide, by David Flanagan (2011) • JavaScript: The Good Parts, by Douglas Crockford (2008) • JavaScript Patterns, by Stoyan Stefanov (2010) • Speaking JavaScript, by Axel Rauschmayer (2014) • Developing Backbone.js Applications, by Addy Osmani (2013) Browser Support The examples in this book make use of relatively new HTML5 and CSS3 APIs, and expectamodernbrowser.Anythingbelowtheseversionshasnotbeentestedthoroughly and/or may not support the technology that we use in the examples: • IE 10+ • Firefox 28.0+ • Chrome 33.0+ Youshouldbefamiliarwithusingthedevelopertoolsinyourpreferredbrowsertodebug potential errors, see network requests, and use the JavaScript console. Additional Software Later chapters will make use of two popular databases: PostgreSQL and Redis. Brief installation instructions are noted in the chapters where needed, but you should refer to the official documentation for a more complete guide for your system. PostgreSQL is an open source relational database system that has strong support in the Django community. Any version of PostgreSQL supported by Django will work for this book. Django 1.7 supports PostgreSQL 8.4 and higher. Redis is an open source key/value cache. This book makes use of the pub/sub features of Redis and requires 2.0 and higher. Prerequisites | xv
  • 23. CHAPTER 1 The World’s Smallest Django Project How many of our journeys into using Django have begun with the official polls tutorial? For many it seems like a rite of passage, but as an introduction to Django it is a fairly daunting task. With various commands to run and files to generate, it is even harder to tell the difference between a project and an application. For new users wanting to start building applications with Django, it begins to feel far too “heavy” as an option for a web framework. What are some ways we can ease these new users’ fears to create a clean and simple start? Let’s take a moment to consider the recommended tasks for starting a Django project. The creation of a new project generally starts with the startproject command. There is no real magic to what this command does; it simply creates a few files and directories. While the startproject command is a useful tool, it is not required in order to start a Django project. You are free to lay out your project however you like based on what you want to do. For larger projects, developers benefit from the code organization provided by the startproject command. However, the convenience of this command shouldn’t stop you from understanding what it does and why it is helpful. In this chapter we’ll lay out an example of how to create a simple project using Django’s basicbuildingblocks.Thislightweight“HelloWorld”projectwillcreateasimpleDjango application using a single-file approach. Hello Django Building a “Hello World” example in a new language or framework is a common first project.We’veseenthissimplestarterprojectexamplecomeoutoftheFlaskcommunity to display how lightweight it is as a microframework. In this chapter, we’ll start by using a single hello.py file. This file will contain all of the code needed to run our Django project. In order to have a full working project, we’ll 1
  • 24. need to create a view to serve the root URL and the necessary settings to configure the Django environment. Creating the View Django is referred to as a model-template-view (MTV) framework. The view portion typically inspects the incoming HTTP request and queries, or constructs, the necessary data to send to the presentation layer. Inourexamplehello.pyfile,let’screateasimplewaytoexecutea“HelloWorld”response. from django.http import HttpResponse def index(request): return HttpResponse('Hello World') In a larger project, this would typically be in a views.py file inside one of your apps. However, there is no requirement for views to live inside of apps. There is also no requirementthatviewsliveinafilecalledviews.py.Thisispurelyamatterofconvention, but not a requirement on which to base our project’s structure. The URL Patterns In order to tie our view into the site’s structure, we’ll need to associate it with a URL pattern.Forthisexample,theserverrootcanservetheviewonitsown.Djangoassociates views with their URL by pairing a regular expression to match the URL and any callable arguments to the view. The following is an example from hello.py of how we make this connection. from django.conf.urls import url from django.http import HttpResponse def index(request): return HttpResponse('Hello World') urlpatterns = ( url(r'^$', index), ) Now this file combines both a typical views.py file and the root urls.py file. Again, it is worth noting that there is no requirement for the URL patterns to be included in a urls.py file. They can live in any importable Python module. Let’s move on to our Django settings and the simple lines we’ll need to make our project runnable. 2 | Chapter 1: The World’s Smallest Django Project
  • 25. The Settings Django settings detail everything from database and cache connections to internation‐ alization features and static and uploaded resources. For many developers just getting started, the settings in Django are a major point of confusion. While recent releases have worked to trim down the default settings’ file length, it can still be overwhelming. This example will run Django in debugging mode. Beyond that, Django merely needs to be configured to know where the root URLs can be found and will use the value defined by the urlpatterns variable in that module. In this example from hello.py, the root URLs are in the current module and will use the urlpatterns defined in the pre‐ vious section. from django.conf import settings settings.configure( DEBUG=True, SECRET_KEY='thisisthesecretkey', ROOT_URLCONF=__name__, MIDDLEWARE_CLASSES=( 'django.middleware.common.CommonMiddleware', 'django.middleware.csrf.CsrfViewMiddleware', 'django.middleware.clickjacking.XFrameOptionsMiddleware', ), ) ... This example includes a nonrandom SECRET_KEY setting, which should not be used in a production environment. A secret key must be generated for the default session and cross-site request forgery (CSRF) protection. It is important for any production site to have a random SECRET_KEY that is kept private. To learn more, go to the documentation at https://docs.djangoproject.com/en/1.7/topics/sign ing/. We need to configure the settings before making any additional imports from Django, as some parts of the framework expect the settings to be configured before they are imported. Normally, this wouldn’t be an issue since these settings would be included in their own settings.py file. The file generated by the default startproject command would also include settings for things that aren’t used by this example, such as the in‐ ternationalization and static resources. Hello Django | 3
  • 26. Running the Example Let’s take a look at what our example looks like during runserver. A typical Django project contains a manage.py file, which is used to run various commands such as cre‐ ating database tables and running the development server. This file itself is a total of 10 lines of code. We’ll be adding in the relevant portions of this file into our hello.py to create the same abilities manage.py has: import sys from django.conf import settings settings.configure( DEBUG=True, SECRET_KEY='thisisthesecretkey', ROOT_URLCONF=__name__, MIDDLEWARE_CLASSES=( 'django.middleware.common.CommonMiddleware', 'django.middleware.csrf.CsrfViewMiddleware', 'django.middleware.clickjacking.XFrameOptionsMiddleware', ), ) from django.conf.urls import url from django.http import HttpResponse def index(request): return HttpResponse('Hello World') urlpatterns = ( url(r'^$', index), ) if __name__ == "__main__": from django.core.management import execute_from_command_line execute_from_command_line(sys.argv) Now you can start the example in the command line: hostname $ python hello.py runserver Performing system checks... System check identified no issues (0 silenced). August 06, 2014 - 19:15:36 Django version 1.7c2, using settings None 4 | Chapter 1: The World’s Smallest Django Project
  • 27. Starting development server at http://7.0.0.1:8000/ Quit the server with CONTROL-C. and visit http://localhost:8000/ in your favorite browser to see “Hello World,” as seen in Figure 1-1. Figure 1-1. Hello World Now that we have a very basic file structure in place, let’s move on to adding more elements to serve up our files. Improvements This example shows some of the fundamental pieces of the Django framework: writing views, creating settings, and running management commands. At its core, Django is a PythonframeworkfortakingincomingHTTPrequestsandreturningHTTPresponses. What happens in between is up to you. Django also provides additional utilities for common tasks involved in handling HTTP requests, such as rendering HTML, parsing form data, and persisting session state. While not required, it is important to understand how these features can be used in Improvements | 5
  • 28. your application in a lightweight manner. By doing so, you gain a better understanding of the overall Django framework and true capabilities. WSGI Application Currently, our “Hello World” project runs through the runserver command. This is a simple server based on the socket server in the standard library. It has helpful utilities for local development such as auto–code reloading. While it is convenient for local development, runserver is not appropriate for production deployment security. The Web Server Gateway Interface (WSGI) is the specification for how web servers communicate with application frameworks such as Django, and was defined by PEP 333 and improved in PEP 3333. There are numerous choices for web servers that speak WSGI, including Apache via mod_wsgi, Gunicorn, uWSGI, CherryPy, Tornado, and Chaussette. Each of these servers needs a properly defined WSGI application to be used. Django has an easy interface for creating this application through get_wsgi_application. ... from django.conf.urls import url from django.core.wsgi import get_wsgi_application from django.http import HttpResponse ... application = get_wsgi_application() if __name__ == "__main__": from django.core.management import execute_from_command_line execute_from_command_line(sys.argv) This would normally be contained within the wsgi.py file created by the startproject command. The name application is merely a convention used by most WSGI servers; each provides configuration options to use a different name if needed. Now our simple Django project is ready for the WSGI server. Gunicorn is a popular choice for a pure-Python WSGI application server; it has a solid performance record, is easy to install, and also runs on Python 3. Gunicorn can be installed via the Python Package Index (pip). hostname $ pip install gunicorn Once Gunicorn is installed, you can run it fairly simply by using the gunicorn com‐ mand. hostname $ gunicorn hello --log-file=- [2014-08-06 19:17:26 -0400] [37043] [INFO] Starting gunicorn 19.1.1 [2014-08-06 19:17:26 -0400] [37043] [INFO] Listening at: http://127.0.0.1:8000 (37043) 6 | Chapter 1: The World’s Smallest Django Project
  • 29. [2014-08-06 19:17:26 -0400] [37043] [INFO] Using worker: sync [2014-08-06 19:17:26 -0400] [37046] [INFO] Booting worker with pid: 37046 As seen in the output, this example is running using Gunicorn version 19.1.1. The timestamps shown contain your time zone offset, which may differ depending on your locale. The process IDs for the arbiter and the worker will also be different. As of R19, Gunicorn no longer logs to the console by default. Adding the --log-file=- option ensures that the output will be logged to the console. You can read more about Gunicorn settings at http:// docs.gunicorn.org/en/19.1/. As with runserver in Django, the server is listening on http://127.0.0.1:8000/. This works out nicely and makes an easier configuration for us to work with. Additional Configuration While Gunicorn is a production-ready web server, the application itself is not yet pro‐ duction ready, as DEBUG should never be enabled in production. As previously noted, the SECRET_KEY is also nonrandom and should be made random for additional security. For more information on the security implications of the DEBUG and SECRET_KEY settings, please refer to the official Django documenta‐ tion. This leads to a common question in the Django community: how should the project manage different settings for development, staging, and production environments? Django’s wiki contains a long list of approaches, and there are a number of reusable applications that aim to tackle this problem. A comparison of those applications can be found on Django Packages. While many of these options can be ideal in some cases, such as converting the settings.py into a package and creating modules for each envi‐ ronment, they do not line up well with our example’s current single-file setup. The Twelve Factor App is a methodology for building and deploying HTTP service applications. This methodology recommends separating configuration and code as well as storing configurations in environment variables. This makes the configuration easy to change on the deployment and makes the configuration OS-agnostic. Improvements | 7
  • 30. Let’s apply this methodology to our hello.py example. There are only two settings that are likely to change between environments: DEBUG and SECRET_KEY. import os import sys from django.conf import settings DEBUG = os.environ.get('DEBUG', 'on') == 'on' SECRET_KEY = os.environ.get('SECRET_KEY', os.urandom(32)) settings.configure( DEBUG=DEBUG, SECRET_KEY=SECRET_KEY, ROOT_URLCONF=__name__, MIDDLEWARE_CLASSES=( 'django.middleware.common.CommonMiddleware', 'django.middleware.csrf.CsrfViewMiddleware', 'django.middleware.clickjacking.XFrameOptionsMiddleware', ), ) As you may notice, the default for DEBUG is True, and the SECRET_KEY will be randomly generated each time the application is loaded if it is not set. That will work for this toy example,butiftheapplicationwereusingapieceofDjangothatrequirestheSECRET_KEY to remain stable, such as the signed cookies, this would cause the sessions to be fre‐ quently invalidated. Let’s examine how this translates to launching the application. To disable the DEBUG setting, we need to set the DEBUG environment variable to something other than on. In a UNIX-derivative system, such as Linux, OS X, or FreeBSD, environment variables are set on the command line with the export command. On Windows, you’d use set. hostname $ export DEBUG=off hostname $ python hello.py runserver CommandError: You must set settings.ALLOWED_HOSTS if DEBUG is False. As you can see from the error, the ALLOWED_HOSTS setting isn’t configured by our ap‐ plication. ALLOWED_HOSTS is used to validate incoming HTTP HOST header values and should be set to a list of acceptable values for the HOST. If the application is meant to serve example.com, then ALLOWED_HOSTS should allow only for clients that are request‐ ing example.com. If the ALLOWED_HOSTS environment variable isn’t set, then it will allow requests only for localhost. This snippet from hello.py illustrates. import os import sys from django.conf import settings 8 | Chapter 1: The World’s Smallest Django Project
  • 31. DEBUG = os.environ.get('DEBUG', 'on') == 'on' SECRET_KEY = os.environ.get('SECRET_KEY', os.urandom(32)) ALLOWED_HOSTS = os.environ.get('ALLOWED_HOSTS', 'localhost').split(',') settings.configure( DEBUG=DEBUG, SECRET_KEY=SECRET_KEY, ALLOWED_HOSTS=ALLOWED_HOSTS, ROOT_URLCONF=__name__, MIDDLEWARE_CLASSES=( 'django.middleware.common.CommonMiddleware', 'django.middleware.csrf.CsrfViewMiddleware', 'django.middleware.clickjacking.XFrameOptionsMiddleware', ), ) With our ALLOWED_HOSTS variable set, we now have validation for our incoming HTTP HOST header values. For a complete reference on the ALLOWED_HOSTS setting, see the offi‐ cial Django documentation. Outside the development environment, the application might need to serve multiple hosts, such as localhost and example.com, so the configuration allows us to specify multiple hostnames separated by commas. hostname $ export DEBUG=off hostname $ export ALLOWED_HOSTS=localhost,example.com hostname $ python hello.py runserver ... [06/Aug/2014 19:45:53] "GET / HTTP/1.1" 200 11 This gives us a flexible means of configuration across environments. While it would be slightly more difficult to change more complex settings, such as INSTALLED_APPS or MIDDLEWARE_CLASSES, that is in line with the overall methodology, which encourages minimal differences between environments. If you want to make complex changes between environments, you should take time to consider what impact that will have on the testa‐ bility and deployment of the application. Improvements | 9
  • 32. We can reset DEBUG to the default by removing the environment variable from the shell or by starting a new shell. hostname $ unset DEBUG Reusable Template So far this example has centered on rethinking the layout created by Django’s startproject command. However, this command also allows for using a template to provide the layout. It isn’t difficult to transform this file into a reusable template to start future projects using the same base layout. A template for startproject is a directory or zip file that is rendered as a Django template when the command is run. By default, all of the Python source files will be rendered as a template. The rendering is passed project_name, project_directory, secret_key, and docs_version as the context. The names of the files will also be ren‐ dered with this context. To transform hello.py into a project template (project_name/ project_name.py), the relevant parts of the file need to be replaced by these variables. import os import sys from django.conf import settings DEBUG = os.environ.get('DEBUG', 'on') == 'on' SECRET_KEY = os.environ.get('SECRET_KEY', '{{ secret_key }}') ALLOWED_HOSTS = os.environ.get('ALLOWED_HOSTS', 'localhost').split(',') settings.configure( DEBUG=DEBUG, SECRET_KEY=SECRET_KEY, ALLOWED_HOSTS=ALLOWED_HOSTS, ROOT_URLCONF=__name__, MIDDLEWARE_CLASSES=( 'django.middleware.common.CommonMiddleware', 'django.middleware.csrf.CsrfViewMiddleware', 'django.middleware.clickjacking.XFrameOptionsMiddleware', ), ) from django.conf.urls import url from django.core.wsgi import get_wsgi_application from django.http import HttpResponse def index(request): return HttpResponse('Hello World') 10 | Chapter 1: The World’s Smallest Django Project
  • 33. urlpatterns = ( url(r'^$', index), ) application = get_wsgi_application() if __name__ == "__main__": from django.core.management import execute_from_command_line execute_from_command_line(sys.argv) Nowlet’ssavethisfileasproject_name.pyinadirectorycalledproject_name.Also,rather than using os.urandom for the SECRET_KEY default, this code will generate a random secret to be the default each time a new project is created. This makes the SECRET_KEY default stable at the project level while still being sufficiently random across projects. To use the template with startproject, you can use the --template argument. hostname $ django-admin.py startproject foo --template=project_name This should create a foo.py inside a foo directory, which is now ready to run just like the original hello.py. As outlined in this example, it is certainly possible to write and run a Django project withouthavingtousethe startproject command.Thedefaultsettingsandlayoutused by Django aren’t appropriate for every project. The --template option for startproject can be used to either expand on these defaults or to trim them down, as you’ve seen in this chapter. AswithanyPythonproject,therecomesapointwhereorganizingthecodeintomultiple modules is an important part of the process. For a sufficiently focused site, with only a handful of URLs, our “Hello World” example may be a reasonable approach. What is also interesting about this approach is that it isn’t immediately obvious that Django has a templating engine or an object-relational mapper (ORM) built in. It is clear that you are free to choose whatever Python libraries you think best solve your problem.YounolongerhavetousetheDjangoORM,astheofficialtutorialmightimply. Instead, you get to use the ORM if you want. The project in the next chapter will expand on this single-file example to provide a simple HTTP service and make use of more of the utilities that come with Django. Improvements | 11
  • 35. CHAPTER 2 Stateless Web Application Most Django applications and tutorials center on some variety of user-generated con‐ tent, such as to-do lists, blogs, and content management systems. This isn’t surprising given Django’s original roots in journalism. In 2005, Django was originally developed at World Online in Lawrence, Kansas, as a way for reporters to quickly create content for the Web. Since then, it has been used by publishing organizations such as the Washington Post, the Guardian, PolitiFact, and the Onion. This aspect of Django may give the impression that its main purpose is content publishing, or that Django itself is a content management system. With large organizations such as NASA adopting Django as their framework of choice, however, Django has obviously outgrown its original purpose. In the previous chapter we created a minimal project that made use only of Django’s coreHTTPhandlingandURLrouting.Inthischapterwewillexpanduponthatexample to create a stateless web application that uses more of Django’s utilities, such as input validation, caching, and templates. Why Stateless? HTTP itself is a stateless protocol, meaning each request that comes to the server is independent of the previous request. If a particular state is needed, it has to be added at the application layer. Frameworks like Django use cookies and other mechanisms to tie together requests made by the same client. Alongwithapersistentsessionstoreontheserver,theapplicationcanthenhandletasks, such as holding user authentication across requests. With that comes a number of chal‐ lenges, as this consistent state reads, and potentially writes, on every request in a dis‐ tributed server architecture. 13
  • 36. As you can imagine, a stateless application does not maintain this consistent state on a server. If authentication or other user credentials are required, then they must be passed by the client on every request. This often makes scaling, caching, and load balancing with stateless applications much easier. You can also make stateless applications easily linkable because the URL can convey most of these states. There are two options we can take, which we’ll outline in the next section: reusable apps and composable services. Reusable Apps Versus Composable Services Much of the focus in the Django community is about building reusable applications that can be installed and configured into any Django project. However, large applica‐ tions with different components often have a fairly complex architectural structure. An approach to combat this complexity is to break large websites into composable services—that is, smaller services that communicate with one another. This doesn’t mean that they can’t and won’t share code at some point. It does mean, however, that each service can then be configured and built separately. Stateless components, such as REST APIs, are great candidates for breaking out into separate Django projects that can be deployed and tuned independently. Let’s build on our Chapter 1 project by creating a placeholder image server using the two techniques just described with Django. Placeholder Image Server Placeholder images are frequently used in application prototypes, example projects, or testing environments. A typical placeholder image service will take a URL that indicates the size of the image and generate that image. The URL may contain additional infor‐ mation, such as the color of the image or text to display within the image. Since every‐ thing that is needed to construct the requested image is contained within the URL, and there’s little need for authentication, this makes a good candidate for a stateless appli‐ cation. Start by creating a new project called placeholder with the startproject using the project_name template created in Chapter 1. hostname $ django-admin.py startproject placeholder --template=project_name This will generate a placeholder.py file for us to begin building our service. If you have used the project template correctly, placeholder.py should look like this: import os import sys from django.conf import settings DEBUG = os.environ.get('DEBUG', 'on') == 'on' 14 | Chapter 2: Stateless Web Application
  • 37. SECRET_KEY = os.environ.get('SECRET_KEY', '%jv_4#hoaqwig2gu!eg#^ozptd*a@88u(aasv7z!7xt^5(*i&k') ALLOWED_HOSTS = os.environ.get('ALLOWED_HOSTS', 'localhost').split(',') settings.configure( DEBUG=DEBUG, SECRET_KEY=SECRET_KEY, ALLOWED_HOSTS=ALLOWED_HOSTS, ROOT_URLCONF=__name__, MIDDLEWARE_CLASSES=( 'django.middleware.common.CommonMiddleware', 'django.middleware.csrf.CsrfViewMiddleware', 'django.middleware.clickjacking.XFrameOptionsMiddleware', ), ) from django.conf.urls import url from django.core.wsgi import get_wsgi_application from django.http import HttpResponse def index(request): return HttpResponse('Hello World') urlpatterns = ( url(r'^$', index), ) application = get_wsgi_application() if __name__ == "__main__": from django.core.management import execute_from_command_line execute_from_command_line(sys.argv) The SECRET_KEY setting will be different from this published ver‐ sion, as it is randomly generated by the startproject command. With our initial settings in place, we can now begin to write our views and start building out the pages to create these responses. Placeholder Image Server | 15
  • 38. Views Since this application will be simple, we will need only two views to generate our re‐ sponses. The first view will render the placeholder images based on their requested width and height. The other view will render the home page content, which explains how the project works and renders a few example images. Because we used Django’s -- template flag when running the startproject command, the index has already been generated (as shown in this snippet from placeholder.py) and will need to be adapted later. ... def placeholder(request, width, height): # TODO: Rest of the view will go here return HttpResponse('Ok') def index(request): return HttpResponse('Hello World') ... With these simple views in place, we should now think about the URL structure for displaying our placeholders. URL Patterns When opening your generated placeholder.py file, you’ll notice that there is a URL pat‐ tern for the server root. We’ll also need a route to the placeholder view we just created. The stub of the placeholder view will take two arguments: width and height. As men‐ tioned previously, those parameters will be captured by the URL and passed to the view. Since they will only ever be integers, we’ll want to make sure to enforce them by the URL. Since URL patterns in Django use regular expressions to match the incoming URL, we’ll be able to easily pass in those parameters. Captured pattern groups are passed to the view as positional arguments, and named groups are passed as keyword arguments. Named groups are captured using the ?P syntax, and any digit characters are matched by using [0-9]. This snippet from placeholder.py shows how your URL patterns will be laid out to gen‐ erate those values: ... urlpatterns = ( url(r'^image/(?P<width>[0-9]+)x(?P<height>[0-9]+)/$', placeholder, name='placeholder'), url(r'^$', index, name='homepage'), ) ... 16 | Chapter 2: Stateless Web Application
  • 39. Withthesepatternsinplace,incomingrequeststotheURL/image/30x25/willberouted totheplaceholder viewandpassinthosevalues(e.g.,width=30 andheight=25).Along with the new route for the placeholder view, the name homepage has been added to the index router. We will also see how naming these URL patterns, while a good practice in general, will be especially useful when we begin to build the templates later. Placeholder View Along with the original HTTP request, the placeholder view should accept two integer arguments for the image’s height and width values. Though the regular expression will ensure that the height and width consist of digits, they will be passed to the view as strings. The view will need to convert them and may also want to validate that they are a manageable size. We can easily do this by validating user input with Django forms. Typically forms are used to validate POST and GET content, but they can also be used tovalidateparticularvaluesfromtheURL,orthosestoredincookies.Hereisanexample from placeholder.py of a simple form to validate the height and width of an image: ... from django import forms from django.conf.urls import url ... class ImageForm(forms.Form): """Form to validate requested placeholder image.""" height = forms.IntegerField(min_value=1, max_value=2000) width = forms.IntegerField(min_value=1, max_value=2000) def placeholder(request, width, height): ... As you can see, the first thing the view should do is validate the requested image size. Iftheformisvalid,thentheheightandwidthcanbeaccessedintheform’scleaned_data attribute. At this point, the height and width will be converted to integers, and the view can be sure that the values are between 1 and 2000. We’ll also need to add validation to the form to send an error message if the values are incorrect, as shown in this excerpt from placeholder.py. ... from django import forms from django.conf.urls import url from django.core.wsgi import get_wsgi_application from django.http import HttpResponse, HttpResponseBadRequest class ImageForm(forms.Form): """Form to validate requested placeholder image.""" Placeholder View | 17
  • 40. height = forms.IntegerField(min_value=1, max_value=2000) width = forms.IntegerField(min_value=1, max_value=2000) def placeholder(request, width, height): form = ImageForm({'height': height, 'width': width}) if form.is_valid(): height = form.cleaned_data['height'] width = form.cleaned_data['width'] # TODO: Generate image of requested size return HttpResponse('Ok') else: return HttpResponseBadRequest('Invalid Image Request') ... If the form isn’t valid, the view will send an error response to the client. Here the view returns an HttpResponseBadRequest, which is a subclass of HttpResponse, and sends a 400 Bad Request response. Image Manipulation The view now has the ability to accept and clean the height and width requested by the client, but it does not yet generate the actual image. To handle image manipulation in Python, you need to have Pillow installed as follows: hostname $ pip install Pillow By default, the install will try to compile Pillow from the source. If you do not have a compiler installed for your environment, or you are missing the necessary headers, it can fail to install. For installa‐ tion notes on various platforms, visit https:// pillow.readthedocs.org/en/latest/installation.html. Creating an image with Pillow requires two arguments: the color mode and the size as a tuple. This view from placeholder.py will use the RGB mode and the size from the form’s cleaned data values. There is a third argument, which is not required, that sets the color of the image. By default in Pillow, every pixel of the image will be black. ... from io import BytesIO from PIL import Image ... class ImageForm(forms.Form): """Form to validate requested placeholder image.""" height = forms.IntegerField(min_value=1, max_value=2000) width = forms.IntegerField(min_value=1, max_value=2000) 18 | Chapter 2: Stateless Web Application
  • 41. def generate(self, image_format='PNG'): """Generate an image of the given type and return as raw bytes.""" height = self.cleaned_data['height'] width = self.cleaned_data['width'] image = Image.new('RGB', (width, height)) content = BytesIO() image.save(content, image_format) content.seek(0) return content def placeholder(request, width, height): form = ImageForm({'height': height, 'width': width}) if form.is_valid(): image = form.generate() return HttpResponse(image, content_type='image/png') else: return HttpResponseBadRequest('Invalid Image Request') ... A new generate method has been added to the ImageForm to encapsulate the logic of building the image. It takes one argument for the image format, which defaults to PNG, and returns the image contents as bytes. Using the width and height given by the URL and validated by the form, a new image is constructed using the Image class from Pillow. The view calls form.generate to get the constructed image, and the bytes for the image are then used to construct the response body. The form then validates the size to prevent requesting too large of an image and con‐ suming too many resources on the server. Once the image has been validated, the view successfully returns the PNG image for the requested width and height. The image content is sent to the client without writing it to the disk. However, an all-black image, with no sizing information, is not a very stylish or useful placeholder.WithPillow wecanaddthistexttotheimageusingtheImageDraw module, as shown in this snippet from placeholder.py. ... from PIL import Image, ImageDraw ... class ImageForm(forms.Form): ... def generate(self, image_format='PNG'): """Generate an image of the given type and return as raw bytes.""" height = self.cleaned_data['height'] width = self.cleaned_data['width'] image = Image.new('RGB', (width, height)) Placeholder View | 19
  • 42. draw = ImageDraw.Draw(image) text = '{} X {}'.format(width, height) textwidth, textheight = draw.textsize(text) if textwidth < width and textheight < height: texttop = (height - textheight) // 2 textleft = (width - textwidth) // 2 draw.text((textleft, texttop), text, fill=(255, 255, 255)) content = BytesIO() image.save(content, image_format) content.seek(0) return content ... generate now uses ImageDraw to add a text overlay if it will fit. Using ImageDraw, the form uses the current image to create text showing the width and height on the image, Now that we have our valid placeholder image in place, let’s add some caching to help minimize requests to the server. Adding Caching The placeholder image view currently regenerates the image and serves it each time the view is requested. Since the width and height of the image are set via the original, we are constantly making unnecessary requests to our server. One way to avoid this repetition is to use caching. There are two options to think about when you’re determining how to utilize caching for this service: server-side and client- side. For server-side caching, you can easily use Django’s cache utilities. This will trade memory usage to store the cached values while saving the CPU cycles required to gen‐ erate the images, as shown in this excerpt from placeholder.py. ... from django.conf.urls import url from django.core.cache import cache ... class ImageForm(forms.Form): ... def generate(self, image_format='PNG'): """Generate an image of the given type and return as raw bytes.""" height = self.cleaned_data['height'] width = self.cleaned_data['width'] key = '{}.{}.{}'.format(width, height, image_format) content = cache.get(key) if content is None: image = Image.new('RGB', (width, height)) draw = ImageDraw.Draw(image) text = '{} X {}'.format(width, height) textwidth, textheight = draw.textsize(text) 20 | Chapter 2: Stateless Web Application
  • 43. if textwidth < width and textheight < height: texttop = (height - textheight) // 2 textleft = (width - textwidth) // 2 draw.text((textleft, texttop), text, fill=(255, 255, 255)) content = BytesIO() image.save(content, image_format) content.seek(0) cache.set(key, content, 60 * 60) return content A cache key is generated that depends on the width, height, and image format. Before a new image is created, the cache is checked to see if the image is already stored. When there is a cache miss and a new image is created, the image is cached using the key for an hour. Django defaults to using a process-local, in-memory cache, but you could use a different backend—such as Memcached or the file system—by configuring the CACHES setting. A complementary approach is to focus on the client-side behavior and make use of the browser’s built-in caching. Django includes an etag decorator for generating and using theETagheadersfortheview.Thedecoratortakesasingleargument,whichisafunction to generate the ETag header from the request and view arguments. Here is an example from placeholder.py of how we would add that to our view: import hashlib import os ... from django.http import HttpResponse, HttpResponseBadRequest from django.views.decorators.http import etag ... def generate_etag(request, width, height): content = 'Placeholder: {0} x {1}'.format(width, height) return hashlib.sha1(content.encode('utf-8')).hexdigest() @etag(generate_etag) def placeholder(request, width, height): ... generate_etag is a new function that takes the same arguments as the placeholder view. It uses hashlib to return an opaque ETag value, which will vary based on the width and height values. The generate_etag function will be passed to the etag decorator on the placeholder view. Placeholder View | 21
  • 44. With this decorator in place, the server will need to generate the image the first time the browser requests it. On subsequent requests, if the browser makes a request with the matching ETag, the browser will receive a 304 Not Modified response for the image. The browser will use the image from the cache and save bandwidth and time to regen‐ erate the HttpResponse. This view generates an image based only on the width and height. If other features were added, such as the background color or the im‐ age text, then the ETag generation would also need to be updated to take these into account. The django.middleware.common.CommonMiddleware, which is enabled in the MIDDLEWARE_CLASSES setting, also has support for generating and using ETags if the USE_ETAGS setting is enabled. However, there is a difference between how the middle‐ ware and the decorator work. The middleware will calculate the ETag based on the md5 hash of the response content. That requires the view to do all the work to generate the content in order to calculate the hash. The result is the same in that the browser will receive a 304 Not Modified response and the bandwidth will be saved. Using the etag decorator has the advantage of calculating the ETag prior to the view being called, which will also save on the processing time and resources. The following is the completed placeholder view for placeholder.py, along with the form and decorator functions: ... class ImageForm(forms.Form): """Form to validate requested placeholder image.""" height = forms.IntegerField(min_value=1, max_value=2000) width = forms.IntegerField(min_value=1, max_value=2000) def generate(self, image_format='PNG'): """Generate an image of the given type and return as raw bytes.""" height = self.cleaned_data['height'] width = self.cleaned_data['width'] key = '{}.{}.{}'.format(width, height, image_format) content = cache.get(key) if content is None: image = Image.new('RGB', (width, height)) draw = ImageDraw.Draw(image) text = '{} X {}'.format(width, height) textwidth, textheight = draw.textsize(text) if textwidth < width and textheight < height: texttop = (height - textheight) // 2 textleft = (width - textwidth) // 2 draw.text((textleft, texttop), text, fill=(255, 255, 255)) content = BytesIO() 22 | Chapter 2: Stateless Web Application
  • 45. image.save(content, image_format) content.seek(0) cache.set(key, content, 60 * 60) return content def generate_etag(request, width, height): content = 'Placeholder: {0} x {1}'.format(width, height) return hashlib.sha1(content.encode('utf-8')).hexdigest() @etag(generate_etag) def placeholder(request, width, height): form = ImageForm({'height': height, 'width': width}) if form.is_valid(): image = form.generate() return HttpResponse(image, content_type='image/png') else: return HttpResponseBadRequest('Invalid Image Request') ... With our placeholder view ready, let’s go back and build out our home page view to complete our application. Creating the Home Page View The home page will render a basic HTML template to explain how the project works and include some sample images. Up to this point, Django has not been configured to render templates. It also has not been configured to serve static resources, such as Java‐ Script,CSS,andtemplates.Let’saddthenecessarysettingstoservethosestaticresources: TEMPLATE_DIRS and STATICFILES_DIRS. Adding Static and Template Settings Django’s template loader will automatically discover templates and static resources in‐ sidetheinstalledapps.SincethisprojectdoesnotincludeanyDjangoapplications,these locations need to be configured with the TEMPLATE_DIRS and STATICFILES_DIRS set‐ tings. django.contrib.staticfiles will also need to be added to the IN STALLED_APPS for the {% static %} tag and collectstatic commands to be available. Here is an example of how your directory structure should look at this point: placeholder/ placeholder.py The templates and static resources would fit nicely in directories next to placehold‐ er.py, as in: placeholder/ placeholder.py Creating the Home Page View | 23
  • 46. templates/ home.html static/ site.css To avoid hardcoding these paths, we’ll be constructing them relative to the placehold‐ er.py file using the os module from the Python standard library. import hashlib import os import sys from django.conf import settings DEBUG = os.environ.get('DEBUG', 'on') == 'on' SECRET_KEY = os.environ.get('SECRET_KEY', '%jv_4#hoaqwig2gu!eg#^ozptd*a@88u(aasv7z!7xt^5(*i&k') BASE_DIR = os.path.dirname(__file__) settings.configure( DEBUG=DEBUG, SECRET_KEY=SECRET_KEY, ROOT_URLCONF=__name__, MIDDLEWARE_CLASSES=( 'django.middleware.common.CommonMiddleware', 'django.middleware.csrf.CsrfViewMiddleware', 'django.middleware.clickjacking.XFrameOptionsMiddleware', ), INSTALLED_APPS=( 'django.contrib.staticfiles', ), TEMPLATE_DIRS=( os.path.join(BASE_DIR, 'templates'), ), STATICFILES_DIRS=( os.path.join(BASE_DIR, 'static'), ), STATIC_URL='/static/', ... Now let’s add a simple template structure to finish out this example project with a clean frontend interface. Home Page Template and CSS The purpose of the home page for this application is to demonstrate how to use the placeholder images with some brief documentation and examples. It should be saved 24 | Chapter 2: Stateless Web Application
  • 47. as templates/home.html next to placeholder.py. We’ll also add in the src reference to our placeholder route to request those images. {% load staticfiles %} <!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> <title>Django Placeholder Images</title> <link rel="stylesheet" href="{% static 'site.css' %}" type="text/css"> </head> <body> <h1>Django Placeholder Images</h1> <p>This server can be used for serving placeholder images for any web page.</p> <p>To request a placeholder image of a given width and height simply include an image with the source pointing to <b>/placeholder/&lt;width&gt;x&lt;height&gt;/</b> on this server such as:</p> <pre> &lt;img src="{{ example }}" &gt; </pre> <h2>Examples</h2> <ul> <li><img src="{% url 'placeholder' width=50 height=50 %}"></li> <li><img src="{% url 'placeholder' width=100 height=50 %}"></li> <li><img src="{% url 'placeholder' width=50 height=100 %}"></li> <ul> </body> </html> Here are some simple styles to add to site.css to help create a clean layout. Also, don’t forget to save this file in your static/ folder, as previously outlined in your STATICFILES_DIRS setting: body { text-align: center; } ul { list-type: none; } li { display: inline-block; } Creating the Home Page View | 25
  • 48. You should save this as static/site.css next to placeholder.py, as outlined in the previous section. Finally, we need to update the index view in placeholder.py to render this tem‐ plate: ... from django.core.cache import cache from django.core.urlresolvers import reverse from django.core.wsgi import get_wsgi_application from django.http import HttpResponse, HttpResponseBadRequest from django.shortcuts import render from django.views.decorators.http import etag ... def index(request): example = reverse('placeholder', kwargs={'width': 50, 'height':50}) context = { 'example': request.build_absolute_uri(example) } return render(request, 'home.html', context) ... The updated index view builds an example URL by reversing the placeholder view, and passes it to the template context. The home.html template is rendered using the render shortcut. Completed Project Now you should have a completed placeholder.py file that looks similar to the following one. Along with home.html and site.css from the previous section, it completes our simple placeholder image service using Django: import hashlib import os import sys from io import BytesIO from PIL import Image, ImageDraw from django.conf import settings DEBUG = os.environ.get('DEBUG', 'on') == 'on' SECRET_KEY = os.environ.get('SECRET_KEY', '%jv_4#hoaqwig2gu!eg#^ozptd*a@88u(aasv7z!7xt^5(*i&k') ALLOWED_HOSTS = os.environ.get('ALLOWED_HOSTS', 'localhost').split(',') BASE_DIR = os.path.dirname(__file__) settings.configure( DEBUG=DEBUG, 26 | Chapter 2: Stateless Web Application
  • 49. SECRET_KEY=SECRET_KEY, ALLOWED_HOSTS=ALLOWED_HOSTS, ROOT_URLCONF=__name__, MIDDLEWARE_CLASSES=( 'django.middleware.common.CommonMiddleware', 'django.middleware.csrf.CsrfViewMiddleware', 'django.middleware.clickjacking.XFrameOptionsMiddleware', ), INSTALLED_APPS=( 'django.contrib.staticfiles', ), TEMPLATE_DIRS=( os.path.join(BASE_DIR, 'templates'), ), STATICFILES_DIRS=( os.path.join(BASE_DIR, 'static'), ), STATIC_URL='/static/', ) from django import forms from django.conf.urls import url from django.core.cache import cache from django.core.urlresolvers import reverse from django.core.wsgi import get_wsgi_application from django.http import HttpResponse, HttpResponseBadRequest from django.shortcuts import render from django.views.decorators.http import etag class ImageForm(forms.Form): """Form to validate requested placeholder image.""" height = forms.IntegerField(min_value=1, max_value=2000) width = forms.IntegerField(min_value=1, max_value=2000) def generate(self, image_format='PNG'): """Generate an image of the given type and return as raw bytes.""" height = self.cleaned_data['height'] width = self.cleaned_data['width'] key = '{}.{}.{}'.format(width, height, image_format) content = cache.get(key) if content is None: image = Image.new('RGB', (width, height)) draw = ImageDraw.Draw(image) text = '{} X {}'.format(width, height) textwidth, textheight = draw.textsize(text) if textwidth < width and textheight < height: texttop = (height - textheight) // 2 textleft = (width - textwidth) // 2 draw.text((textleft, texttop), text, fill=(255, 255, 255)) content = BytesIO() Creating the Home Page View | 27
  • 50. Another Random Scribd Document with Unrelated Content
  • 51. choir of young voices, and bid all prepare. A sacrifice will be offered to Mitzor; the Great White Glory must be appeased.” Alan and Sir John were very mystified over the whole scene. These Jovians did not seem to understand Death—yet they spoke of sacrifice! “I am sorry, my son,” said the Jkak. “I can save nothing for you. All must be burnt and offered to Mitzor. Come now, I will draw a ring around the contaminated spot, and we will witness the destruction from without.” Sir John and Alan were both loth to have the Argenta burnt—but being dependent on the Jovians for their entire future, they were unable to demur. With a silent prayer for the friend who had given his life for them, they left the ship and stood some way off. After an interminable time of waiting, a mighty blast of music burst on their ears, and they saw a procession of etheric bhors coming towards them. The first stopped, and Misrath the High Priest alighted, followed by priests and acolytes in quaint garments of ecclesiastical cut. A procession formed—two acolytes with censers led the way, and wafted the glorious perfume from side to side. Then followed one of the most mystical and picturesque ceremonies it was possible to imagine. Almost of Mosaic grandeur, it thrilled the watchers. They were unable to understand what was being said—all was in the language of the Keemarnians—but the meaning was plain. The High Priest offered the Argenta and its contents to Mitzor, the Great White Glory. He offered it, with its fine workmanship, its precious metals— and its body of sin. He asked that through the mediation of the sacrifice, any evil might be averted, that the entrance of Death might bring. He consecrated the Argenta to Mitzor—he consecrated the ground it contaminated. He poured the “waters of purity” across its bow, and named it “Meeka,” the Bringer of Knowledge. Then the Argenta was sprayed from stem to stern with a milky fluid that dried like little curds all over the vessel. A torch was lighted and applied to the ship. Little flames ran along meeting each other until they merged into one great whole; there was a roar and a noise like thunder, and the Argenta, the hobby of a life time, the fruit of patient labour, was no more!
  • 52. Sir John watched with a set face, but as the fire died out, and he saw that the whole had been swallowed up, had consumed itself entirely,—he crumpled up, and lay inert upon the ground.
  • 53. CHAPTER VI THE SACRAMENT OF SCHLERIK-ITATA Alan bent over his uncle, but the High Priest waved him away. “Touch him not,” said he sternly, and such command rang in his tones, that Alan stepped back involuntarily. Again the scene was repeated—Sir John was prayed over, sprayed with the “waters of purity,” and incensed. As the sweet fumes found their way up his nostrils, he stirred. Alan rushed to him and embraced him. “It was only foolishness, Alan,” said he brokenly. “But the Argenta—my ship—I was so proud of her. Masters, you know how I felt? She was my all in my days of sorrow. And in my days of joy, when reunited we sailed in her, she was my joy.” “I understand, Uncle John. But try not to mind—when one is in Rome—you know the rest. We are in Jupiter and we must do as the Jovians wish.” Persoph the Jkak, came up to them. “Nay, grieve not,” said he kindly. “We have cleared this place of sin. An air bird to take the place of the one that has gone shall be placed at your disposal. Go you home. Cards will be brought you for the Sacrament of Schlerik- itata. I beg of you all—attend it. Nay, I command you. We will meet again within eight Kymos. Farewell. Farewell.” Waz-Y-Kjesta, motioned to their bhor. “Come, my friend,” said he. “I will drive you back another way—we will drive along the shores of the secti, and watch the breakers roll in.” The sea shore was wonderful; the sea was blue, a deep, deep blue, and the breakers, flecked with foam, rolled in to a golden shore. They passed bays, promontories, caves and rocks—and they found the drive of bewildering beauty. Alan asked, “What is the Sacrament of Sch—” “Schlerik-itata?” supplemented the Waz.
  • 54. “Yes.” “My friend, you must wait until you witness it. You will understand us more fully when you have been to the home of Ak-Marn. Now to- night, there is a small party being given by Kulmervan and his fellow students at the Observatory. I have been asked to bring you all. Will you come?” “With pleasure,” said Alan. “The Jkak is sending you all a complete outfit, my friend. Your clothes are old, travel-stained and torn—they are sombre too. If you accept his present, wear to-night your brightest garments.” “Will you help me to adjust them?” asked Alan. The Waz drew himself up with a haughty air, but it as soon passed. “I was forgetting, my friend, that you know not our customs. The serving men will assist you. When you reach home, you will find your house fully staffed, and Quori, a most efficient steward and adviser.” “What about meeting to-night for the party?” “I will call for you as the Kymo sinks. You will have bhors sufficient for your use.” When they reached home they found a note awaiting them from Mavis, asking them to come over and have lunch with her and Desmond, and they walked through the garden to the other house. Mavis was waiting for them, her cheeks dimpling and her eyes sparkling. “It’s a wonderful country,” said she. “I’ve nothing to do all day; the cooking and cleaning seem to go by clockwork. Morkaba is Baby’s personal attendant and mine; she has arranged my frock. How do you like it?” and she twirled round on one foot showing the soft draperies of Keemarnian dress. It was of a soft green, embroidered with coloured silks and her hair was left loose flowing around her shoulders, and caught above her ears by a narrow fillet of gold that gleamed as she tossed her head. “I like it much better than the frumpy old English fashions,” said she. “Desmond is not quite ready yet—he will look splendid.” “We shall change later,” said Sir John, “and I shall be glad to get out of these stuffy and dirty garments. All the same I don’t fancy myself a cross between an imitation gladiator and a stained glass twelfth century saint.”
  • 55. They thoroughly enjoyed their meal; eggs served in a wonderful salad of fruit and vegetables proved to be the staple part, and this course was followed by a baked grain, similar to barley, but of a bright green colour, deliciously creamy and sweet. There was milk to drink, and plenty of heavy cream. “They seem to be almost vegetarians here,” said Mavis, “for although we have had plenty of milk, eggs and cream, I have not seen a sign of fish or meat.” “All the better,” said Sir John, “after all that tinned stuff while we were on the Argenta—ugh!” They drove in state to the students’ party. The Waz had constituted himself their guide, and they were very thankful for his services. The large ground floor of the Observatory had been converted into a veritable bower of roses. At one end, almost hidden by flowers, were the musicians—playing dreamy music on soft-toned, stringed instruments. The Host in Chief, Kulmervan, with Waiko, stood on a raised dais at one end and received their guests, who were all announced by an usher who wore a kilt-like shirt and a flowing cape. As the strangers entered he announced from a card they gave him, first in his own language and then in English, “Sir John, Alan, Desmond, Masters, and Mavis.” No surnames were known on Jupiter, and so far they possessed no Keemarnian title. To Sir John they gave his prefix, although they did not quite understand it. A great silence reigned when the announcement was made— Kulmervan left the dais and advanced toward his guests, and this mark of homage was acknowledged by clamorous cheers from all the others who were present. “Welcome,” said he. “I witnessed your descent upon our land. Indeed, it was I who helped to focus our ray of attraction upon your vessel and helped to draw you into our atmosphere.” “What are your rays?” asked Alan. “Surely you had never any cause to use one before?” “Indeed, yes, my friend. Some time ago, some of our Keemarnians, while experimenting in the Heavens, found themselves outside our atmosphere. They never returned. Across the roadway between the red planet ‘Mydot’—Mars I think you call it—and ourselves, are many
  • 56. rapidly moving meteoric bodies. We fear that our gallant brothers met one of these, and were destroyed. Many men of science went after these lost ones but none ever returned. Through our wonderful glass, we saw one of our air birds in space; it was unable to reach home. Then was the great magnetic ray discovered. In the shortest space of time it was perfected, and played on the silent air bird. Gradually it was drawn nearer and nearer to our shores until it was within our atmosphere, and was able to land in safety. Since that time, if air birds venture too high, we have nearly always been able to save the adventurous spirits, and in your case, we brought you safely here.” “It’s a wonderful invention,” said Sir John, “and I can imagine would have been of immense value to our airmen on earth.” Kulmervan then presented them to Waiko, and Mavis was led to a seat of honour on the dais. They spent a most enjoyable time, and the whole entertainment was very like what they were accustomed to on earth. Games were played,—games with balls and racquets, and balls and hoops, and between the games there was singing and dancing. Refreshments were served in a hall adjoining, and consisted mainly of luscious fruits and dainty cakes and pastries. The many Keemarnians they met, invited them in turn to parties and entertainments, and they felt they had more invitations than they could safely accept. “Never accept,” whispered Waz-Y-Kjesta to them all, “unless you mean to honour your host with your presence. A refusal never offends, but to accept and then to disappoint, is unforgivable.” Suddenly in the middle of the dancing a trumpet blew loud and clear. The band ceased and the couples stood still. Then rang out a fanfare of royal welcome, and the guests rushed to the entrance hall in great excitement, waving and cheering. “It must be some one of importance who is coming,” said Desmond. “Perhaps it is the Rorka,” suggested Mavis. There was a roll of drums, and then, on a litter carried by six stalwart men, entered a girl of perhaps eighteen years. The cortége stopped and Kulmervan bent low before her, and kissed her proffered hand. She bowed ever so slightly, and he assisted her from her cushioned throne. She stood beside him, and proved to be quite small, not more than five feet in height, but of a beauty almost indescribable. She was very fair and fragile. Her eyes
  • 57. were purple-blue fringed with long, black lashes. Her fillet was of gold, and was enriched with gems the colour of her eyes, while her robe of blue hung in folds about her. Perhaps it was her lips that impressed the watchers most. A perfect bow—they were of a vivid scarlet that contrasted strangely with the delicate pink flush of her cheeks. Self possessed, calm and regal she looked as she graciously acknowledged the plaudits of the guests. “Who is she, Alan?” asked Mavis. But he was unconscious of her question, he could only gaze and gaze at the beautiful apparition who had come so unexpectedly upon the scene. Waiko bent in turn before the stranger who whispered something to him. Immediately he came toward Mavis. “We are honoured to- night,” said he. “The Ipso-Rorka Chlorie has journeyed from Pyrmo to welcome you. She heard of your presence and came at once.” “Who is she?” asked Mavis. “Why the highest lady in the land—the only child of our Rorka.” Mavis went toward where the girl stood, and the Ipso-Rorka held out both her hands to the English girl. “Welcome,” said she, in a voice musical and low. “I hear you start soon to honour the Rorka, my father, with a visit. May I welcome you first?” In turn the others were presented to her, but her attention was all for Mavis—it was Mavis the woman she wanted to know. And Alan? He had seen his ideal! Years before, he wondered whether he would ever meet her—and now he had. And a King’s daughter! And he a stranger in a strange world! How dare he even lift his eyes toward her. Yet he dared—and his pulses leapt madly as his eyes feasted on her beauty. Not once did she address him—not once did she even seem to notice him. Chlorie put her hand lightly on Desmond’s arm. “I will dance with you,” said she smiling, and Alan watched them lead the merry throng of dancing couples. The demon of jealousy, earth jealousy, was in his heart. “Why are you looking so—how can I put it—so sad?” asked Kulmervan. Alan laughed. “He has a wife,” he muttered. “Why does he take her from others?” “But she has honoured him. It is not for us to choose for the Ipso- Rorka,” said Kulmervan.
  • 58. “Yes, but she is so beautiful, so sweet, so glorious,” began Alan. Then he stopped suddenly. “Oh,” he continued, “what do you people of Jupiter know of love or hate? Your lives are too quiet, too humdrum to know aught of passion—” “Teach me! Teach me!” cried Kulmervan leaning toward him. “Your face is drawn—your eye hard. Yet you look as if you could battle with the world. What is it?” “Love and hate,” said Alan grimly. Then he laughed. “What a fool I am. Desmond is my cousin; we love each other like brothers. He has won Mavis—why should he not dance with the Ipso-Rorka? Mavis does not mind.” But Kulmervan turned away in silence. Knowledge had come to him in a curious way. He saw passion, love, hatred, anger, jealousy all raging within a human heart. Unconsciously the feelings were photographed upon his too sensitive mind. Love that had only smouldered was now born in all its fury for the Princess Chlorie, the fair. And with love was born the twin, hate—hate for Alan, the man he feared might supplant him. It seemed as if death, although burned and purified, had brought into Keemar unrest and sin. The prayers of the High Priest himself were unable to wash it away, until scourged and purified the earth folk themselves became less material and more godlike and true. The day for the Sacrament of Schlerik-itata arrived at last and the strangers found themselves on the way to Ak-Marn’s palace. Although the Aks had no administrative powers, as had the Jkaks, they were held in the highest esteem, for they were princes of royal blood. Ak-Marn greeted them warmly. They saw that his dress was different from the usual male costume. He was in unrelieved white, and wore neither jewel nor ornament. The material of his robe, which hung with a long cloak to the ground, was almost like plush and there was something almost bridal about the costume. Yet Ak- Marn was an old man, with a beard of white, and grandchildren in plenty. Surely Schlerik-itata could not be the same as matrimony, thought Mavis. The guests were eight thousand in number, and all wore their brightest jewels and their finest raiment.
  • 59. There was singing and dancing and much gay chatter, and the whole scene was one of wonderful gaiety and joy. Refreshments were brought in, and Ak-Marn began to speak. The English people could now understand the Keemarnian language fairly well. It was easy, its grammar simple, and its pronunciation almost Latin. “Friends,” said Ak-Marn. “I break bread with you. Two and ten Kymos have sunk since I quenched my thirst or satisfied my hunger. I’ve prayed to Mitzor, the Great White Glory and Tower of Help, to prepare me for my journey. My call came eighty and five Kymos since —I saw the figures in fire. I heard my call, and am prepared. I go with hope in my heart—with joy in my breast. I am to be envied, my friends, for my days have been long upon Keemar. I leave my loved one, Viok, and our children, and our children’s children in your care, my friends. When I am gone, cheer her with loving words—help her with kind counsel. I leave you with love in my heart. I leave you with the knowledge that our parting is not for long. Soon you will join me in the home of the Tower of Help. Remember that the eternities of time cannot be measured.” Then bread was broken, and there followed the “Feast of the Sacrament,” and the most intimate friends of Ak-Marn drank to his “future”—drank to his coming “joy.” And Alan and Sir John were no longer mystified. They realized that what they in their materialism knew as “Death” was nigh—but not Death, the slayer of happiness, Death, the dread reaper, but Death in a kindly form, a death that gave life—a death that was glorious. “I thought at first that the Jovians were of a finer nature than ours,” said Alan. “If they have conquered Death, they must indeed be high,” said Sir John thoughtfully. “Who is Mitzor?” asked Mavis. “The God of our Fathers, my dear. The God of Abraham and the God of the New Testament. Whatever their religion and ritual is, they worship the same God as we do,” said Alan. “Are you sure?” “Quite.” When the feast was ended, the guests, one by one, bade farewell to their host. It was a long tedious business, as no one was permitted to
  • 60. pass without at least a few personal words from Ak-Marn who was seated on a raised chair near the doorway. And as each woman passed out, she was crowned with a wreath of beautiful, freshly cut flowers, from which hung a filmy white veil, while the men were given long white cloaks with hoods which they drew over their bare heads. Mavis bent her knee, and held out her hands to the kindly old man. “My child,” said he. “Our beautiful ceremony is so far meaningless to you. Go home—pray to Mitzor the Mighty that He may refine and cleanse you, that when your time comes you may be reincarnated to Him, through the medium of his Sacrament. Farewell.” To Alan he spoke long and quietly. “My son,” said he, “you are in a strange world, you are young, you are carnal. Ah,” as Alan would have protested, “we of Keemar, my Alan, are not as of your world. We know not sin as you know it. Our first parents, Menlin and Jorlar, were placed in a garden—” Alan started—“Yes, my friend, as your parents were. They succumbed not to temptation—so they lived in happy solitude for many years. Then Mitzor in His great kindness gave them the knowledge of Love—Love without sin. They mated. Their love grew. Children of love were born sinless into our world. Child bearing was a glory; motherhood the highest estate. They knew neither sin nor sorrow, and so in love our populace grew.” “Do you mean to say you are sinless here?” asked Alan incredulously. “My son, it is not an estate for us to glory in, for the merits do not belong to us, but to our first parents. No—real sin has never entered here, but we live in dread of its coming. In a far off country—in Fyjipo—there is built a large palace behind high walls. If anger, or lust, or impatience is shown by any one of us, an order is given and the offender is taken to the Hall of Sorrows to purge away his sins. Should a madness come upon us, for such we reckon these failings to be—we are kept safe until it has passed, and until we can no longer contaminate our fellow creatures.” “It’s a wonderful country,” said Alan. “Where we come from, is all sin and misery and—” “Nay, tell me not. I go on a journey. I shall face my Mitzor. I charge you, should you or your friends feel this madness coming on you, hide yourselves, I beg, in the Hall of Sorrows. Stay there until it has
  • 61. passed, and preserve the purity and happiness of this land. Farewell.” The cloak was fastened round Alan’s shoulders, and he too left the kindly presence. Waz-Y-Kjesta was waiting for them at the outer hall. “Go home,” he whispered. “Your bhor awaits you. I beg of you, eat no more this night, but in the early dawn, while Kymo still sleeps, put on your cloaks, and the Lady Mavis her veil, and go you to the Temple of Mitzor. Farewell.” It was a very solemn party that retired to their rooms that night, yet the full mystery of the Sacrament had not been unfolded to them. It was dark when they arose, and in a dim twilight they drove to the Temple. They had never before been inside it, and it was with much trepidation that they waited on the threshold. It was a very beautiful building of pale blue marble—the colour of the sky. An enormous dome rose up in the centre of the square body of the Temple, and at the four corners, minarets with gilded tops finished the picture. A flight of fifty steps led up to the doors which were of a burnished metal, and studded with precious gems. Just inside was an antechamber, where the guests waited in silence until they were ushered to the seats that were allotted to them. The inside was wonderful. Mosaic walls representing allegorical tales gleamed in the dim light; the roof was of gold, and marble pillars supported it down the long aisle. An enormous altar rose up at the further end upon which were carved in marble cherubim and seraphim. In the sanctuary, if such it could be called, was a small white throne of marble, with heavy, white curtains draped at either side. It was placed in such a position that although it did not intercept the view of the altar, which was high above the nave, yet it could be seen by every one in the building. The seats allotted to Alan and his party were very near the front where rails of gold separated the Sanctuary from the people’s part of the Temple. Music floated on the air—soft like babbling brooks and the song of birds; now bursting out into thunderous praise and mighty worship. Suddenly there came a solemn hush; a bell tinkled; the organ played softly, and there came the sound of boys’ sweet voices raised in ecstasy: from a door at the side of the choir a dozen acolytes walked dressed in their garments of white. The procession started
  • 62. down the nave. After these boys came priests and deacons, and then Misrath, the High Priest walked in front of a raised throne. On this sat Ak-Marn, his eyes closed and his hands clasped in prayer. Behind him walked his wife and their children. Their faces were radiant, it is true; yet there was a touch of sadness in his wife’s gait. Then followed more priests and acolytes, all singing hymns of joy. The procession wound round the Temple, and back through the middle aisle, and through the rails into the Sanctuary. Ak-Marn was led to the marble throne; his wife alone of his family had followed close behind, and now his arms were around her. Their lips met in one long kiss, then with a bowed head she left his side, and took her place with her family in the very front seats. The organ thundered. Voices rang in a mighty pæan of praise. Then silence! Misrath came forward and offered prayers to Mitzor— prayers of offering, prayers of supplication. A mighty wreath of freshly cut flowers was placed upon the altar. It was to be a burnt offering, and as the smoke of the sacrifice arose on the air, the white curtains were drawn around the figure of Ak-Marn and he was hidden from view. Then singing rent the air; the acolytes incensed the throne, until it was entirely covered by the perfumed smoke, covered like a pall. Alan watched in wonder. The grandeur of the prayers, the singing, the mystic curtains drawn around Ak-Marn appalled him. Misrath’s voice rose above the music. “Children of Keemar,” he intoned. “One more brother has been caught by the mantle of Mitzor, and has left this world for ever. He has gone to Glory, gone to Happiness—gone to Mitzor Himself. Peace be unto his house. Peace be unto his wife. Peace be unto his seed for ever. We bid him—farewell.” There was a great silence. The censers were stilled. Gradually the smoke of the incense cleared away from the marble throne, now gleaming in the rising rays of the Kymo. Misrath touched the cords of the enveloping curtain, and drew them back. The little white throne was empty! Ak-Marn had returned to the bosom of his Creator! But stay! On the floor, as if shed in the hurried flight of its owner, lay the bridal robe of Ak-Marn. The High Priest raised it, blessed it, sprinkled it with the waters of purity, and
  • 63. Ak-Marn’s wife received it in her arms. Then the mighty congregation rose and sang one last song of praise, and at the end, quietly left the building. And the last view Alan had of Ak-Marn’s wife was of a solitary figure, dressed like a bride, clasping the little white throne that was the last resting place of her loved one. “I don’t understand,” whispered Mavis hoarsely, as they were being driven back to their home. “My dear, he is dead,” said Sir John. “Dead? If that is Death, then it is something to welcome and not to dread,” she answered softly. There was a faraway look in her eyes. “What a wonderful Sacrament! Death that is no sorrow—only a parting for a little while, and then—reunion.” She clasped her husband’s hand. “Belovèd,” she murmured, “if Death comes to us like that, then can we have no real sorrow any more. Its shadow cannot cause us pain or grief. What do you think, Alan?” But Alan did not answer. He was thinking of two deep blue eyes, a laughing mouth, wilful golden curls that flirted on two soft, pink cheeks. He was longing to crush the lithe and sweet body close to his, and smother her roses with kisses. The knowledge and fear of Death had lapsed; Jupiter had eradicated it,—but with its extinction had come love. Love, stronger a thousandfold than Death. He looked upward to where the Sun, Kymo in all his glory, was shining. The whole world was bathed in a glory of light. Yes, Jupiter had conquered death, and before him lay life and love!
  • 64. CHAPTER VII HATRED ON KEEMAR Marlinok, the Jkak’s majordomo, called on Sir John and Alan a few days after they had witnessed the Sacrament of Schlerik-itata. “Will you be ready,” he asked them, “when the Kymo is at the full, to start on your journey to Hoormoori to render homage to the Rorka?” “Are we all to go?” asked Alan. “But one of you need go,” he answered. “The Rorka will visit Minniviar later, and then the other strangers may make their bows.” “I am glad of that,” said Sir John, “for I should like to stay here in quietness and retirement for a little while. I am beginning to feel the burden of my age, and am worn out with the strain of the last few years.” “I will go to Hoormoori,” announced Alan, “I can start at whatever time the Jkak thinks best.” “He has prepared incense and jewels for you to take as gifts from the absent ones,” said Marlinok, “if you will now see Waz-Y-Kjesta all your arrangements can be made.” “I’ll go now,” said Alan. Alan was going down a pretty lane toward where the air birds were housed when he suddenly became aware of footsteps behind him. He turned—immediately the footsteps ceased, and he could see no one. Thinking he must be mistaken, and fearing nothing from the Keemarnians, he went on his way blithely. The air was deliciously warm, and the fresh breeze, balmy with the scent of flowers, tempered it. Still the footsteps followed with monotonous regularity; as he hastened, so they became quicker; as his died down, so they ceased altogether. Yet he had no sense of fear, no feeling of impending evil; the thought of peril on Keemar was impossible to imagine. The Keemarnians were of a breed as different from the
  • 65. earth to which he belonged, as he was from Heaven! He passed delightful homely fields, gleaming with buttercups and daisies. Friendly cows chewed the cud in sleepy enjoyment. They did not rise as he drew near, but only raised their sleepy heads, and looked at him out of their liquid eyes with interest and friendliness. A pig grunted in a corner as she suckled her squealing young; a donkey brayed; a couple of goats were nibbling the grass while their kids frolicked near them. He saw strange animals too. There was the gorwa of the deer family, a beautiful creature, the colour of a Scottish stag, and its counterpart in miniature, but with none of its brother’s timidity. All the animals on Keemar were of a smaller build than those he had been accustomed to. The cows were even smaller then the little fawn Jerseys so valued in England. He had seen terriers and bull dogs, dalmatians and spaniels in this strange world, and the bigger breeds were all represented on a smaller scale. The Jkak had a dog—a Borzoi, Alan would have called it, yet perhaps it was no bigger than a small Irish terrier; but strangely enough, its beauty was not diminished by its minuteness. So Alan went on. The way was strange to him, but he was enjoying the calmness of the scene, and he knew his excellent bump of locality would sooner or later lead him to Y- Kjesta. Again the footsteps beat time with his own, and anxious for companionship, he stepped into the shadow of a tree, and hoped to waylay a shy, but friendly stranger. A second passed. The footsteps had ceased—then came a rustling, and the head of Kulmervan the Student appeared over a honeysuckle bush. Silently he came forward, alert and watchful until he was on a level with Alan. “Hullo!” said Alan amiably. “Where are you going, Kulmervan?” The effect was magical! Kulmervan jumped as though he had been struck, and his face whitened. He remained silent. “I’m going to see Waz-Y-Kjesta,” went on Alan. “Are you coming my way?” Kulmervan did not reply, but a baleful light gleamed in his eyes, and his mouth twitched. “What’s the matter?” asked Alan curiously. Suddenly Kulmervan spoke, and there was a wealth of passion in his tones. “Why did you come here, you strangers? I was happy until you came. I was contented. You have made me want—want the unknown. You have stirred my heart and filled it with longings that I
  • 66. cannot yet fathom. Why have you come to stir up misery among a happy and contented race?” “I don’t know what you mean,” said Alan, “I have done nothing.” “You’ve done everything. You dared to raise your eyes to the level of Chlorie, our Ipso-Rorka. You put thoughts about her into my head. Oh—” as Alan would have broken in—“I read your thoughts, it was easy, my friend. You dared to think of her as a woman—even your woman. It was an impertinence, I tell you. I love Chlorie with my whole soul, and before Mitzor the Mighty, I’ll carry her away into some far off land, before she can look with a favourable eye on a man, not only of another world, but a man of a coarser nature than our own.” Kulmervan was breathless when he finished, for his words had come thick and fast, tumbling over themselves in his great excitement. Alan was speechless, and looked as he felt, absolutely uncomfortable and ill at ease. “Why your very pose proves guilt,” continued Kulmervan. “Why should I not love Chlorie?” demanded Alan, “Why should my love for her cause strife between us?” “Because, my stranger, I am a Prince of the Rorka’s House. I am not only Kulmervan the Student; but Taz-Ak of the House of Pluthoz. Why else would Chlorie have honoured my party—why else come to the dance of a student? There are but four Keemarnians that Chlorie can marry, and I rank second.” Alan wondered at the time why the Princess should come in so natural a manner to the Student’s reception. He wondered at the time at her familiarity with Kulmervan. She had patted his hand, smiled into his eyes, and had honoured him more than once with a dance. But Alan, too, was in love. Idiotically, insanely in love with a woman who had not even troubled to raise her eyes to his, at his presentation. His pulses throbbed at the remembrance of the touch of her fingertips as he raised them to his lips. He loved her, and in that moment was born a desire to overcome all obstacles, and princess or no princess, to win her. But he knew too that in this pleasant land of Keemar an enmity had come upon him, and wondered whether the Curse of Death had brought it. He wondered
  • 67. whether the dead and decomposed body of their faithful Murdoch had indeed brought sorrow to this fair land. “I’ve spoken to your Ipso-Rorka only once,” said he. “The night of your party. She has called on my uncle and Mavis. Mavis has been out driving with her several times. But I, unfortunately, have missed her each time. Surely you are not jealous because I—” “Because you love her? I am,” said Kulmervan thickly, “and I say this—if you so much as dare to raise your eyes to her, if you dare to address her, I’ll make you suffer for it—aye, even though I also suffer eternally for it,” and with that he turned on his heel and walked quickly away. Alan was very perturbed about this meeting, and felt inclined to tell the story of it to Waz-Y-Kjesta,—yet the sacred feeling he had for Chlorie was not to be spoken of, or bandied about from man to man. No, he would keep it to himself, and trust to time and common sense to cure Kulmervan of his strange hatred. He walked quickly on, and already could see the air birds in the distance, circling above their houses. The little lane turned quickly at right angles—there was a steep descent, and hedges rose at either side to a height of six or seven feet, while the overhanging branches of the trees met in the middle and formed a leafy arch. The grassy banks were carpeted with flowers, and the scent hung sweet on the air. Again the narrow path turned sharply to the right, and before Alan realized it, there almost at his feet, stretched across almost the full width of the path, lay a lion, full grown, with his shaggy mane stirring in the breeze. Alan stopped suddenly, and his heart beat quickly. The lion’s eyes were closed—he was sleeping. The Englishman was almost afraid to move lest the savage beast should spring upon him and devour him. He looked round to the right, the bough of a tree hung low over the path. He leapt up the bank, and with one mighty spring caught hold of it, and swarmed up to a topmost branch. He was safe—but the sudden sound had startled the lion, who rose up and with a low growl prowled backward and forward beneath the tree. It was an uncomfortable position to be in—the tree bough was very thin, and bent and twisted and crackled ominously. Still the King of
  • 68. Beasts remained sentinel underneath. Alan felt the perspiration on his face as the limb shivered and bent, yet there was no other to which he could move. Still the animal remained near, his quickened senses no doubt wondering at the noise he heard, and waiting to see what had caused it. The minutes dragged by—the branch was weakening perceptibly— he could already see the white of the inside where the branch was gradually tearing away from the parent trunk. There was no one in sight, and still the lion walked restlessly to and fro. The Kymo was sinking rapidly. It was already low down on the horizon, and Alan knew he had been about two English hours in his perilous position. He saw a branch above his head, and he wormed his way along to see if he could in any way reach it. Carefully he went —slowly—suddenly with a scream and a crash the branch gave way, and Alan felt himself being hurled to the ground. The distance was not great, and he landed in the centre of some sweet-smelling, soft bushes. He was dazed, and wondered when the lion would pounce. He knew he was powerless to help himself. He heard the pad, pad, of its feet; he could hear the sharp intake of its breath—then the thing was upon him. He shut his eyes and waited.— Nothing happened but the snuffing of the wild beast, and a gentle nosing as it examined the stranger. Alan opened his eyes. The animal was sitting on its haunches surveying him, and he felt there was amusement in the beast’s eyes as it watched him. He moved slightly—still the beast watched motionless. He raised himself up from the encircling bushes and clambered down. He knew he would have to face the inevitable. Suddenly a voice hailed him, and he saw Waz-Y-Kjesta coming round the bend in the lane. “Stand back,” he cried. “There’s a lion here—he may spring!” But the Waz came on fearlessly. Alan was petrified, his tongue was parched, no sound came from his lips. He watched the Waz in frozen horror. The Keemarnian was smiling. “Where have you been, my friend? You are late—very late. I thought you had missed your way, so I came to seek you.” He was now within three feet of the lion. “What is the matter? Why are you so grave? Has aught affrighted you?”
  • 69. Alan pointed to the tawny beast. His hand was shaking. Surely the farce must end soon, the lion spring, and tragedy culminate the play. “Why Maquer,” said the Waz affectionately, “what are you doing here? You seldom visit us, you know.” The lion moved toward him, and rubbed his great head against the Keemarnian’s leg, while Y-Kjesta talked to him and petted him. “He’s tame then?” gasped Alan with a rush of relief. “You know him?” “No, my friend. I’ve never seen this Maquer before—they generally stay in rocky places.” “But he is so friendly.” “All beasts are friendly here, my Alan. What—would Maquer have hurt you on your Earth?” And Alan laughingly told of his fright at the lion. He had learnt one more truth about Keemar—there were no savage animals upon it. Of a truth, it was a perfect land! Waz-Y-Kjesta was highly amused at his friend’s story, and together they went toward the air birds. The Keemarnian airships were indeed wonderful creations. White and gold, they were shaped like swans, with graceful wings outspread, gleaming in the light. They were made of a mixture of wood and metal, and contained accommodation for perhaps forty passengers, as well as the Waz in command, and a staff of ten. Although not as big as the ill-fated Argenta, the Keemarnian airship was possessed of a speed nearly thrice as great. “This is the Chlorie,” said Y-Kjesta, “and our fastest bird. The Jkak has given orders that you are to choose your own vessel, so perhaps you would like to see over some others?” “No,” said Alan, looking at the blue hangings, and seeing in them the reflection of his love’s eyes. “No, this one will do beautifully.” And the Waz was impressed by the easy way in which his friend was pleased. He little realized that it was the name of the vessel—the Chlorie—that attracted him. And in the strangeness of it Alan tried to read his fate. “We’ll go for a short cruise,” said the Waz, “and go back to the landing stage Minniviar.”
  • 70. There was not a cloud in the sky, and the warmth from the sun’s rays was pleasant. “I can’t understand how you benefit so considerably from the sun, your Kymo,” said Alan. “Let me see, you must be at least five times further away from the sun than we were on our earth, yet instead of your light and heat being reduced to about one twenty-fifth of our supply, you appear to benefit to exactly the same degree.” “Ah, my friend, that is easy to explain. Dark clouds hover outside our globe—” “Yes, bands of vapour,” corrected Alan. “Well—vapour. These bands completely encircle our world. They are saturated with a composition of gas, sulphuric ether I think you would call it. Well, this gas acts as a trap to the sun’s rays. It admits the solar rays to our planet but prevents their withdrawal. Therefore it permits the heat to enter, but prevents its escape.” “Well?” “Consequently we get the maximum of light, and an equable temperature.” “Do you then, have no seasons here?” “Seasons?” “Yes, Spring or Winter.” “Oh yes, it is cold at the poles—very cold, but as we get nearer to the equator it becomes warmer, and hardly varies. You see, my Alan, our world differs from yours. The axis of rotation is almost perpendicular to our orbit, consequently we are not subject to seasons as you were in Quilphis.” “I didn’t know that before.” “We too, are more flattened at each end—indeed, there are many differences between our world that is, and yours that was.” “Do you ever have rain here?” “Yes, my Alan. How else would plants live and crops thrive? But again, we do not suffer from excesses.” “But don’t you have hurricanes that last from six to seven weeks? Surely those are excesses.” “Hurricanes? I do not know the word.”
  • 71. Welcome to Our Bookstore - The Ultimate Destination for Book Lovers Are you passionate about books and eager to explore new worlds of knowledge? At our website, we offer a vast collection of books that cater to every interest and age group. From classic literature to specialized publications, self-help books, and children’s stories, we have it all! Each book is a gateway to new adventures, helping you expand your knowledge and nourish your soul Experience Convenient and Enjoyable Book Shopping Our website is more than just an online bookstore—it’s a bridge connecting readers to the timeless values of culture and wisdom. With a sleek and user-friendly interface and a smart search system, you can find your favorite books quickly and easily. Enjoy special promotions, fast home delivery, and a seamless shopping experience that saves you time and enhances your love for reading. Let us accompany you on the journey of exploring knowledge and personal growth! ebookgate.com