<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>django</title><link>http://agiliq.com/blog/tag/django/</link><description>Category: django</description><atom:link href="http://agiliq.com/blog/rss/latest/django/" rel="self"></atom:link><language>en-us</language><lastBuildDate>Mon, 11 Dec 2017 11:20:41 -0000</lastBuildDate><item><title>Django 2.0 Window expressions tutorial</title><link>http://agiliq.com/blog/2017/12/django-20-window-expressions-tutorial/</link><description>&lt;p&gt;Django 2.0 was &lt;a class="reference external" href="https://docs.djangoproject.com/en/2.0/releases/"&gt;released recently&lt;/a&gt; and among the most exciting things for me is support for Window expressions, which allows adding an OVER clause to querysets. We will use Window expressions to analyze the commits data to the Django repo.&lt;/p&gt;
&lt;div class="section" id="so-what-is-an-over-clause"&gt;
&lt;h1&gt;So what is an over clause?&lt;/h1&gt;
&lt;p&gt;An over clause is of this format&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="n"&gt;depname&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;empno&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;salary&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="k"&gt;avg&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;salary&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;OVER&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;PARTITION&lt;/span&gt; &lt;span class="k"&gt;BY&lt;/span&gt; &lt;span class="n"&gt;depname&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;empsalary&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Compare this to a similar &lt;cite&gt;GROUP BY&lt;/cite&gt; statement&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="n"&gt;depname&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;avg&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;salary&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;empsalary&lt;/span&gt;
&lt;span class="k"&gt;GROUP&lt;/span&gt; &lt;span class="k"&gt;BY&lt;/span&gt; &lt;span class="n"&gt;depname&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The difference is a &lt;cite&gt;GROUP BY&lt;/cite&gt; has as many rows as grouping elements, here number of &lt;cite&gt;depname&lt;/cite&gt;. An over clause adds the the aggregated result to each row of the select.&lt;/p&gt;
&lt;p&gt;&lt;a class="reference external" href="https://www.postgresql.org/docs/9.1/static/tutorial-window.html"&gt;Postgres documentation says&lt;/a&gt;, &amp;quot;A window function performs a calculation across a set of table rows that are somehow related to the current row. This is comparable to the type of calculation that can be done with an aggregate function. But unlike regular aggregate functions, use of a window function does not cause rows to become grouped into a single output row — the rows retain their separate identities. Behind the scenes, the window function is able to access more than just the current row of the query result.&amp;quot; This is true for all other DB implementation as well.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="what-are-real-world-uses-of-over-expressions"&gt;
&lt;h1&gt;What are real world uses of over expressions?&lt;/h1&gt;
&lt;p&gt;We will use the Django ORM with the &lt;cite&gt;Window&lt;/cite&gt; expression to to some analysis on the most prolific committers to Django. To do this we will export the commiter names and time of commit to a csv.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;git log  --no-merges --date&lt;span class="o"&gt;=&lt;/span&gt;iso --pretty&lt;span class="o"&gt;=&lt;/span&gt;format:&lt;span class="s1"&gt;&amp;#39;%h|%an|%aI&amp;#39;&lt;/span&gt; &amp;gt; commits.iso.csv
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This is not ranking of Django developers, just of their number of commits, which allows us an interestig dataset. I am grateful to everyone who has contributed to Django - they have made my life immesureably better.&lt;/p&gt;
&lt;p&gt;With some light data wrangling using Pandas, we transform this to a per author, per year data and import to Postgres. Our table structure looks like this.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;experiments&lt;/span&gt;&lt;span class="o"&gt;=#&lt;/span&gt; &lt;span class="err"&gt;\&lt;/span&gt;&lt;span class="n"&gt;d&lt;/span&gt; &lt;span class="n"&gt;commits_by_year&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
   &lt;span class="k"&gt;Table&lt;/span&gt; &lt;span class="ss"&gt;&amp;quot;public.commits_by_year&amp;quot;&lt;/span&gt;
    &lt;span class="k"&gt;Column&lt;/span&gt;     &lt;span class="o"&gt;|&lt;/span&gt;  &lt;span class="k"&gt;Type&lt;/span&gt;   &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;Modifiers&lt;/span&gt;
&lt;span class="c1"&gt;---------------+---------+-----------&lt;/span&gt;
 &lt;span class="n"&gt;id&lt;/span&gt;            &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nb"&gt;bigint&lt;/span&gt;  &lt;span class="o"&gt;|&lt;/span&gt;
 &lt;span class="n"&gt;author&lt;/span&gt;        &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nb"&gt;text&lt;/span&gt;    &lt;span class="o"&gt;|&lt;/span&gt;
 &lt;span class="n"&gt;commit_year&lt;/span&gt;   &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nb"&gt;integer&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;
 &lt;span class="n"&gt;commits_count&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nb"&gt;integer&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;We define a model to interact with this table.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;django.db&lt;/span&gt; &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="n"&gt;models&lt;/span&gt;


&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Committer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;models&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Model&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;author&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;models&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CharField&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;max_length&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;commit_year&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;models&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;PositiveIntegerField&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;commits_count&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;models&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;PositiveIntegerField&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Meta&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;db_table&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;&amp;#39;commits_by_year&amp;#39;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Lets quickly test if our data is imported. &lt;a class="reference external" href="https://github.com/shabda/experiments/blob/master/data/commits_by_year.csv"&gt;You can get a csv from here&lt;/a&gt;, and import to Postgres to follow along.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;In&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt; &lt;span class="n"&gt;Committer&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;objects&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;all&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;count&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;Out&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt; &lt;span class="mi"&gt;2318&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Let us setup our environment and get the imports we need.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;## Some ORM imports which we are going to need

from django.db.models import Avg, F, Window
from django.db.models.functions import  Rank, DenseRank, CumeDist
from django_commits.models import Committer

# We will use pandas to display the queryset in tanular format
import pandas
pandas.options.display.max_rows=20

# An utility function to display querysets
def as_table(values_queryset):
    return pandas.DataFrame(list(values_queryset))
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Lets quickly look at the data we have.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;as_table(Committer.objects.all().values(
  &amp;quot;author&amp;quot;, &amp;quot;commit_year&amp;quot;, &amp;quot;commits_count&amp;quot;
))
&lt;/pre&gt;&lt;/div&gt;
&lt;div&gt;
&lt;style scoped&gt;
    .dataframe tbody tr th:only-of-type {
        vertical-align: middle;
    }

    .dataframe tbody tr th {
        vertical-align: top;
    }

    .dataframe thead th {
        text-align: right;
    }
&lt;/style&gt;
&lt;table border="1" class="dataframe"&gt;
  &lt;thead&gt;
    &lt;tr style="text-align: right;"&gt;
      &lt;th&gt;&lt;/th&gt;
      &lt;th&gt;author&lt;/th&gt;
      &lt;th&gt;commit_year&lt;/th&gt;
      &lt;th&gt;commits_count&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;th&gt;0&lt;/th&gt;
      &lt;td&gt;Tim Graham&lt;/td&gt;
      &lt;td&gt;2017&lt;/td&gt;
      &lt;td&gt;373&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;th&gt;1&lt;/th&gt;
      &lt;td&gt;Sergey Fedoseev&lt;/td&gt;
      &lt;td&gt;2017&lt;/td&gt;
      &lt;td&gt;158&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;th&gt;2&lt;/th&gt;
      &lt;td&gt;Mariusz Felisiak&lt;/td&gt;
      &lt;td&gt;2017&lt;/td&gt;
      &lt;td&gt;113&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;th&gt;3&lt;/th&gt;
      &lt;td&gt;Claude Paroz&lt;/td&gt;
      &lt;td&gt;2017&lt;/td&gt;
      &lt;td&gt;102&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;th&gt;4&lt;/th&gt;
      &lt;td&gt;Mads Jensen&lt;/td&gt;
      &lt;td&gt;2017&lt;/td&gt;
      &lt;td&gt;55&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;th&gt;5&lt;/th&gt;
      &lt;td&gt;Simon Charette&lt;/td&gt;
      &lt;td&gt;2017&lt;/td&gt;
      &lt;td&gt;40&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;th&gt;6&lt;/th&gt;
      &lt;td&gt;Jon Dufresne&lt;/td&gt;
      &lt;td&gt;2017&lt;/td&gt;
      &lt;td&gt;33&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;th&gt;7&lt;/th&gt;
      &lt;td&gt;Anton Samarchyan&lt;/td&gt;
      &lt;td&gt;2017&lt;/td&gt;
      &lt;td&gt;27&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;th&gt;8&lt;/th&gt;
      &lt;td&gt;François Freitag&lt;/td&gt;
      &lt;td&gt;2017&lt;/td&gt;
      &lt;td&gt;17&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;th&gt;9&lt;/th&gt;
      &lt;td&gt;Srinivas Reddy Thatiparthy&lt;/td&gt;
      &lt;td&gt;2017&lt;/td&gt;
      &lt;td&gt;14&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;th&gt;...&lt;/th&gt;
      &lt;td&gt;...&lt;/td&gt;
      &lt;td&gt;...&lt;/td&gt;
      &lt;td&gt;...&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;th&gt;2308&lt;/th&gt;
      &lt;td&gt;Malcolm Tredinnick&lt;/td&gt;
      &lt;td&gt;2006&lt;/td&gt;
      &lt;td&gt;175&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;th&gt;2309&lt;/th&gt;
      &lt;td&gt;Georg Bauer&lt;/td&gt;
      &lt;td&gt;2006&lt;/td&gt;
      &lt;td&gt;90&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;th&gt;2310&lt;/th&gt;
      &lt;td&gt;Russell Keith-Magee&lt;/td&gt;
      &lt;td&gt;2006&lt;/td&gt;
      &lt;td&gt;86&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;th&gt;2311&lt;/th&gt;
      &lt;td&gt;Jacob Kaplan-Moss&lt;/td&gt;
      &lt;td&gt;2006&lt;/td&gt;
      &lt;td&gt;83&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;th&gt;2312&lt;/th&gt;
      &lt;td&gt;Luke Plant&lt;/td&gt;
      &lt;td&gt;2006&lt;/td&gt;
      &lt;td&gt;20&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;th&gt;2313&lt;/th&gt;
      &lt;td&gt;Wilson Miner&lt;/td&gt;
      &lt;td&gt;2006&lt;/td&gt;
      &lt;td&gt;12&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;th&gt;2314&lt;/th&gt;
      &lt;td&gt;Adrian Holovaty&lt;/td&gt;
      &lt;td&gt;2005&lt;/td&gt;
      &lt;td&gt;1015&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;th&gt;2315&lt;/th&gt;
      &lt;td&gt;Jacob Kaplan-Moss&lt;/td&gt;
      &lt;td&gt;2005&lt;/td&gt;
      &lt;td&gt;130&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;th&gt;2316&lt;/th&gt;
      &lt;td&gt;Georg Bauer&lt;/td&gt;
      &lt;td&gt;2005&lt;/td&gt;
      &lt;td&gt;112&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;th&gt;2317&lt;/th&gt;
      &lt;td&gt;Wilson Miner&lt;/td&gt;
      &lt;td&gt;2005&lt;/td&gt;
      &lt;td&gt;20&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;2318 rows × 3 columns&lt;/p&gt;
&lt;/div&gt;&lt;p&gt;We will now use the Window expression to get the contributors ranked
by number of commits, within each year. We will go over the code in detail, but lets look at the queryset and results.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;# Find out who have been the most prolific contributors
# in the years 2010-2017

dense_rank_by_year = Window(
    expression=DenseRank(),
    partition_by=F(&amp;quot;commit_year&amp;quot;),
    order_by=F(&amp;quot;commits_count&amp;quot;).desc()
)

commiters_with_rank = Committer.objects.filter(
        commit_year__gte=2010, commits_count__gte=10
    ).annotate(
        the_rank=dense_rank_by_year
    ).order_by(
        &amp;quot;-commit_year&amp;quot;, &amp;quot;the_rank&amp;quot;
    ).values(
        &amp;quot;author&amp;quot;, &amp;quot;commit_year&amp;quot;, &amp;quot;commits_count&amp;quot;, &amp;quot;the_rank&amp;quot;
    )
as_table(commiters_with_rank)
&lt;/pre&gt;&lt;/div&gt;
&lt;div&gt;
&lt;style scoped&gt;
    .dataframe tbody tr th:only-of-type {
        vertical-align: middle;
    }

    .dataframe tbody tr th {
        vertical-align: top;
    }

    .dataframe thead th {
        text-align: right;
    }
&lt;/style&gt;
&lt;table border="1" class="dataframe"&gt;
  &lt;thead&gt;
    &lt;tr style="text-align: right;"&gt;
      &lt;th&gt;&lt;/th&gt;
      &lt;th&gt;author&lt;/th&gt;
      &lt;th&gt;commit_year&lt;/th&gt;
      &lt;th&gt;commits_count&lt;/th&gt;
      &lt;th&gt;the_rank&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;th&gt;0&lt;/th&gt;
      &lt;td&gt;Tim Graham&lt;/td&gt;
      &lt;td&gt;2017&lt;/td&gt;
      &lt;td&gt;373&lt;/td&gt;
      &lt;td&gt;1&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;th&gt;1&lt;/th&gt;
      &lt;td&gt;Sergey Fedoseev&lt;/td&gt;
      &lt;td&gt;2017&lt;/td&gt;
      &lt;td&gt;158&lt;/td&gt;
      &lt;td&gt;2&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;th&gt;2&lt;/th&gt;
      &lt;td&gt;Mariusz Felisiak&lt;/td&gt;
      &lt;td&gt;2017&lt;/td&gt;
      &lt;td&gt;113&lt;/td&gt;
      &lt;td&gt;3&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;th&gt;3&lt;/th&gt;
      &lt;td&gt;Claude Paroz&lt;/td&gt;
      &lt;td&gt;2017&lt;/td&gt;
      &lt;td&gt;102&lt;/td&gt;
      &lt;td&gt;4&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;th&gt;4&lt;/th&gt;
      &lt;td&gt;Mads Jensen&lt;/td&gt;
      &lt;td&gt;2017&lt;/td&gt;
      &lt;td&gt;55&lt;/td&gt;
      &lt;td&gt;5&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;th&gt;5&lt;/th&gt;
      &lt;td&gt;Simon Charette&lt;/td&gt;
      &lt;td&gt;2017&lt;/td&gt;
      &lt;td&gt;40&lt;/td&gt;
      &lt;td&gt;6&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;th&gt;6&lt;/th&gt;
      &lt;td&gt;Jon Dufresne&lt;/td&gt;
      &lt;td&gt;2017&lt;/td&gt;
      &lt;td&gt;33&lt;/td&gt;
      &lt;td&gt;7&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;th&gt;7&lt;/th&gt;
      &lt;td&gt;Anton Samarchyan&lt;/td&gt;
      &lt;td&gt;2017&lt;/td&gt;
      &lt;td&gt;27&lt;/td&gt;
      &lt;td&gt;8&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;th&gt;8&lt;/th&gt;
      &lt;td&gt;François Freitag&lt;/td&gt;
      &lt;td&gt;2017&lt;/td&gt;
      &lt;td&gt;17&lt;/td&gt;
      &lt;td&gt;9&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;th&gt;9&lt;/th&gt;
      &lt;td&gt;Srinivas Reddy Thatiparthy&lt;/td&gt;
      &lt;td&gt;2017&lt;/td&gt;
      &lt;td&gt;14&lt;/td&gt;
      &lt;td&gt;10&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;th&gt;...&lt;/th&gt;
      &lt;td&gt;...&lt;/td&gt;
      &lt;td&gt;...&lt;/td&gt;
      &lt;td&gt;...&lt;/td&gt;
      &lt;td&gt;...&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;th&gt;171&lt;/th&gt;
      &lt;td&gt;Joseph Kocherhans&lt;/td&gt;
      &lt;td&gt;2010&lt;/td&gt;
      &lt;td&gt;53&lt;/td&gt;
      &lt;td&gt;11&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;th&gt;172&lt;/th&gt;
      &lt;td&gt;Ramiro Morales&lt;/td&gt;
      &lt;td&gt;2010&lt;/td&gt;
      &lt;td&gt;53&lt;/td&gt;
      &lt;td&gt;11&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;th&gt;173&lt;/th&gt;
      &lt;td&gt;Jacob Kaplan-Moss&lt;/td&gt;
      &lt;td&gt;2010&lt;/td&gt;
      &lt;td&gt;42&lt;/td&gt;
      &lt;td&gt;12&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;th&gt;174&lt;/th&gt;
      &lt;td&gt;Chris Beaven&lt;/td&gt;
      &lt;td&gt;2010&lt;/td&gt;
      &lt;td&gt;29&lt;/td&gt;
      &lt;td&gt;13&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;th&gt;175&lt;/th&gt;
      &lt;td&gt;Malcolm Tredinnick&lt;/td&gt;
      &lt;td&gt;2010&lt;/td&gt;
      &lt;td&gt;26&lt;/td&gt;
      &lt;td&gt;14&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;th&gt;176&lt;/th&gt;
      &lt;td&gt;Honza Král&lt;/td&gt;
      &lt;td&gt;2010&lt;/td&gt;
      &lt;td&gt;20&lt;/td&gt;
      &lt;td&gt;15&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;th&gt;177&lt;/th&gt;
      &lt;td&gt;Carl Meyer&lt;/td&gt;
      &lt;td&gt;2010&lt;/td&gt;
      &lt;td&gt;17&lt;/td&gt;
      &lt;td&gt;16&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;th&gt;178&lt;/th&gt;
      &lt;td&gt;Ian Kelly&lt;/td&gt;
      &lt;td&gt;2010&lt;/td&gt;
      &lt;td&gt;17&lt;/td&gt;
      &lt;td&gt;16&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;th&gt;179&lt;/th&gt;
      &lt;td&gt;Simon Meers&lt;/td&gt;
      &lt;td&gt;2010&lt;/td&gt;
      &lt;td&gt;11&lt;/td&gt;
      &lt;td&gt;17&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;th&gt;180&lt;/th&gt;
      &lt;td&gt;Gary Wilson Jr&lt;/td&gt;
      &lt;td&gt;2010&lt;/td&gt;
      &lt;td&gt;10&lt;/td&gt;
      &lt;td&gt;18&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;181 rows × 4 columns&lt;/p&gt;
&lt;/div&gt;&lt;p&gt;Lets look a the the ORM code in more detail here.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;# We are creating the Window function part of our SQL query here
dense_rank_by_year = Window(
    # We want to get the Rank with no gaps
    expression=DenseRank(),
    # We want to partition the queryset on commit_year
    # Each distinct commit_year is a different partition
    partition_by=F(&amp;quot;commit_year&amp;quot;),
    # This decides the ordering within each partition
    order_by=F(&amp;quot;commits_count&amp;quot;).desc()
)


commiters_with_rank = Committer.objects.filter(
        commit_year__gte=2010, commits_count__gte=10
    # Standard filter oprtation, limit rows to 2010-2017
    ).annotate(
    # For each commiter, we are annotating its rank
        the_rank=dense_rank_by_year
    ).order_by(
        &amp;quot;-commit_year&amp;quot;, &amp;quot;the_rank&amp;quot;
    ).values(
        &amp;quot;author&amp;quot;, &amp;quot;commit_year&amp;quot;, &amp;quot;commits_count&amp;quot;, &amp;quot;the_rank&amp;quot;
    )
as_table(commiters_with_rank)
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Now lets try getting the average commits per commiter for each year along with the other data.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;avg_commits_per_year = Window(
    # We want the average of commits per committer, with each partition
    expression=Avg(&amp;quot;commits_count&amp;quot;),
    # Each individual year is a partition.
    partition_by=F(&amp;quot;commit_year&amp;quot;)
)

commiters_with_yearly_average = Committer.objects.filter().annotate(
      avg_commit_per_year=avg_commits_per_year
    ).values(
        &amp;quot;author&amp;quot;, &amp;quot;commit_year&amp;quot;, &amp;quot;commits_count&amp;quot;, &amp;quot;avg_commit_per_year&amp;quot;
    )
# We could have done further operation with avg_commit_per_year
# Eg: F(commits_count) - F(avg_commit_per_year),
# would tell us committers who commit more than average
as_table(commiters_with_yearly_average)
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This gives us&lt;/p&gt;
&lt;div&gt;
&lt;style scoped&gt;
    .dataframe tbody tr th:only-of-type {
        vertical-align: middle;
    }

    .dataframe tbody tr th {
        vertical-align: top;
    }

    .dataframe thead th {
        text-align: right;
    }
&lt;/style&gt;
&lt;table border="1" class="dataframe"&gt;
  &lt;thead&gt;
    &lt;tr style="text-align: right;"&gt;
      &lt;th&gt;&lt;/th&gt;
      &lt;th&gt;author&lt;/th&gt;
      &lt;th&gt;avg_commit_per_year&lt;/th&gt;
      &lt;th&gt;commit_year&lt;/th&gt;
      &lt;th&gt;commits_count&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;th&gt;0&lt;/th&gt;
      &lt;td&gt;Wilson Miner&lt;/td&gt;
      &lt;td&gt;319.250000&lt;/td&gt;
      &lt;td&gt;2005&lt;/td&gt;
      &lt;td&gt;20&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;th&gt;1&lt;/th&gt;
      &lt;td&gt;Adrian Holovaty&lt;/td&gt;
      &lt;td&gt;319.250000&lt;/td&gt;
      &lt;td&gt;2005&lt;/td&gt;
      &lt;td&gt;1015&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;th&gt;2&lt;/th&gt;
      &lt;td&gt;Jacob Kaplan-Moss&lt;/td&gt;
      &lt;td&gt;319.250000&lt;/td&gt;
      &lt;td&gt;2005&lt;/td&gt;
      &lt;td&gt;130&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;th&gt;3&lt;/th&gt;
      &lt;td&gt;Georg Bauer&lt;/td&gt;
      &lt;td&gt;319.250000&lt;/td&gt;
      &lt;td&gt;2005&lt;/td&gt;
      &lt;td&gt;112&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;th&gt;4&lt;/th&gt;
      &lt;td&gt;Russell Keith-Magee&lt;/td&gt;
      &lt;td&gt;188.571429&lt;/td&gt;
      &lt;td&gt;2006&lt;/td&gt;
      &lt;td&gt;86&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;th&gt;5&lt;/th&gt;
      &lt;td&gt;Jacob Kaplan-Moss&lt;/td&gt;
      &lt;td&gt;188.571429&lt;/td&gt;
      &lt;td&gt;2006&lt;/td&gt;
      &lt;td&gt;83&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;th&gt;6&lt;/th&gt;
      &lt;td&gt;Luke Plant&lt;/td&gt;
      &lt;td&gt;188.571429&lt;/td&gt;
      &lt;td&gt;2006&lt;/td&gt;
      &lt;td&gt;20&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;th&gt;7&lt;/th&gt;
      &lt;td&gt;Wilson Miner&lt;/td&gt;
      &lt;td&gt;188.571429&lt;/td&gt;
      &lt;td&gt;2006&lt;/td&gt;
      &lt;td&gt;12&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;th&gt;8&lt;/th&gt;
      &lt;td&gt;Adrian Holovaty&lt;/td&gt;
      &lt;td&gt;188.571429&lt;/td&gt;
      &lt;td&gt;2006&lt;/td&gt;
      &lt;td&gt;854&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;th&gt;9&lt;/th&gt;
      &lt;td&gt;Malcolm Tredinnick&lt;/td&gt;
      &lt;td&gt;188.571429&lt;/td&gt;
      &lt;td&gt;2006&lt;/td&gt;
      &lt;td&gt;175&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;th&gt;...&lt;/th&gt;
      &lt;td&gt;...&lt;/td&gt;
      &lt;td&gt;...&lt;/td&gt;
      &lt;td&gt;...&lt;/td&gt;
      &lt;td&gt;...&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;th&gt;2308&lt;/th&gt;
      &lt;td&gt;Adam Johnson&lt;/td&gt;
      &lt;td&gt;4.916084&lt;/td&gt;
      &lt;td&gt;2017&lt;/td&gt;
      &lt;td&gt;13&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;th&gt;2309&lt;/th&gt;
      &lt;td&gt;Tom&lt;/td&gt;
      &lt;td&gt;4.916084&lt;/td&gt;
      &lt;td&gt;2017&lt;/td&gt;
      &lt;td&gt;13&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;th&gt;2310&lt;/th&gt;
      &lt;td&gt;Srinivas Reddy Thatiparthy&lt;/td&gt;
      &lt;td&gt;4.916084&lt;/td&gt;
      &lt;td&gt;2017&lt;/td&gt;
      &lt;td&gt;14&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;th&gt;2311&lt;/th&gt;
      &lt;td&gt;François Freitag&lt;/td&gt;
      &lt;td&gt;4.916084&lt;/td&gt;
      &lt;td&gt;2017&lt;/td&gt;
      &lt;td&gt;17&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;th&gt;2312&lt;/th&gt;
      &lt;td&gt;Anton Samarchyan&lt;/td&gt;
      &lt;td&gt;4.916084&lt;/td&gt;
      &lt;td&gt;2017&lt;/td&gt;
      &lt;td&gt;27&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;th&gt;2313&lt;/th&gt;
      &lt;td&gt;Jon Dufresne&lt;/td&gt;
      &lt;td&gt;4.916084&lt;/td&gt;
      &lt;td&gt;2017&lt;/td&gt;
      &lt;td&gt;33&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;th&gt;2314&lt;/th&gt;
      &lt;td&gt;Simon Charette&lt;/td&gt;
      &lt;td&gt;4.916084&lt;/td&gt;
      &lt;td&gt;2017&lt;/td&gt;
      &lt;td&gt;40&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;th&gt;2315&lt;/th&gt;
      &lt;td&gt;Mads Jensen&lt;/td&gt;
      &lt;td&gt;4.916084&lt;/td&gt;
      &lt;td&gt;2017&lt;/td&gt;
      &lt;td&gt;55&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;th&gt;2316&lt;/th&gt;
      &lt;td&gt;Claude Paroz&lt;/td&gt;
      &lt;td&gt;4.916084&lt;/td&gt;
      &lt;td&gt;2017&lt;/td&gt;
      &lt;td&gt;102&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;th&gt;2317&lt;/th&gt;
      &lt;td&gt;Mariusz Felisiak&lt;/td&gt;
      &lt;td&gt;4.916084&lt;/td&gt;
      &lt;td&gt;2017&lt;/td&gt;
      &lt;td&gt;113&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;2318 rows × 4 columns&lt;/p&gt;
&lt;/div&gt;&lt;p&gt;You could try other Window functions such as &lt;cite&gt;CumeDist&lt;/cite&gt;, &lt;cite&gt;Rank&lt;/cite&gt; or &lt;cite&gt;Ntile&lt;/cite&gt;.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;from django.db.models.functions import CumeDist
cumedist_by_year = Window(
    expression=CumeDist(),
    partition_by=F(&amp;quot;commit_year&amp;quot;),
    order_by=F(&amp;quot;commits_count&amp;quot;).desc()
)

commiters_with_rank = Committer.objects.filter(
        commit_year__gte=2010, commits_count__gte=10
    ).annotate(
        cumedist_by_year=cumedist_by_year
    ).order_by(
        &amp;quot;-commit_year&amp;quot;, &amp;quot;the_rank&amp;quot;
    ).values(
        &amp;quot;author&amp;quot;, &amp;quot;commit_year&amp;quot;, &amp;quot;commits_count&amp;quot;, &amp;quot;cumedist_by_year&amp;quot;
    )
as_table(commiters_with_rank)
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Until now, we have partitioned on &lt;cite&gt;commit_year&lt;/cite&gt;. We can partition on other fields too. We will partition on &lt;cite&gt;author&lt;/cite&gt; to find out how their contributions have changed over the years using the &lt;cite&gt;Lag&lt;/cite&gt; window expression.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;from django.db.models.functions import Lag
from django.db.models import Value
commits_in_previous_year = Window(
    expression=Lag(&amp;quot;commits_count&amp;quot;, default=Value(0)),
    partition_by=F(&amp;quot;author&amp;quot;),
    order_by=F(&amp;quot;commit_year&amp;quot;).asc(),
)

commiters_with_pervious_year_commit = Committer.objects.filter(
        commit_year__gte=2010, commits_count__gte=10
    ).annotate(
        commits_in_previous_year=commits_in_previous_year
    ).order_by(
        &amp;quot;author&amp;quot;, &amp;quot;-commit_year&amp;quot;
    ).values(
        &amp;quot;author&amp;quot;, &amp;quot;commit_year&amp;quot;, &amp;quot;commits_count&amp;quot;, &amp;quot;commits_in_previous_year&amp;quot;
    )
as_table(commiters_with_pervious_year_commit)
&lt;/pre&gt;&lt;/div&gt;
&lt;div&gt;
&lt;style scoped&gt;
    .dataframe tbody tr th:only-of-type {
        vertical-align: middle;
    }

    .dataframe tbody tr th {
        vertical-align: top;
    }

    .dataframe thead th {
        text-align: right;
    }
&lt;/style&gt;
&lt;table border="1" class="dataframe"&gt;
  &lt;thead&gt;
    &lt;tr style="text-align: right;"&gt;
      &lt;th&gt;&lt;/th&gt;
      &lt;th&gt;author&lt;/th&gt;
      &lt;th&gt;commit_year&lt;/th&gt;
      &lt;th&gt;commits_count&lt;/th&gt;
      &lt;th&gt;commits_in_previous_year&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;th&gt;0&lt;/th&gt;
      &lt;td&gt;Adam Chainz&lt;/td&gt;
      &lt;td&gt;2016&lt;/td&gt;
      &lt;td&gt;42&lt;/td&gt;
      &lt;td&gt;12&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;th&gt;1&lt;/th&gt;
      &lt;td&gt;Adam Chainz&lt;/td&gt;
      &lt;td&gt;2015&lt;/td&gt;
      &lt;td&gt;12&lt;/td&gt;
      &lt;td&gt;0&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;th&gt;2&lt;/th&gt;
      &lt;td&gt;Adam Johnson&lt;/td&gt;
      &lt;td&gt;2017&lt;/td&gt;
      &lt;td&gt;13&lt;/td&gt;
      &lt;td&gt;0&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;th&gt;3&lt;/th&gt;
      &lt;td&gt;Adrian Holovaty&lt;/td&gt;
      &lt;td&gt;2012&lt;/td&gt;
      &lt;td&gt;40&lt;/td&gt;
      &lt;td&gt;98&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;th&gt;4&lt;/th&gt;
      &lt;td&gt;Adrian Holovaty&lt;/td&gt;
      &lt;td&gt;2011&lt;/td&gt;
      &lt;td&gt;98&lt;/td&gt;
      &lt;td&gt;72&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;th&gt;5&lt;/th&gt;
      &lt;td&gt;Adrian Holovaty&lt;/td&gt;
      &lt;td&gt;2010&lt;/td&gt;
      &lt;td&gt;72&lt;/td&gt;
      &lt;td&gt;0&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;th&gt;6&lt;/th&gt;
      &lt;td&gt;Akshesh&lt;/td&gt;
      &lt;td&gt;2016&lt;/td&gt;
      &lt;td&gt;31&lt;/td&gt;
      &lt;td&gt;0&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;th&gt;7&lt;/th&gt;
      &lt;td&gt;Alasdair Nicol&lt;/td&gt;
      &lt;td&gt;2016&lt;/td&gt;
      &lt;td&gt;13&lt;/td&gt;
      &lt;td&gt;19&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;th&gt;8&lt;/th&gt;
      &lt;td&gt;Alasdair Nicol&lt;/td&gt;
      &lt;td&gt;2015&lt;/td&gt;
      &lt;td&gt;19&lt;/td&gt;
      &lt;td&gt;17&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;th&gt;9&lt;/th&gt;
      &lt;td&gt;Alasdair Nicol&lt;/td&gt;
      &lt;td&gt;2013&lt;/td&gt;
      &lt;td&gt;17&lt;/td&gt;
      &lt;td&gt;0&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;th&gt;...&lt;/th&gt;
      &lt;td&gt;...&lt;/td&gt;
      &lt;td&gt;...&lt;/td&gt;
      &lt;td&gt;...&lt;/td&gt;
      &lt;td&gt;...&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;th&gt;171&lt;/th&gt;
      &lt;td&gt;Timo Graham&lt;/td&gt;
      &lt;td&gt;2012&lt;/td&gt;
      &lt;td&gt;13&lt;/td&gt;
      &lt;td&gt;70&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;th&gt;172&lt;/th&gt;
      &lt;td&gt;Timo Graham&lt;/td&gt;
      &lt;td&gt;2011&lt;/td&gt;
      &lt;td&gt;70&lt;/td&gt;
      &lt;td&gt;60&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;th&gt;173&lt;/th&gt;
      &lt;td&gt;Timo Graham&lt;/td&gt;
      &lt;td&gt;2010&lt;/td&gt;
      &lt;td&gt;60&lt;/td&gt;
      &lt;td&gt;0&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;th&gt;174&lt;/th&gt;
      &lt;td&gt;Tom&lt;/td&gt;
      &lt;td&gt;2017&lt;/td&gt;
      &lt;td&gt;13&lt;/td&gt;
      &lt;td&gt;0&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;th&gt;175&lt;/th&gt;
      &lt;td&gt;Unai Zalakain&lt;/td&gt;
      &lt;td&gt;2013&lt;/td&gt;
      &lt;td&gt;17&lt;/td&gt;
      &lt;td&gt;0&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;th&gt;176&lt;/th&gt;
      &lt;td&gt;Vajrasky Kok&lt;/td&gt;
      &lt;td&gt;2013&lt;/td&gt;
      &lt;td&gt;14&lt;/td&gt;
      &lt;td&gt;0&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;th&gt;177&lt;/th&gt;
      &lt;td&gt;areski&lt;/td&gt;
      &lt;td&gt;2014&lt;/td&gt;
      &lt;td&gt;15&lt;/td&gt;
      &lt;td&gt;0&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;th&gt;178&lt;/th&gt;
      &lt;td&gt;eltronix&lt;/td&gt;
      &lt;td&gt;2016&lt;/td&gt;
      &lt;td&gt;10&lt;/td&gt;
      &lt;td&gt;0&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;th&gt;179&lt;/th&gt;
      &lt;td&gt;wrwrwr&lt;/td&gt;
      &lt;td&gt;2014&lt;/td&gt;
      &lt;td&gt;21&lt;/td&gt;
      &lt;td&gt;0&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;th&gt;180&lt;/th&gt;
      &lt;td&gt;Łukasz Langa&lt;/td&gt;
      &lt;td&gt;2013&lt;/td&gt;
      &lt;td&gt;15&lt;/td&gt;
      &lt;td&gt;0&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;181 rows × 4 columns&lt;/p&gt;
&lt;/div&gt;&lt;p&gt;I hope this tutorial has been helpful in understanding the window expressions. While still not as felxible as SqlAlchemy, Django ORM has become extremely powerful with recent Django releases. Stay tuned for more advanced ORM tutorials.&lt;/p&gt;
&lt;/div&gt;
</description><guid>http://agiliq.com/blog/2017/12/django-20-window-expressions-tutorial/</guid></item><item><title>Configure Django to log exceptions in production</title><link>http://agiliq.com/blog/2017/12/configure-django-log-exceptions-production/</link><description>&lt;p&gt;Django default logging behaviour for unhandled exceptions is:&lt;/p&gt;
&lt;h4&gt;With DEBUG=True (Development)&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;Log the exception on console/stream.&lt;/li&gt;
&lt;li&gt;Show the exception on page, i.e in http response.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;With DEBUG=False (Production)&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;Do not log the exception on console/stream.&lt;/li&gt;
&lt;li&gt;Do not show the exception in response.&lt;/li&gt;
&lt;li&gt;Send an email to admin if email settings are configured correctly.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Usually not logging the exception on console isn't a problem since an exception email is sent to you which can help you know the source of exception. But this assumes that email settings are configured correctly else you will not receive the exception email.&lt;/p&gt;
&lt;p&gt;You might not have email settings configured correctly and don't want to get into that right away. You might instead want to log the exception on console even with DEBUG=False. This post would help you in such scenario.&lt;/p&gt;
&lt;h4&gt;Default logging configuration&lt;/h4&gt;
&lt;p&gt;Django's default logging setting is:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;DEFAULT_LOGGING&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;version&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;disable_existing_loggers&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;False&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;filters&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;require_debug_false&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;django&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;utils&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RequireDebugFalse&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;require_debug_true&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;django&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;utils&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RequireDebugTrue&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;formatters&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;django&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;server&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;django&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;utils&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ServerFormatter&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;format&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;server_time&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;handlers&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;console&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;level&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;INFO&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;filters&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;require_debug_true&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
            &lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;class&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;logging&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;StreamHandler&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;django&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;server&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;level&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;INFO&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;class&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;logging&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;StreamHandler&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;formatter&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;django&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;server&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;mail_admins&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;level&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;ERROR&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;filters&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;require_debug_false&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
            &lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;class&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;django&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;utils&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AdminEmailHandler&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;loggers&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;django&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;handlers&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;console&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;mail_admins&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
            &lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;level&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;INFO&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;django&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;server&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;handlers&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;django&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;server&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
            &lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;level&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;INFO&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;propagate&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;False&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Without any explicit &lt;code&gt;settings.LOGGING&lt;/code&gt; configured in settings.py, this is the default logging configuration Django works with. You can ignore &lt;code&gt;django.server&lt;/code&gt; part.&lt;/p&gt;
&lt;p&gt;Any unhandled Django exception is handled in function &lt;code&gt;handle_uncaught_exception&lt;/code&gt;. The relevant code is on &lt;a href="https://github.com/django/django/blob/1.11.7/django/core/handlers/exception.py#L124" target="_blank"&gt;Github&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Error is logged using &lt;code&gt;logger.error&lt;/code&gt; in this function. This logger is an instance of &lt;code&gt;django.request&lt;/code&gt;. Since logger &lt;code&gt;django&lt;/code&gt; is a parent of &lt;code&gt;django.request&lt;/code&gt;, so log records are propogated to logger &lt;code&gt;django&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;As you can see from &lt;code&gt;DEFAULT_LOGGING&lt;/code&gt;, logger &lt;code&gt;django&lt;/code&gt; has two handlers.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;console&lt;/li&gt;
&lt;li&gt;mail_admins&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;As you can see from &lt;code&gt;DEFAULT_LOGGING&lt;/code&gt;, handler &lt;code&gt;console&lt;/code&gt; has a filter called &lt;code&gt;require_debug_true&lt;/code&gt; because of which this handler doesn't handle log records in production, i.e when DEBUG=False.&lt;/p&gt;
&lt;h4&gt;Logging to console in production&lt;/h4&gt;
&lt;p&gt;So you can create a new handler which directs &lt;code&gt;ERROR&lt;/code&gt; log records to Stream when DEBUG=False.&lt;/p&gt;
&lt;p&gt;This handler would look like&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;console_debug_false&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;level&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;ERROR&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;filters&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;require_debug_false&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;class&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;logging&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;StreamHandler&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;And you can ask logger &lt;code&gt;django&lt;/code&gt; to use this handler by adding this handler in &lt;code&gt;loggers['django']['handlers']&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Your final &lt;code&gt;settings.LOGGING&lt;/code&gt; would look like following:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;LOGGING&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;version&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;disable_existing_loggers&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;False&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;filters&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;require_debug_false&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;django&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;utils&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RequireDebugFalse&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;require_debug_true&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;django&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;utils&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RequireDebugTrue&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;formatters&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;django&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;server&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;django&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;utils&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ServerFormatter&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;format&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;server_time&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;handlers&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;console&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;level&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;INFO&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;filters&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;require_debug_true&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
            &lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;class&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;logging&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;StreamHandler&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;console_debug_false&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;level&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;ERROR&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;filters&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;require_debug_false&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
            &lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;class&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;logging&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;StreamHandler&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;django&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;server&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;level&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;INFO&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;class&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;logging&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;StreamHandler&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;formatter&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;django&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;server&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;mail_admins&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;level&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;ERROR&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;filters&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;require_debug_false&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
            &lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;class&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;django&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;utils&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AdminEmailHandler&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;loggers&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;django&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;handlers&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;console&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;console_debug_false&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;mail_admins&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
            &lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;level&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;INFO&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;django&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;server&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;handlers&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;django&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;server&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
            &lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;level&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;INFO&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;propagate&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;False&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;If you don't want emails to be sent to admins, in case email settings aren't configured correctly, then you should remove &lt;code&gt;mail_admins&lt;/code&gt; from &lt;code&gt;loggers['django']['handlers']&lt;/code&gt;.&lt;/p&gt;</description><guid>http://agiliq.com/blog/2017/12/configure-django-log-exceptions-production/</guid></item><item><title>Template fragment caching gotchas</title><link>http://agiliq.com/blog/2015/08/template-fragment-caching-gotchas/</link><description>&lt;h4&gt;Variables in cached template fragment&lt;/h4&gt;
&lt;p&gt;Assuming this is in template.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="k"&gt;cache&lt;/span&gt; &lt;span class="mi"&gt;300&lt;/span&gt; &lt;span class="nx"&gt;nums&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="nb"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="nx"&gt;nums&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="nx"&gt;endfor&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="nx"&gt;endcache&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;And assuming we send {'nums': range(100)} from context, then 0 to 99 will be sent in the response.&lt;/p&gt;
&lt;p&gt;Now suppose we change context to {'nums': range(1000)}, still for next 5 minutes i.e until the cache expires, 0 to 99 will be sent in the response. 0 to 999 will not be sent in the response.&lt;/p&gt;
&lt;p&gt;To fix this, we should use the variable too with the {% cache %} tag. So correct code would be&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="k"&gt;cache&lt;/span&gt; &lt;span class="mi"&gt;300&lt;/span&gt; &lt;span class="nx"&gt;nums_cache&lt;/span&gt; &lt;span class="nx"&gt;nums&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="nb"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="nx"&gt;nums&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="nx"&gt;endfor&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="nx"&gt;endcache&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;After this whenever context &lt;strong&gt;nums&lt;/strong&gt; changes, cache would be reevaluated.&lt;/p&gt;
&lt;h4&gt;Boolean variable in cached template fragment&lt;/h4&gt;
&lt;p&gt;Assuming template contains&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="k"&gt;cache&lt;/span&gt; &lt;span class="mi"&gt;300&lt;/span&gt; &lt;span class="nx"&gt;hello&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nx"&gt;hello&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Hello&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="nx"&gt;endif&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="nx"&gt;endcache&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;and assuming {'hello': True} is sent in context. Then &amp;lt;p&amp;gt;Hello&amp;lt;/p&amp;gt; will be sent in response.&lt;/p&gt;
&lt;p&gt;Now even when we send {'hello': False} in context, "&amp;lt;p&amp;gt;Hello&amp;lt;/p&amp;gt;" will still be sent in response because it's already cached.&lt;/p&gt;
&lt;p&gt;To fix this.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="k"&gt;cache&lt;/span&gt; &lt;span class="mi"&gt;300&lt;/span&gt; &lt;span class="nx"&gt;hello_cache&lt;/span&gt; &lt;span class="nx"&gt;hello&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nx"&gt;hello&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Hello&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="nx"&gt;endif&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="nx"&gt;endcache&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;h4&gt;request.user in cached template fragment&lt;/h4&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="k"&gt;cache&lt;/span&gt; &lt;span class="mi"&gt;300&lt;/span&gt; &lt;span class="nx"&gt;username_cache&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;{{&lt;/span&gt;&lt;span class="nx"&gt;request.user.username&lt;/span&gt;&lt;span class="p"&gt;}}&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="nx"&gt;endcache&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;When current user logs out and a new user logs in, still the username of old user is shown on the web page because template fragment is already cached and would not be reevaluated.&lt;/p&gt;
&lt;p&gt;Fix it like&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="k"&gt;cache&lt;/span&gt; &lt;span class="mi"&gt;300&lt;/span&gt; &lt;span class="nx"&gt;username_cache&lt;/span&gt; &lt;span class="nx"&gt;request.user.username&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;{{&lt;/span&gt;&lt;span class="nx"&gt;request.user.username&lt;/span&gt;&lt;span class="p"&gt;}}&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="nx"&gt;endcache&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;h4&gt;Gotcha while using base template&lt;/h4&gt;
&lt;p&gt;Assuming we are using template inheritance, and our base template i.e base.html looks like:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="cp"&gt;{%&lt;/span&gt; &lt;span class="k"&gt;load&lt;/span&gt; &lt;span class="nv"&gt;cache&lt;/span&gt; &lt;span class="cp"&gt;%}&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;html&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;head&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/head&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;body&amp;gt;&lt;/span&gt;
    &lt;span class="cp"&gt;{%&lt;/span&gt; &lt;span class="k"&gt;cache&lt;/span&gt; &lt;span class="m"&gt;300&lt;/span&gt; &lt;span class="nv"&gt;base_body&lt;/span&gt; &lt;span class="cp"&gt;%}&lt;/span&gt;
    &lt;span class="cp"&gt;{%&lt;/span&gt; &lt;span class="k"&gt;block&lt;/span&gt; &lt;span class="nv"&gt;body&lt;/span&gt; &lt;span class="cp"&gt;%}&lt;/span&gt;
    &lt;span class="cp"&gt;{%&lt;/span&gt; &lt;span class="k"&gt;endblock&lt;/span&gt; &lt;span class="cp"&gt;%}&lt;/span&gt;
    &lt;span class="cp"&gt;{%&lt;/span&gt; &lt;span class="k"&gt;endcache&lt;/span&gt; &lt;span class="cp"&gt;%}&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/body&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/html&amp;gt;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;And the child template, say test.html looks like&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="cp"&gt;{%&lt;/span&gt; &lt;span class="k"&gt;extends&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;base.html&amp;quot;&lt;/span&gt; &lt;span class="cp"&gt;%}&lt;/span&gt;
&lt;span class="cp"&gt;{%&lt;/span&gt; &lt;span class="k"&gt;load&lt;/span&gt; &lt;span class="nv"&gt;cache&lt;/span&gt; &lt;span class="cp"&gt;%}&lt;/span&gt;
&lt;span class="cp"&gt;{%&lt;/span&gt; &lt;span class="k"&gt;block&lt;/span&gt; &lt;span class="nv"&gt;body&lt;/span&gt; &lt;span class="cp"&gt;%}&lt;/span&gt;
  &lt;span class="cp"&gt;{%&lt;/span&gt; &lt;span class="k"&gt;cache&lt;/span&gt; &lt;span class="m"&gt;300&lt;/span&gt; &lt;span class="nv"&gt;username&lt;/span&gt; &lt;span class="nv"&gt;request.user.username&lt;/span&gt; &lt;span class="cp"&gt;%}&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;p&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;{{&lt;/span&gt;&lt;span class="nv"&gt;request.user.username&lt;/span&gt;&lt;span class="cp"&gt;}}&lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
  &lt;span class="cp"&gt;{%&lt;/span&gt; &lt;span class="k"&gt;endcache&lt;/span&gt; &lt;span class="cp"&gt;%}&lt;/span&gt;
&lt;span class="cp"&gt;{%&lt;/span&gt; &lt;span class="k"&gt;endblock&lt;/span&gt; &lt;span class="cp"&gt;%}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Assuming our view uses test.html. Suppose cache is empty now, and you are logged in as user1 and then you make the request to a url which uses test.html. So response will contain "&amp;lt;p&amp;gt;user1&amp;lt;/p&amp;gt;".&lt;/p&gt;
&lt;p&gt;Now if you logout and login as user2 and make the request, still the response will be "&amp;lt;p&amp;gt;user1&amp;lt;/p&amp;gt;" instead of "&amp;lt;p&amp;gt;user2&amp;lt;/p&amp;gt;".&lt;/p&gt;
&lt;p&gt;The reason for this is, as per &lt;a href="https://docs.djangoproject.com/en/1.7/topics/templates/" target="_blank"&gt;Django docs&lt;/a&gt;.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;The&lt;/span&gt; &lt;span class="n"&gt;extends&lt;/span&gt; &lt;span class="n"&gt;tag&lt;/span&gt; &lt;span class="n"&gt;is&lt;/span&gt; &lt;span class="n"&gt;the&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt; &lt;span class="n"&gt;here&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt; &lt;span class="n"&gt;It&lt;/span&gt; &lt;span class="n"&gt;tells&lt;/span&gt; &lt;span class="n"&gt;the&lt;/span&gt; &lt;span class="n"&gt;template&lt;/span&gt; &lt;span class="n"&gt;engine&lt;/span&gt; &lt;span class="n"&gt;that&lt;/span&gt; &lt;span class="n"&gt;this&lt;/span&gt; &lt;span class="n"&gt;template&lt;/span&gt; &lt;span class="err"&gt;“&lt;/span&gt;&lt;span class="n"&gt;extends&lt;/span&gt;&lt;span class="err"&gt;”&lt;/span&gt; &lt;span class="n"&gt;another&lt;/span&gt; &lt;span class="n"&gt;template&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt; &lt;span class="n"&gt;When&lt;/span&gt; &lt;span class="n"&gt;the&lt;/span&gt; &lt;span class="n"&gt;template&lt;/span&gt; &lt;span class="n"&gt;system&lt;/span&gt; &lt;span class="n"&gt;evaluates&lt;/span&gt; &lt;span class="n"&gt;this&lt;/span&gt; &lt;span class="n"&gt;template&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;first&lt;/span&gt; &lt;span class="n"&gt;it&lt;/span&gt; &lt;span class="n"&gt;locates&lt;/span&gt; &lt;span class="n"&gt;the&lt;/span&gt; &lt;span class="n"&gt;parent&lt;/span&gt; &lt;span class="err"&gt;–&lt;/span&gt; &lt;span class="n"&gt;in&lt;/span&gt; &lt;span class="n"&gt;this&lt;/span&gt; &lt;span class="k"&gt;case&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="err"&gt;“&lt;/span&gt;&lt;span class="n"&gt;base&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;html&lt;/span&gt;&lt;span class="err"&gt;”&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;But in our case, the parent template itself has some cached content, which Django will use. Django will not even bother to look at the &lt;code&gt;{% block body %}&lt;/code&gt; of child template if it finds cached content &lt;code&gt;base_body&lt;/code&gt; for the parent template.&lt;/p&gt;
&lt;p&gt;The fix for this is to differentiate the cache of different users even in the base template. So we could change the base template to look like.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="cp"&gt;{%&lt;/span&gt; &lt;span class="k"&gt;load&lt;/span&gt; &lt;span class="nv"&gt;cache&lt;/span&gt; &lt;span class="cp"&gt;%}&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;html&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;head&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/head&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;body&amp;gt;&lt;/span&gt;
    &lt;span class="cp"&gt;{%&lt;/span&gt; &lt;span class="k"&gt;cache&lt;/span&gt; &lt;span class="m"&gt;300&lt;/span&gt; &lt;span class="nv"&gt;base_body&lt;/span&gt; &lt;span class="nv"&gt;request.user.username&lt;/span&gt; &lt;span class="cp"&gt;%}&lt;/span&gt;
    &lt;span class="cp"&gt;{%&lt;/span&gt; &lt;span class="k"&gt;block&lt;/span&gt; &lt;span class="nv"&gt;body&lt;/span&gt; &lt;span class="cp"&gt;%}&lt;/span&gt;
    &lt;span class="cp"&gt;{%&lt;/span&gt; &lt;span class="k"&gt;endblock&lt;/span&gt; &lt;span class="cp"&gt;%}&lt;/span&gt;
    &lt;span class="cp"&gt;{%&lt;/span&gt; &lt;span class="k"&gt;endcache&lt;/span&gt; &lt;span class="cp"&gt;%}&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/body&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/html&amp;gt;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;After this, if user1 is logged in the "&amp;lt;p&amp;gt;user1&amp;lt;/p&amp;gt;" is sent in response. If user2 is logged in then "&amp;lt;p&amp;gt;user2&amp;lt;/p&amp;gt;" is sent in response.&lt;/p&gt;
&lt;h4&gt;Gotcha with {% include %} tag.&lt;/h4&gt;
&lt;p&gt;It is similar to the gotcha of template inheritance discussed in last section.&lt;/p&gt;
&lt;p&gt;Assuming the view uses test.html, which contains.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="n"&gt;cache&lt;/span&gt; &lt;span class="mi"&gt;60&lt;/span&gt; &lt;span class="n"&gt;body_cache&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="n"&gt;include&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;body.html&amp;quot;&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="n"&gt;endcache&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;And body.html contains&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="nt"&gt;&amp;lt;p&amp;gt;&lt;/span&gt;Hello {{request.user.username}}&lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;So when first user, say user1 logs in, cache is evaluated and &amp;lt;p&amp;gt;Hello user1&amp;lt;/p&amp;gt; is sent in response. When user2 logs in, still &amp;lt;p&amp;gt;Hello user2&amp;lt;/p&amp;gt; will be sent in response.&lt;/p&gt;
&lt;p&gt;To fix this, test.html should also use all the variables on which &lt;strong&gt;included&lt;/strong&gt; template depends.&lt;/p&gt;
&lt;p&gt;So code in test.html should change to&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="n"&gt;cache&lt;/span&gt; &lt;span class="mi"&gt;60&lt;/span&gt; &lt;span class="n"&gt;body_cache&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="n"&gt;include&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;body.html&amp;quot;&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="n"&gt;endcache&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;If &lt;strong&gt;included&lt;/strong&gt; template, i.e body.html depended on any other variable, that other variable too should be used with {% cache %} tag.&lt;/p&gt;</description><guid>http://agiliq.com/blog/2015/08/template-fragment-caching-gotchas/</guid></item><item><title>Profiling Django Middlewares</title><link>http://agiliq.com/blog/2015/07/profiling-django-middlewares/</link><description>&lt;p&gt;I assume you have a basic understanding of Profiling, what it means and why we use it.&lt;/p&gt;
&lt;h3&gt;Why this post&lt;/h3&gt;
&lt;p&gt;Recently I had to profile a Django application which wasn't performing as fast as it should. This application had several custom middlewares too. So it was possible that custom middlewares were the cause of slow performance.&lt;/p&gt;
&lt;p&gt;There are some existing Django libraries to profile Django code. eg: Django Debug Toolbar, django-silk , django_cprofile etc. Most of them can profile view code well but they can't profile other middlewares.&lt;/p&gt;
&lt;p&gt;I wanted a way to profile middlewares too.&lt;/p&gt;
&lt;h3&gt;Problem with Django Debug Toolbar&lt;/h3&gt;
&lt;p&gt;I assume you understand middlewares and how the order in which middlewares are defined matter. If you want to get more idea about middlewares, &lt;a href="http://agiliq.com/blog/2015/07/understanding-django-middlewares/" target="_blank"&gt;this post&lt;/a&gt; might help.&lt;/p&gt;
&lt;p&gt;Django debug toolbar is probably designed for profiling the views. It uses process_view() and returns an HttpResponse instace from process_view(). process_request() of all middlewares run before any middleware's process_view(). So using Django debug toolbar, it's not possible to profile what's going on inside process_request() of different middlewares.&lt;/p&gt;
&lt;p&gt;And since process_view() of debug toolbar returns HttpResponse, process_view() of other middlewares is bypassed and so we can't profile process_view() of other middlewares.&lt;/p&gt;
&lt;p&gt;So I guess it is not possible to profile middleware code using Django debug toolbar.&lt;/p&gt;
&lt;h3&gt;django-silk&lt;/h3&gt;
&lt;p&gt;Django silk seemed better at profiling middlewares too. It looks promising and I will play more with it.&lt;/p&gt;
&lt;p&gt;But Django silk also tracks queries executed, inserts the results in db etc. In case you only wanted to know the time it takes to execute different functions and wanted to find out the most time consuming functions, you might not want the overhead of django silk.&lt;/p&gt;
&lt;h3&gt;Writing our own middleware&lt;/h3&gt;
&lt;p&gt;We want to write a simple middleware that just tells the most expensive functions/methods and time it took to execute those functions. We don't want to capture sql queries or anything fancy.&lt;/p&gt;
&lt;p&gt;We will use standard Python provided &lt;strong&gt;cProfile&lt;/strong&gt; to achieve our goal. &lt;a href="https://docs.python.org/2/library/profile.html" target="_blank"&gt;This official doc&lt;/a&gt; can help you get familiar with cProfile in 10 mins.&lt;/p&gt;
&lt;p&gt;Add the following in any app's middleware.py. Supposing you have an app called books and you add this in books/middleware.py&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="kr"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;cProfile&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;pstats&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;StringIO&lt;/span&gt;

&lt;span class="kr"&gt;class&lt;/span&gt; &lt;span class="nx"&gt;ProfilerMiddleware&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;object&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
    &lt;span class="nx"&gt;def&lt;/span&gt; &lt;span class="nx"&gt;process_request&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
        &lt;span class="nx"&gt;pr&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;cProfile&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Profile&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="nx"&gt;pr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;enable&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;_pr&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;pr&lt;/span&gt;

    &lt;span class="nx"&gt;def&lt;/span&gt; &lt;span class="nx"&gt;process_response&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
        &lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;_pr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;disable&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="nx"&gt;s&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;StringIO&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;StringIO&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="nx"&gt;sortby&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;cumulative&amp;#39;&lt;/span&gt;
        &lt;span class="err"&gt;#&lt;/span&gt; &lt;span class="nx"&gt;Sort&lt;/span&gt; &lt;span class="nx"&gt;the&lt;/span&gt; &lt;span class="nx"&gt;output&lt;/span&gt; &lt;span class="nx"&gt;by&lt;/span&gt; &lt;span class="nx"&gt;cumulative&lt;/span&gt; &lt;span class="nx"&gt;time&lt;/span&gt; &lt;span class="nx"&gt;it&lt;/span&gt; &lt;span class="nx"&gt;took&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="nx"&gt;fuctions&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nx"&gt;methods&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
        &lt;span class="nx"&gt;ps&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;pstats&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Stats&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;_pr&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;stream&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;sort_stats&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;sortby&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="err"&gt;#&lt;/span&gt; &lt;span class="nx"&gt;Print&lt;/span&gt; &lt;span class="nx"&gt;only&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt; &lt;span class="nx"&gt;most&lt;/span&gt; &lt;span class="nx"&gt;time&lt;/span&gt; &lt;span class="nx"&gt;consuming&lt;/span&gt; &lt;span class="nx"&gt;functions&lt;/span&gt;
        &lt;span class="nx"&gt;ps&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;print_stats&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="nx"&gt;print&lt;/span&gt; &lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getvalue&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;And add books.middleware.ProfileMiddleware at top of your MIDDLEWARE_CLASSES.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;MIDDLEWARE_CLASSES&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;books&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;middleware&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ProfilerMiddleware&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="err"&gt;#&lt;/span&gt; &lt;span class="n"&gt;Assuming&lt;/span&gt; &lt;span class="n"&gt;you&lt;/span&gt; &lt;span class="n"&gt;have&lt;/span&gt; &lt;span class="n"&gt;some&lt;/span&gt; &lt;span class="n"&gt;custom&lt;/span&gt; &lt;span class="n"&gt;middlewares&lt;/span&gt; &lt;span class="n"&gt;here&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;even&lt;/span&gt; &lt;span class="n"&gt;they&lt;/span&gt; &lt;span class="n"&gt;will&lt;/span&gt; &lt;span class="n"&gt;be&lt;/span&gt; &lt;span class="n"&gt;profiled&lt;/span&gt;
    &lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;django&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;contrib&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sessions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;middleware&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SessionMiddleware&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;django&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;middleware&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;common&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CommonMiddleware&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;django&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;middleware&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;csrf&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CsrfViewMiddleware&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;django&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;contrib&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;auth&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;middleware&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AuthenticationMiddleware&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="err"&gt;#&lt;/span&gt; &lt;span class="n"&gt;This&lt;/span&gt; &lt;span class="n"&gt;middleware&lt;/span&gt; &lt;span class="n"&gt;will&lt;/span&gt; &lt;span class="n"&gt;be&lt;/span&gt; &lt;span class="n"&gt;profiled&lt;/span&gt; &lt;span class="n"&gt;too&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
    &lt;span class="err"&gt;#&lt;/span&gt; &lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;books&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;middleware&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SomeCustomMiddleware&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;django&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;contrib&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;messages&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;middleware&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;MessageMiddleware&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;django&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;middleware&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;clickjacking&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;XFrameOptionsMiddleware&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Try any url and you should see the profiler output on the runserver console.&lt;/p&gt;
&lt;h3&gt;Explanation&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;We put our middleware at top of MIDDLEWARE_CLASSES.&lt;/li&gt;
&lt;li&gt;So this middleware's process_request() will be executed before any other middleware's process_request(). Also it will be executed before any other middleware's any other function like process_view() etc.&lt;/li&gt;
&lt;li&gt;We enable profiling in process_request() so everything hereafter will be profiled. So process_request() and process_view() of any other middleware will be profiled.&lt;/li&gt;
&lt;li&gt;We disable profiling in process_response() of our middleware. process_response() of this middleware will run at last, i.e after process_response() of all other middlewares have run.&lt;/li&gt;
&lt;li&gt;This way process_response() of all other middlewares get profiled too.&lt;/li&gt;
&lt;/ul&gt;</description><guid>http://agiliq.com/blog/2015/07/profiling-django-middlewares/</guid></item><item><title>Understanding Django Middlewares</title><link>http://agiliq.com/blog/2015/07/understanding-django-middlewares/</link><description>&lt;p&gt;I assume you have read &lt;a href="https://docs.djangoproject.com/en/1.8/topics/http/middleware/" target="_blank"&gt;official Django docs on middleware&lt;/a&gt;. I will elaborate on things mentioned in the documentation but I assume you are familiar with basics of middleware.&lt;/p&gt;
&lt;p&gt;In this post we will discuss the following.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;What is a middleware&lt;/li&gt;
&lt;li&gt;When to use middleware&lt;/li&gt;
&lt;li&gt;Things to remember when writing middleware&lt;/li&gt;
&lt;li&gt;Writing some middlewares to understand how order of middleware matters&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;What is a middleware&lt;/h3&gt;
&lt;p&gt;Middlewares are hooks to modify Django &lt;strong&gt;request&lt;/strong&gt; or &lt;strong&gt;response&lt;/strong&gt; object. Putting the definition of middleware from Django &lt;a href="https://docs.djangoproject.com/en/1.8/topics/http/middleware/"&gt;docs&lt;/a&gt;.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;Middleware&lt;/span&gt; &lt;span class="n"&gt;is&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="n"&gt;framework&lt;/span&gt; &lt;span class="n"&gt;of&lt;/span&gt; &lt;span class="n"&gt;hooks&lt;/span&gt; &lt;span class="n"&gt;into&lt;/span&gt; &lt;span class="n"&gt;Django&lt;/span&gt;&lt;span class="err"&gt;’&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="n"&gt;processing&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt; &lt;span class="n"&gt;It&lt;/span&gt;&lt;span class="err"&gt;’&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="n"&gt;light&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;low&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;level&lt;/span&gt; &lt;span class="err"&gt;“&lt;/span&gt;&lt;span class="n"&gt;plugin&lt;/span&gt;&lt;span class="err"&gt;”&lt;/span&gt; &lt;span class="n"&gt;system&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;globally&lt;/span&gt; &lt;span class="n"&gt;altering&lt;/span&gt; &lt;span class="n"&gt;Django&lt;/span&gt;&lt;span class="err"&gt;’&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt; &lt;span class="n"&gt;input&lt;/span&gt; &lt;span class="n"&gt;or&lt;/span&gt; &lt;span class="n"&gt;output&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;h3&gt;When to use middleware&lt;/h3&gt;
&lt;p&gt;You can use middleware if you want to modify the &lt;strong&gt;request&lt;/strong&gt; i.e &lt;strong&gt;HttpRequest&lt;/strong&gt; object which is sent to the view. Or you might want to modify the &lt;strong&gt;HttpResponse&lt;/strong&gt; object returned from the view. Both these can be achieved by using a middleware.&lt;/p&gt;
&lt;p&gt;You might want to perform an operation before the view executes. In such case you would use a middleware.&lt;/p&gt;
&lt;p&gt;Django provides some default middleware. eg: AuthenticationMiddleware&lt;/p&gt;
&lt;p&gt;Very often you would have used &lt;strong&gt;request.user&lt;/strong&gt; inside the view. Django wants &lt;strong&gt;user&lt;/strong&gt; attribute to be set on &lt;code&gt;request&lt;/code&gt; before any view executes. Django takes a middleware approach to accomplish this. So Django provides an AuthenticationMiddleware which can modify the request object.&lt;/p&gt;
&lt;p&gt;And Django modifies the request object like:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="nl"&gt;https:&lt;/span&gt;&lt;span class="c1"&gt;//github.com/django/django/blob/master/django/contrib/auth/middleware.py#L22&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Similarly you might have an application which works with users of different timezones. You want to use the user's timezone while showing any page to the user. You want access to user's timezone in all the views. It makes sense to add it in session in such case. So you can add a middleware like this:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;class&lt;/span&gt; &lt;span class="n"&gt;TimezoneMiddleware&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;object&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;def&lt;/span&gt; &lt;span class="n"&gt;process_request&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
        &lt;span class="err"&gt;#&lt;/span&gt; &lt;span class="n"&gt;Assuming&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt; &lt;span class="n"&gt;has&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="n"&gt;OneToOneField&lt;/span&gt; &lt;span class="n"&gt;to&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="n"&gt;model&lt;/span&gt; &lt;span class="n"&gt;called&lt;/span&gt; &lt;span class="n"&gt;Profile&lt;/span&gt;
        &lt;span class="err"&gt;#&lt;/span&gt; &lt;span class="n"&gt;And&lt;/span&gt; &lt;span class="n"&gt;Profile&lt;/span&gt; &lt;span class="n"&gt;stores&lt;/span&gt; &lt;span class="n"&gt;the&lt;/span&gt; &lt;span class="n"&gt;timezone&lt;/span&gt; &lt;span class="n"&gt;of&lt;/span&gt; &lt;span class="n"&gt;the&lt;/span&gt; &lt;span class="n"&gt;User&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
        &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;session&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;timezone&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;profile&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;timezone&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;TimezoneMiddleware is dependent on &lt;code&gt;request.user&lt;/code&gt;. And &lt;code&gt;request.user&lt;/code&gt; is populated in &lt;strong&gt;AuthenticationMiddleware&lt;/strong&gt;. So TimezoneMiddleware written by us must come after Django provided AuthenticationMiddleware in the tuple settings.MIDDLEWARE_CLASSES.&lt;/p&gt;
&lt;p&gt;We will get more idea about order of middlewares in coming examples.&lt;/p&gt;
&lt;h3&gt;Things to remember when using middleware&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Order of middlewares is important.&lt;/li&gt;
&lt;li&gt;A middleware only need to extend from class &lt;strong&gt;object&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;A middleware is free to implement some of the methods and not implement other methods.&lt;/li&gt;
&lt;li&gt;A middleware may implement &lt;strong&gt;process_request&lt;/strong&gt; but may not implement &lt;strong&gt;process_response&lt;/strong&gt; and &lt;strong&gt;process_view&lt;/strong&gt;. Infact it is very common and lot of Django provided middlewares do it.&lt;/li&gt;
&lt;li&gt;A middleware may implement &lt;strong&gt;process_response&lt;/strong&gt; but not implement &lt;strong&gt;process_request&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;AuthenticationMiddleware only implements process_request and doesn't implement process_response. You can check it &lt;a href="https://github.com/django/django/blob/master/django/contrib/auth/middleware.py#L14" target="_blank"&gt;here&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;GZipMiddleware only implements process_response and doesn't implement process_request or process_view. You can see it &lt;a href="https://github.com/django/django/blob/master/django/middleware/gzip.py#L9" target="_blank"&gt;here&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;Writing some middlewares&lt;/h3&gt;
&lt;p&gt;Make sure you have a Django project with a url and a view, and that you are able to access that view. Since we will try several things with &lt;code&gt;request.user&lt;/code&gt;, make sure authentication is properly set for you and that &lt;code&gt;request.user&lt;/code&gt; prints the right thing in this view.&lt;/p&gt;
&lt;p&gt;Create a file middleware.py in any of your app.&lt;/p&gt;
&lt;p&gt;I have an app called &lt;code&gt;books&lt;/code&gt; and so I am writing this in books/middleware.py&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;class&lt;/span&gt; &lt;span class="n"&gt;BookMiddleware&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;object&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;def&lt;/span&gt; &lt;span class="n"&gt;process_request&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;print&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;Middleware executed&amp;quot;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Add this middleware in MIDDLEWARE_CLASSES&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;MIDDLEWARE_CLASSES&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;books&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;middleware&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;BookMiddleware&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;django&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;contrib&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sessions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;middleware&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SessionMiddleware&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;django&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;middleware&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;common&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CommonMiddleware&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;django&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;middleware&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;csrf&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CsrfViewMiddleware&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;django&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;contrib&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;auth&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;middleware&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AuthenticationMiddleware&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;django&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;contrib&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;messages&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;middleware&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;MessageMiddleware&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;django&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;middleware&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;clickjacking&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;XFrameOptionsMiddleware&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Make request to any url. This should get printed on &lt;code&gt;runserver&lt;/code&gt; console&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;Middleware&lt;/span&gt; &lt;span class="n"&gt;executed&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Modify BookMiddleware.process_request so it looks like&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;class&lt;/span&gt; &lt;span class="n"&gt;BookMiddleware&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;object&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;def&lt;/span&gt; &lt;span class="n"&gt;process_request&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;print&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;Middleware executed&amp;quot;&lt;/span&gt;
        &lt;span class="n"&gt;print&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Make request to a url again. This will raise an error.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;WSGIRequest&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt; &lt;span class="n"&gt;object&lt;/span&gt; &lt;span class="n"&gt;has&lt;/span&gt; &lt;span class="n"&gt;no&lt;/span&gt; &lt;span class="n"&gt;attribute&lt;/span&gt; &lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;This happened because attribute &lt;code&gt;user&lt;/code&gt; hasn't been set on &lt;code&gt;request&lt;/code&gt; yet.&lt;/p&gt;
&lt;p&gt;Now change the order of middlewares so BookMiddleware comes after AuthenticationMiddleware&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;MIDDLEWARE_CLASSES&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;django&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;contrib&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sessions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;middleware&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SessionMiddleware&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;django&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;middleware&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;common&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CommonMiddleware&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;django&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;middleware&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;csrf&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CsrfViewMiddleware&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;django&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;contrib&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;auth&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;middleware&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AuthenticationMiddleware&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;books&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;middleware&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;BookMiddleware&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;django&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;contrib&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;messages&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;middleware&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;MessageMiddleware&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;django&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;middleware&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;clickjacking&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;XFrameOptionsMiddleware&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Make request to any url. This should get printed on &lt;code&gt;runserver&lt;/code&gt; console&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="nx"&gt;Middleware&lt;/span&gt; &lt;span class="nx"&gt;executed&lt;/span&gt;
&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;username&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;This tells that &lt;code&gt;process_request&lt;/code&gt; is executed on the middlewares in the order in which they are listed in settings.MIDDLEWARE_CLASSES&lt;/p&gt;
&lt;p&gt;You can verify it further. Add another middleware in your middleware.py&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;class&lt;/span&gt; &lt;span class="n"&gt;AnotherMiddleware&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;object&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;def&lt;/span&gt; &lt;span class="n"&gt;process_request&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;print&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;Another middleware executed&amp;quot;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Add this middleware in MIDDLEWARE_CLASSES too.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;MIDDLEWARE_CLASSES&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;django&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;contrib&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sessions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;middleware&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SessionMiddleware&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;django&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;middleware&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;common&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CommonMiddleware&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;django&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;middleware&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;csrf&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CsrfViewMiddleware&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;django&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;contrib&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;auth&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;middleware&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AuthenticationMiddleware&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;books&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;middleware&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;BookMiddleware&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;books&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;middleware&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AnotherMiddleware&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;django&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;contrib&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;messages&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;middleware&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;MessageMiddleware&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;django&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;middleware&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;clickjacking&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;XFrameOptionsMiddleware&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Now output would be:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="nx"&gt;Middleware&lt;/span&gt; &lt;span class="nx"&gt;executed&lt;/span&gt;
&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;username&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nx"&gt;Another&lt;/span&gt; &lt;span class="nx"&gt;middleware&lt;/span&gt; &lt;span class="nx"&gt;executed&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;h4&gt;How returning HttpResponse from process_request changes things&lt;/h4&gt;
&lt;p&gt;Modify BookMiddleware so it looks like&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;class&lt;/span&gt; &lt;span class="n"&gt;BookMiddleware&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;object&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;def&lt;/span&gt; &lt;span class="n"&gt;process_request&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;print&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;Middleware executed&amp;quot;&lt;/span&gt;
        &lt;span class="n"&gt;print&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;HttpResponse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;some response&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Try any url now and your output would be:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="nx"&gt;Middleware&lt;/span&gt; &lt;span class="nx"&gt;executed&lt;/span&gt;
&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;username&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;You will notice two things:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Your view will no more be executed and no matter which url you try, you will see "some response".&lt;/li&gt;
&lt;li&gt;AnotherMiddleware.process_request will not be executed anymore.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;So if a Middleware's process_request() returns a HttpResponse object then process_request of any subsequent middlewares is bypassed. Also view execution is bypassed. You would rarely do this or require this in your projects.&lt;/p&gt;
&lt;p&gt;Comment "return HttpResponse("some response")" so process_request of both middlewares keep executing.&lt;/p&gt;
&lt;h4&gt;Working with process_response&lt;/h4&gt;
&lt;p&gt;Add method process_response to both the middlewares&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;class&lt;/span&gt; &lt;span class="n"&gt;AnotherMiddleware&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;object&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;def&lt;/span&gt; &lt;span class="n"&gt;process_request&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;print&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;Another middleware executed&amp;quot;&lt;/span&gt;

    &lt;span class="n"&gt;def&lt;/span&gt; &lt;span class="n"&gt;process_response&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;print&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;AnotherMiddleware process_response executed&amp;quot;&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;

&lt;span class="n"&gt;class&lt;/span&gt; &lt;span class="n"&gt;BookMiddleware&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;object&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;def&lt;/span&gt; &lt;span class="n"&gt;process_request&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;print&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;Middleware executed&amp;quot;&lt;/span&gt;
        &lt;span class="n"&gt;print&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;HttpResponse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;some response&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="err"&gt;#&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_start&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="n"&gt;def&lt;/span&gt; &lt;span class="n"&gt;process_response&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;print&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;BookMiddleware process_response executed&amp;quot;&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Try some url. Output would be&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="nx"&gt;Middleware&lt;/span&gt; &lt;span class="nx"&gt;executed&lt;/span&gt;
&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;username&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nx"&gt;Another&lt;/span&gt; &lt;span class="nx"&gt;middleware&lt;/span&gt; &lt;span class="nx"&gt;executed&lt;/span&gt;
&lt;span class="nx"&gt;AnotherMiddleware&lt;/span&gt; &lt;span class="nx"&gt;process_response&lt;/span&gt; &lt;span class="nx"&gt;executed&lt;/span&gt;
&lt;span class="nx"&gt;BookMiddleware&lt;/span&gt; &lt;span class="nx"&gt;process_response&lt;/span&gt; &lt;span class="nx"&gt;executed&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;AnotherMiddleware.process_response() is executed before BookMiddleware.process_response() while AnotherMiddleware.process_request() executes after BookMiddleware.process_request(). So process_response() follows the reverse of what happens with process_request. process_response() is executed for last middleware then second last middleware and so on till the first middleware.&lt;/p&gt;
&lt;h4&gt;process_view&lt;/h4&gt;
&lt;p&gt;Django applies middleware's process_view() in the order it’s defined in MIDDLEWARE_CLASSES, top-down. This is similar to the order followed for process_request().&lt;/p&gt;
&lt;p&gt;Also if any process_view() returns an HttpResponse object, then subsequent process_view() calls are bypassed and not executed.&lt;/p&gt;
&lt;p&gt;Check our &lt;a href="http://agiliq.com/blog/2015/07/profiling-django-middlewares/" target="_blank"&gt;next post&lt;/a&gt; to see a practical use of middleware.&lt;/p&gt;</description><guid>http://agiliq.com/blog/2015/07/understanding-django-middlewares/</guid></item><item><title>Tastypie with ForeignKey</title><link>http://agiliq.com/blog/2015/03/tastypie-with-foreignkey/</link><description>&lt;h2&gt;Tastypie with ForeignKeys&lt;/h2&gt;
&lt;p&gt;This is a followup post on &lt;a href="http://agiliq.com/blog/2015/03/getting-started-with-django-tastypie/" target="_blank"&gt;Getting started with tastypie&lt;/a&gt;. We will use the same project setup as used in the last post.&lt;/p&gt;
&lt;p&gt;This post will cover:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Fetch ForeignKey data in GET calls&lt;/li&gt;
&lt;li&gt;Create an object with ForeignKeys using POST calls&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Setup the application&lt;/h3&gt;
&lt;p&gt;Let's add the capability to categorise the expenses&lt;/p&gt;
&lt;p&gt;Add a model called ExpenseCategory&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;class&lt;/span&gt; &lt;span class="n"&gt;ExpenseCategory&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;models&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Model&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;models&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CharField&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;max_length&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;description&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;models&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;TextField&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Add a FK from Expense to ExpenseCategory&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;class&lt;/span&gt; &lt;span class="n"&gt;Expense&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;models&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Model&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;description&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;models&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CharField&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;max_length&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;amount&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;models&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;IntegerField&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;models&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ForeignKey&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;User&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;null&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;category&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;models&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ForeignKey&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ExpenseCategory&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;null&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;There already exists some Expense in db without an associated category, so make ExpenseCategory as nullable.&lt;/p&gt;
&lt;p&gt;Create and apply migrations&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;python&lt;/span&gt; &lt;span class="n"&gt;manage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;py&lt;/span&gt; &lt;span class="n"&gt;makemigrations&lt;/span&gt;
&lt;span class="n"&gt;python&lt;/span&gt; &lt;span class="n"&gt;manage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;py&lt;/span&gt; &lt;span class="n"&gt;migrate&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Let's create an expensecategory from shell and associate it with an expense of user Sheryl.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;u&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;User&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;objects&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;username&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;sheryl&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;ec&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ExpenseCategory&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;objects&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;Misc&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;description&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;Miscellaneous&lt;/span&gt; &lt;span class="n"&gt;expenses&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;e&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Expense&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;objects&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;description&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;Went&lt;/span&gt; &lt;span class="n"&gt;to&lt;/span&gt; &lt;span class="n"&gt;Stockholm&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;amount&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="mi"&gt;5000&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;u&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;category&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;ec&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;h3&gt;Get FK fields in response too.&lt;/h3&gt;
&lt;p&gt;We want category in Expense GET endpoint too.&lt;/p&gt;
&lt;p&gt;Our first approach would be adding 'category' to ExpenseCategory.Meta.fields. Try it&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;fields&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;description&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;amount&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;category&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Try the expense GET endpoint for Sheryl&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="nl"&gt;http:&lt;/span&gt;&lt;span class="c1"&gt;//localhost:8000/api/expense/?username=sheryl&amp;amp;api_key=1a23&amp;amp;format=json&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Still don't see category in response. We need something more than this.&lt;/p&gt;
&lt;h4&gt;Adding fields.ForeignKey on ExpenseResource&lt;/h4&gt;
&lt;p&gt;There is no easy way to achieve this without adding a resource for ExpenseCategory.&lt;/p&gt;
&lt;p&gt;We need to create an ExpenseCategoryResource similar to ExpenseResource&lt;/p&gt;
&lt;p&gt;Add ExpenseCategoryResource to expenses/api.py&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;class&lt;/span&gt; &lt;span class="n"&gt;ExpenseCategoryResource&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ModelResource&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;class&lt;/span&gt; &lt;span class="n"&gt;Meta&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;queryset&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ExpenseCategory&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;objects&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;all&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="n"&gt;resource_name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;expensecategory&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Add proper url pattern for ExpenseCategoryResource in expenses/api.py&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;expense_category_resource&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ExpenseCategoryResource&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="n"&gt;urlpatterns&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;patterns&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;^&lt;/span&gt;&lt;span class="n"&gt;admin&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;include&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;admin&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;site&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;urls&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt;
    &lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;^&lt;/span&gt;&lt;span class="n"&gt;api&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;include&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;expense_resource&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;urls&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt;
    &lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;^&lt;/span&gt;&lt;span class="n"&gt;api&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;include&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;expense_category_resource&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;urls&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Verify things are properly setup for ExpenseCategoryResource by accessing&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="nl"&gt;http:&lt;/span&gt;&lt;span class="c1"&gt;//localhost:8000/api/expensecategory/?format=json&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Add the following to ExpenseCategory&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;category&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;fields&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ForeignKey&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ExpenseCategoryResource&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;attribute&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;category&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;null&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Try&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="nl"&gt;http:&lt;/span&gt;&lt;span class="c1"&gt;//localhost:8000/api/expense/?username=sheryl&amp;amp;api_key=1a23&amp;amp;format=json&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;After this you'll be able to see category in response&lt;/p&gt;
&lt;p&gt;This will return resource_uri of ExpenseCategory by default&lt;/p&gt;
&lt;h4&gt;Using full=True&lt;/h4&gt;
&lt;p&gt;Probably you want to see the name and description of category in the response &lt;/p&gt;
&lt;p&gt;Make the following modification&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;category&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;fields&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ForeignKey&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ExpenseCategoryResource&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;attribute&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;category&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;null&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;full&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Try the GET endpoint again&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="nl"&gt;http:&lt;/span&gt;&lt;span class="c1"&gt;//localhost:8000/api/expense/?username=sheryl&amp;amp;api_key=1a23&amp;amp;format=json&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;h3&gt;POST data with FK&lt;/h3&gt;
&lt;p&gt;There are several ways in which we can set category on expense while making POST call to create expenses.&lt;/p&gt;
&lt;h4&gt;Post with resource_uri of FK&lt;/h4&gt;
&lt;p&gt;We already have one ExpenseCategory in the db and the resource_uri for that expensecategory is '/api/expensecategory/1/'&lt;/p&gt;
&lt;p&gt;We want to create an expense and set the category as our earlier created expensecategory.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;post_data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;description&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;Bought&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="n"&gt;phone&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;testing&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;amount&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;2200&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;category&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;api&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;expensecategory&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="n"&gt;post_url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="c1"&gt;//localhost:8000/api/expense/?username=sheryl&amp;amp;api_key=1a23&amp;#39;&lt;/span&gt;
&lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;requests&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;post_url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dumps&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;post_data&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;headers&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;h4&gt;Posting entire data of FK&lt;/h4&gt;
&lt;p&gt;You find that the expense you want to create doesn't fit in any of the existing categories. You want to create a new expensecategory while making POST data to expense endpoint.&lt;/p&gt;
&lt;p&gt;So we want to creating ExpenseCategory and Expense together.&lt;/p&gt;
&lt;p&gt;You need to post the following data in such case.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;post_data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;description&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;Went&lt;/span&gt; &lt;span class="n"&gt;to&lt;/span&gt; &lt;span class="n"&gt;paris&lt;/span&gt; &lt;span class="n"&gt;to&lt;/span&gt; &lt;span class="n"&gt;attend&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="n"&gt;conference&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;amount&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;9000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;category&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;Travel&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;description&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;Expenses&lt;/span&gt; &lt;span class="n"&gt;incurred&lt;/span&gt; &lt;span class="n"&gt;on&lt;/span&gt; &lt;span class="n"&gt;travelling&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;}}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;No category exists for Travel yet.&lt;/p&gt;
&lt;p&gt;Check the count of ExpenseCategory currently so that later you can verify that a new ExpenseCategory is created.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;ExpenseCategory&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;objects&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;count&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="mi"&gt;1&lt;/span&gt;   &lt;span class="err"&gt;#&lt;/span&gt;&lt;span class="n"&gt;output&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;POST the data to expense endpoint&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;requests&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;post_url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dumps&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;post_data&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;headers&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;print&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;status_code&lt;/span&gt;    &lt;span class="err"&gt;#&lt;/span&gt;&lt;span class="mi"&gt;401&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;h5&gt;Why you got 401&lt;/h5&gt;
&lt;p&gt;Even though you tried creating an Expense on expense post endpoint, tastypie internally tries creating an expensecategory because of structure of post_data. But tastypie finds that ExpenseCategoryResource doesn't have &lt;strong&gt;authorization&lt;/strong&gt; to allow POST yet.&lt;/p&gt;
&lt;p&gt;So we need to add proper authorization to ExpenseCategory before this post call can succeed.&lt;/p&gt;
&lt;p&gt;Add the following to ExpenseCategoryResource.Meta&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;authorization&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Authorization&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;h4&gt;POSTing again&lt;/h4&gt;
&lt;p&gt;Try the post call again.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;requests&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;post_url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dumps&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;post_data&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;headers&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;This would have worked well and a new ExpenseCategory should have been created.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;ExpenseCategory&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;objects&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;count&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="mi"&gt;2&lt;/span&gt;    &lt;span class="err"&gt;#&lt;/span&gt;&lt;span class="n"&gt;output&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Also the new expense would have got associated with the newly created ExpenseCategory.&lt;/p&gt;
&lt;h4&gt;POST with id of FK&lt;/h4&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;post_data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;description&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;Bought&lt;/span&gt; &lt;span class="n"&gt;second&lt;/span&gt; &lt;span class="n"&gt;Disworld&lt;/span&gt; &lt;span class="n"&gt;book&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;amount&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;399&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;category&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;pk&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;}}&lt;/span&gt;

&lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;requests&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;post_url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dumps&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;post_data&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;headers&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;h3&gt;Optimizing FK field calculation&lt;/h3&gt;
&lt;p&gt;If you have full=True on FK resource then a database call will happen for each FK of each row.&lt;/p&gt;
&lt;p&gt;eg: &lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;category&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;fields&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ForeignKey&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ExpenseCategoryResource&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;attribute&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;category&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;null&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;full&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Here if you are hitting expense GET list, and suppose you are getting 20 expenses.&lt;/p&gt;
&lt;p&gt;For each expense, it's category needs to be fetched from db and the categorie's full representation needs to be calculated. So 20 extra db calls will happen.&lt;/p&gt;
&lt;p&gt;Fixing it. Set ExpenseResource.Meta.queryset to&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;queryset&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Expense&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;objects&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;all&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="n"&gt;select_related&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;category&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Now the extra 20 calls will not be made.&lt;/p&gt;
&lt;h3&gt;Getting category_id without ExpenseCategoryResource&lt;/h3&gt;
&lt;p&gt;Suppose you are only interested in getting category_id in GET calls and don't care about name and description of category.&lt;/p&gt;
&lt;p&gt;Comment out everything about ExpenseCategoryResource and relation to ExpenseCategoryResource from ExpenseResource&lt;/p&gt;
&lt;p&gt;And add the following line to ExpenseResource&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;category_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;fields&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;IntegerField&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;attribute&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;category_id&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;null&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;After this you will find &lt;strong&gt;category_id&lt;/strong&gt; in GET responses.&lt;/p&gt;
&lt;h4&gt;Handling POST&lt;/h4&gt;
&lt;p&gt;Similarly you want to be able to POST without worrying about ExpenseCategoryResource.&lt;/p&gt;
&lt;p&gt;You want to send the category_id in post data and using that id, expense should be associated with correct expensecategory.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;description&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;Bought&lt;/span&gt; &lt;span class="n"&gt;iphone&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;amount&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;6500&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;category_id&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;requests&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;http://localhost:8000/api/expense/?username=sheryl&amp;amp;api_key=1a23&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dumps&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;headers&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;h3&gt;Gotchas&lt;/h3&gt;
&lt;p&gt;We have a FK to ExpenseCategory from Expense and it is nullable. Similarly, we have an en FK from ExpenseResource to ExpenseCategoryResource which is nullable.&lt;/p&gt;
&lt;p&gt;Mark ExpenseCategoryResource non-null for now, i.e remove null=True from it.&lt;/p&gt;
&lt;p&gt;So it looks like&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;category&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;fields&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ForeignKey&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ExpenseCategoryResource&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;attribute&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;category&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;full&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Check the count of expenses in the db.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;In&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Expense&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;objects&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;count&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;Out&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;23&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Make a POST request to expense endpoint but don't pass any associated expensecategory.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;post_url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="c1"&gt;//localhost:8000/api/expense/?format=json&amp;amp;username=sheryl&amp;amp;api_key=1a23&amp;#39;&lt;/span&gt;
&lt;span class="n"&gt;post_data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;description&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;Bought&lt;/span&gt; &lt;span class="n"&gt;second&lt;/span&gt; &lt;span class="n"&gt;Disworld&lt;/span&gt; &lt;span class="n"&gt;book&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;amount&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;399&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;requests&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;post_url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dumps&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;post_data&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;headers&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;print&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;status_code&lt;/span&gt;
&lt;span class="mi"&gt;400&lt;/span&gt; &lt;span class="err"&gt;#&lt;/span&gt;&lt;span class="n"&gt;output&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Status code 400 means that request wasn't successul and so expense shouldn't have been created.&lt;/p&gt;
&lt;p&gt;But actually it was created even though tastypie returned us a 400 status code. You can check it using count.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;In&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;22&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Expense&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;objects&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;count&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;Out&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;22&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;24&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;This happened because at the model/db level ExpenseCategory allows null. So save() on Expense was successful. But at api/tastypie level, ExpenseCategoryResource is not nullable, so tastypie raised an error.&lt;/p&gt;</description><guid>http://agiliq.com/blog/2015/03/tastypie-with-foreignkey/</guid></item><item><title>Getting started with Django tastypie</title><link>http://agiliq.com/blog/2015/03/getting-started-with-django-tastypie/</link><description>&lt;p&gt;Django tastypie is a library to write RESTful apis in Django.&lt;/p&gt;
&lt;h3&gt;Why use REST&lt;/h3&gt;
&lt;p&gt;You have a database backed web application. This application tracks expenses. The application allows the capability to enter your expenses, view all your expenses, delete an expense etc. Essentially this application provides CRUD functionality. Django application has access to database credentials, but they are never seen by the users of the web application. Django application decides what to show to which user. Django application ensures that a particular user only sees the expenses entered by him and not somebody else's expenses.&lt;/p&gt;
&lt;p&gt;Now you want to provide a mobile application (Android or iOS) corresponding to this web application. Android application should allow the user to view his expenses, create an expense as well as any other CRUD functionality. But database credentials could not be put in Android code as it is not too hard to decompile an apk and get the db credentials. And we never want a user to get the db credentials else he will be in a position to see everyone's expenses and the entire database. So there has to be another way to allow mobile applications to get things from the database. This is where REST comes into picture.&lt;/p&gt;
&lt;p&gt;With REST, we have three components. A database, a Django application and a mobile application. Mobile application never accesses the database directly. It makes a REST api call to Django application. Mobile application also sends a api_key specific to the mobile user. Based on api_key, Django application determines what data to make visible to this particular api_key owner and sends the corresponding data in response.&lt;/p&gt;
&lt;h3&gt;Resource&lt;/h3&gt;
&lt;p&gt;REST stands for Representational State Transfer. It is a standard for transferring the state of a &lt;strong&gt;Resource&lt;/strong&gt;, from web to mobile.&lt;/p&gt;
&lt;h4&gt;What do I mean by &lt;strong&gt;state of a Resource&lt;/strong&gt;?&lt;/h4&gt;
&lt;p&gt;An expense could be a resource. A Person could be a resource. A blog post could be a resource. Basically any object or instance your program deals with could be a resource. And a resource's state is maintained in it's attributes. eg: You could have a model called Expense. The state of a expense instance is represented by its attributes.&lt;/p&gt;
&lt;p&gt;Any REST library should be able to create and return a representation of such resource, which simply stated means that REST library should be able to tell us the attributes and their values for different model instances. And tastypie is adept at doing this.&lt;/p&gt;
&lt;h3&gt;Setting up the application&lt;/h3&gt;
&lt;p&gt;I am using Django 1.7. Some things might be different for you if you are using different version of Django.&lt;/p&gt;
&lt;p&gt;As with all projects, I want to keep things in a virtual environment&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="err"&gt;$&lt;/span&gt; &lt;span class="n"&gt;mkvirtualenv&lt;/span&gt; &lt;span class="n"&gt;tastier&lt;/span&gt;
&lt;span class="err"&gt;$&lt;/span&gt; &lt;span class="n"&gt;workon&lt;/span&gt; &lt;span class="n"&gt;tastier&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Install Django&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="err"&gt;$&lt;/span&gt; &lt;span class="n"&gt;pip&lt;/span&gt; &lt;span class="n"&gt;install&lt;/span&gt; &lt;span class="n"&gt;Django&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Start a Django project&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tastier&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="err"&gt;$&lt;/span&gt; &lt;span class="n"&gt;django&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;admin&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;py&lt;/span&gt; &lt;span class="n"&gt;startproject&lt;/span&gt; &lt;span class="n"&gt;tastier&lt;/span&gt;

&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tastier&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="err"&gt;$&lt;/span&gt; &lt;span class="n"&gt;cd&lt;/span&gt; &lt;span class="n"&gt;tastier&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Start an app&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tastier&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="err"&gt;$&lt;/span&gt; &lt;span class="n"&gt;python&lt;/span&gt; &lt;span class="n"&gt;manage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;py&lt;/span&gt; &lt;span class="n"&gt;startapp&lt;/span&gt; &lt;span class="n"&gt;expenses&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Add this app to INSTALLED_APPS&lt;/p&gt;
&lt;p&gt;Run migration&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tastier&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;~&lt;/span&gt; &lt;span class="err"&gt;$&lt;/span&gt; &lt;span class="n"&gt;python&lt;/span&gt; &lt;span class="n"&gt;manage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;py&lt;/span&gt; &lt;span class="n"&gt;migrate&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Runserver&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tastier&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;~&lt;/span&gt; &lt;span class="err"&gt;$&lt;/span&gt; &lt;span class="n"&gt;python&lt;/span&gt; &lt;span class="n"&gt;manage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;py&lt;/span&gt; &lt;span class="n"&gt;runserver&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Check that your are able to access http://localhost:8000/admin/login/&lt;/p&gt;
&lt;p&gt;I have pushed the code for this project to &lt;a href="https://github.com/akshar-raaj/tastier" target="_blank"&gt;Github&lt;/a&gt;. You will be able to checkout at different commits in the project to see specific things.&lt;/p&gt;
&lt;h3&gt;Getting started&lt;/h3&gt;
&lt;p&gt;Install django-tastypie.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tastier&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="err"&gt;$&lt;/span&gt; &lt;span class="n"&gt;pip&lt;/span&gt; &lt;span class="n"&gt;install&lt;/span&gt; &lt;span class="n"&gt;django&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;tastypie&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Create a file called &lt;code&gt;expenses/api.py&lt;/code&gt; where you will keep all the tastypie related things.&lt;/p&gt;
&lt;p&gt;Suppose your program deals with a resource called Expense. Let's create a model Expense in expenses/models.py&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;class&lt;/span&gt; &lt;span class="n"&gt;Expense&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;models&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Model&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;description&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;models&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CharField&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;max_length&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;amount&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;models&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;IntegerField&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Run migrations&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;python&lt;/span&gt; &lt;span class="n"&gt;manage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;py&lt;/span&gt; &lt;span class="n"&gt;makemigrations&lt;/span&gt;
&lt;span class="n"&gt;python&lt;/span&gt; &lt;span class="n"&gt;manage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;py&lt;/span&gt; &lt;span class="n"&gt;migrate&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;We will later add a ForeignKey(User) to Expense to associate an expense with User. Don't worry about it for now, we will come back to it.&lt;/p&gt;
&lt;p&gt;Let's add few Expense instances in the database.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;Expense&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;objects&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;description&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;Ate&lt;/span&gt; &lt;span class="n"&gt;pizza&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;amount&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;Expense&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;objects&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;description&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;Went&lt;/span&gt; &lt;span class="n"&gt;to&lt;/span&gt; &lt;span class="n"&gt;Cinema&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;amount&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;h3&gt;Handling GET&lt;/h3&gt;
&lt;p&gt;You want the ability to get the representation of all expenses in your program at url "http://localhost:8000/api/expenses/".&lt;/p&gt;
&lt;p&gt;To deal with a resource, tastypie requires a class which overrides &lt;strong&gt;ModelResource&lt;/strong&gt;. Let's call our class &lt;strong&gt;ExpenseResource&lt;/strong&gt;. Add following to expenses/api.py&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;from&lt;/span&gt; &lt;span class="n"&gt;tastypie&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;resources&lt;/span&gt; &lt;span class="n"&gt;import&lt;/span&gt; &lt;span class="n"&gt;ModelResource&lt;/span&gt;

&lt;span class="n"&gt;from&lt;/span&gt; &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;models&lt;/span&gt; &lt;span class="n"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Expense&lt;/span&gt;

&lt;span class="n"&gt;class&lt;/span&gt; &lt;span class="n"&gt;ExpenseResource&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ModelResource&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;

    &lt;span class="n"&gt;class&lt;/span&gt; &lt;span class="n"&gt;Meta&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;queryset&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Expense&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;objects&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;all&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="n"&gt;resource_name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;expense&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;And you need to add the following to tastier/urls.py&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;from&lt;/span&gt; &lt;span class="n"&gt;expenses&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;api&lt;/span&gt; &lt;span class="n"&gt;import&lt;/span&gt; &lt;span class="n"&gt;ExpenseResource&lt;/span&gt;

&lt;span class="n"&gt;expense_resource&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ExpenseResource&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="n"&gt;urlpatterns&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;patterns&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;^&lt;/span&gt;&lt;span class="n"&gt;admin&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;include&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;admin&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;site&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;urls&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt;
    &lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;^&lt;/span&gt;&lt;span class="n"&gt;api&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;include&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;expense_resource&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;urls&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;h4&gt;GET all expenses&lt;/h4&gt;
&lt;p&gt;After this you should be able to hit&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="nl"&gt;http:&lt;/span&gt;&lt;span class="c1"&gt;//localhost:8000/api/expense/?format=json&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;and you will see all the expenses from database in the response.&lt;/p&gt;
&lt;p&gt;The response would be:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;meta&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;limit&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;next&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;offset&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;previous&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;total_count&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;objects&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[{&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;amount&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;description&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;Ate pizza&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;id&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;resource_uri&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;/api/expense/1/&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;amount&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;description&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;Went to Cinema&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;id&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;resource_uri&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;/api/expense/2/&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;}]}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;You will find the representation of &lt;code&gt;expense&lt;/code&gt; instances in &lt;strong&gt;objects&lt;/strong&gt; key of response.&lt;/p&gt;
&lt;h4&gt;Get a particular expense&lt;/h4&gt;
&lt;p&gt;You can get the representation of expense with id 1 at&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="nl"&gt;http:&lt;/span&gt;&lt;span class="c1"&gt;//localhost:8000/api/expense/1/?format=json&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;See how you are able to hit these two urls without adding them in urlpatterns. These urlpatterns are added by tastypie internally.&lt;/p&gt;
&lt;h4&gt;How these endpoints help and ties with mobile application example?&lt;/h4&gt;
&lt;p&gt;If the mobile app wants to show all the expenses it could use the url &lt;strong&gt;http://localhost:8000/api/expense/?format=json&lt;/strong&gt;, get the response, parse the response and show the result on app.&lt;/p&gt;
&lt;p&gt;Right now every user will see all the expenses. As we move forward we will see how only a user's expenses will be returned when a REST call is made from his/her mobile device.&lt;/p&gt;
&lt;h4&gt;Serialization&lt;/h4&gt;
&lt;p&gt;You must have realized that REST returns you serialized data. You might be wondering why use django-tastypie to achieve it, and not just use json.dumps. You can undoubtedly use json.dumps and not use django-tastypie to provide REST endpoints. But django-tastypie allows the ability to do many more things very easily as you will soon agree. Just hang on.&lt;/p&gt;
&lt;h4&gt;Changing Meta.resource_name&lt;/h4&gt;
&lt;p&gt;You can change ExpenseResource.Meta.resource_name from &lt;code&gt;expense&lt;/code&gt; to &lt;code&gt;expenditure&lt;/code&gt;.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;class&lt;/span&gt; &lt;span class="n"&gt;ExpenseResource&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ModelResource&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;

    &lt;span class="n"&gt;class&lt;/span&gt; &lt;span class="n"&gt;Meta&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;queryset&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Expense&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;objects&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;all&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="n"&gt;resource_name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;expenditure&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;And then the old urls will stop working. Your new GET urls in that case will be&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="nl"&gt;http:&lt;/span&gt;&lt;span class="c1"&gt;//localhost:8000/api/expenditure/?format=json&lt;/span&gt;
&lt;span class="nl"&gt;http:&lt;/span&gt;&lt;span class="c1"&gt;//localhost:8000/api/expenditure/1/?format=json&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Changing the resource_name changes the urls tastypie makes available to you.&lt;/p&gt;
&lt;p&gt;Now change the resource_name back to &lt;code&gt;expense&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;We have our first commit at this point. You can checkout to this commit to see the code till this point.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;git&lt;/span&gt; &lt;span class="n"&gt;checkout&lt;/span&gt; &lt;span class="n"&gt;b6a9c6&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;h4&gt;Meta.fields&lt;/h4&gt;
&lt;p&gt;Suppose you only want &lt;code&gt;description&lt;/code&gt; in expense representation, but don't want &lt;code&gt;amount&lt;/code&gt;. So you can add a fields attribute on ExpenseResource.Meta&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;class&lt;/span&gt; &lt;span class="n"&gt;Meta&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;queryset&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Expense&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;objects&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;all&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;resource_name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;expenditure&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;
    &lt;span class="n"&gt;fields&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;description&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Try&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="nl"&gt;http:&lt;/span&gt;&lt;span class="c1"&gt;//localhost:8000/api/expense/?format=json&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;So if you don't have &lt;strong&gt;fields&lt;/strong&gt; attribute on Meta, all the attributes of Model will be sent in response. If you have &lt;strong&gt;fields&lt;/strong&gt;, only attributes listed in fields will be sent in response.&lt;/p&gt;
&lt;p&gt;Let's add &lt;code&gt;amount&lt;/code&gt; also to &lt;code&gt;fields&lt;/code&gt;. Though this gives us the same behaviour as not having ExpenseResource.Meta.fields at all.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;class&lt;/span&gt; &lt;span class="n"&gt;Meta&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;queryset&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Expense&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;objects&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;all&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;resource_name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;expenditure&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;
    &lt;span class="n"&gt;fields&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;description&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;amount&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;We have our second commit at this point. You can checkout till this point by doing:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;git&lt;/span&gt; &lt;span class="n"&gt;checkout&lt;/span&gt; &lt;span class="mi"&gt;61194&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;h4&gt;Filtering&lt;/h4&gt;
&lt;p&gt;Suppose you only want the Expenses where amount exceeds 150.&lt;/p&gt;
&lt;p&gt;If we had to do this with Django model we would say:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;Expense&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;objects&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;amount__gt&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;150&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;&lt;strong&gt;amount__gt&lt;/strong&gt; is the key thing here. This could be appended to our url pattern to get the expenses where amount exceeds 150.&lt;/p&gt;
&lt;p&gt;This could be achieved at url&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="nl"&gt;http:&lt;/span&gt;&lt;span class="c1"&gt;//localhost:8000/api/expense/?amount__gt=150&amp;amp;format=json&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Try this. You will get an error because we haven't asked tastypie to allow filtering yet.&lt;/p&gt;
&lt;p&gt;Add &lt;strong&gt;filtering&lt;/strong&gt; attribute to ExpenseResource.Meta&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;class&lt;/span&gt; &lt;span class="n"&gt;Meta&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;queryset&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Expense&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;objects&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;all&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;resource_name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;expense&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;
    &lt;span class="n"&gt;fields&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;description&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;amount&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="n"&gt;filtering&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;amount&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;gt&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;You should be able to use&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="nl"&gt;http:&lt;/span&gt;&lt;span class="c1"&gt;//localhost:8000/api/expense/?amount__gt=150&amp;amp;format=json&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;This will only return the expenses where amount exceeds 150.&lt;/p&gt;
&lt;p&gt;Now we want to get all the expenses on Pizza. We could get pizza expenses in following way from shell.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;Expense&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;objects&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;description__icontains&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;pizza&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;So to achieve this thing in api, we need to make following changes to ExpenseResource.Meta.filtering:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;class&lt;/span&gt; &lt;span class="n"&gt;Meta&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;queryset&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Expense&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;objects&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;all&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;resource_name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;expense&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;
    &lt;span class="n"&gt;fields&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;description&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;amount&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="n"&gt;filtering&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;amount&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;gt&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
        &lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;description&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;icontains&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;And then following url would give us the pizza expenses&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="nl"&gt;http:&lt;/span&gt;&lt;span class="c1"&gt;//localhost:8000/api/expense/?description__icontains=pizza&amp;amp;format=json&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;With GET endpoints we were able to do the Read operations. With POST we will be able to do Create operations, as we will see in next section.&lt;/p&gt;
&lt;h3&gt;Handling POST&lt;/h3&gt;
&lt;p&gt;It's hard to do POST from the browser. So we will use &lt;strong&gt;requests&lt;/strong&gt; library to achieve this.&lt;/p&gt;
&lt;p&gt;Check expense count before doing POST.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;Expense&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;objects&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;count&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="mi"&gt;2&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Tastypie by default doesn't authorize a person to do POST request. The default authorization class is &lt;strong&gt;ReadOnlyAuthorization&lt;/strong&gt; which allows GET calls but doesn't allow POST calls. So you will have to disallow authorization checks for the time being. Add the following to ExpenseResource.Meta&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;authorization&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Authorization&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;You'll need to import &lt;code&gt;Authorization&lt;/code&gt; class for it.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;from&lt;/span&gt; &lt;span class="n"&gt;tastypie&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;authorization&lt;/span&gt; &lt;span class="n"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Authorization&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;After this, ExpenseResource would look like:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;class&lt;/span&gt; &lt;span class="n"&gt;ExpenseResource&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ModelResource&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;

    &lt;span class="n"&gt;class&lt;/span&gt; &lt;span class="n"&gt;Meta&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;queryset&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Expense&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;objects&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;all&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="n"&gt;resource_name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;expense&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;
        &lt;span class="n"&gt;fields&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;description&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;amount&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
        &lt;span class="n"&gt;filtering&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;amount&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;gt&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
            &lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;description&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;icontains&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="n"&gt;authorization&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Authorization&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Don't get into detail of Authorization for now, I will come back to it.&lt;/p&gt;
&lt;p&gt;Let's make a POST request to our rest endpoint which will create an Expense object in the database.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;post_url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="c1"&gt;//localhost:8000/api/expense/&amp;#39;&lt;/span&gt;
&lt;span class="n"&gt;post_data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;description&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;Bought&lt;/span&gt; &lt;span class="n"&gt;first&lt;/span&gt; &lt;span class="n"&gt;Disworld&lt;/span&gt; &lt;span class="n"&gt;book&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;amount&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;399&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="n"&gt;headers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;Content&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;type&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;application&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="n"&gt;import&lt;/span&gt; &lt;span class="n"&gt;requests&lt;/span&gt;
&lt;span class="n"&gt;import&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;
&lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;requests&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;post_url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dumps&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;post_data&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;headers&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;print&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;status_code&lt;/span&gt;
&lt;span class="mi"&gt;201&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;status_code 201 means that your Expense object was properly created. You can also verify it by checking that Expense count increased by 1.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;Expense&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;objects&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;count&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="mi"&gt;3&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;If you hit the GET endpoint from your browser, you will see this new Expense object too in the response. Try&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="nl"&gt;http:&lt;/span&gt;&lt;span class="c1"&gt;//localhost:8000/api/expense/?format=json&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;We have third commit at this point.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;git&lt;/span&gt; &lt;span class="n"&gt;checkout&lt;/span&gt; &lt;span class="mi"&gt;749&lt;/span&gt;&lt;span class="n"&gt;cf3&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;h4&gt;Explanation of POST&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;You need to POST at the same url where you get all the expenses. Compare the two urls.&lt;/li&gt;
&lt;li&gt;One way of posting is to POST json encoded data. So we used json.dumps&lt;/li&gt;
&lt;li&gt;If you are sending json encoded data, you need to send appopriate Content-type header too.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;br/&gt;&lt;/p&gt;
&lt;h4&gt;How this ties in with mobile&lt;/h4&gt;
&lt;p&gt;Android or iOS has a way to make POST request at a given url with headers. So you tell mobile app about the endpoint where they need to post and the data to post. They will call this rest endpoint, and the posted data will be handled by Django tastypie and proper row will be created in the database table.&lt;/p&gt;
&lt;h3&gt;Adding authentication&lt;/h3&gt;
&lt;p&gt;Currently GET and POST endpoints respond to every request. So even users who aren't registered with the site will be able to see the expenses. Our first step is ensuring that only registered users are able to use the GET endpoints.&lt;/p&gt;
&lt;h4&gt;Api tokens and sessions&lt;/h4&gt;
&lt;p&gt;In a web application, a user logs in once and then she is able to make any number of web requests without being asked to login every time. eg: User logs in once and then can see her expense list page. After first request she can refresh the page, and can still get response without being asked for her login credentials again. This works because Django uses sessions and cookies to store user state. So browser sends a cookie to Django everytime the user makes a request, and Django app can associate the cookie with a user and shows the data for this particular user.&lt;/p&gt;
&lt;p&gt;With mobile apps, there is no concept of sessions, unless the mobile is working with a WebView. The session corresponding thing in a mobile app is Api key. So an api key is associated with a user. Every REST call should include this api key, and then tastypie can use this key to verify whether a logged in user is making the request.&lt;/p&gt;
&lt;h4&gt;Creating user and api token&lt;/h4&gt;
&lt;p&gt;Let's create an user in our system and a corresponding api token for her.&lt;/p&gt;
&lt;p&gt;On a shell&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;u&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;User&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;objects&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;create_user&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;username&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;sheryl&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;password&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;abc&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;sheryl&lt;/span&gt;&lt;span class="err"&gt;@&lt;/span&gt;&lt;span class="n"&gt;abc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;com&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Tastypie provides a model called ApiKey which allows storing tokens for users. Let's create a token for Sheryl.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;from&lt;/span&gt; &lt;span class="n"&gt;tastypie&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;models&lt;/span&gt; &lt;span class="n"&gt;import&lt;/span&gt; &lt;span class="n"&gt;ApiKey&lt;/span&gt;
&lt;span class="n"&gt;ApiKey&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;objects&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="n"&gt;a23&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;u&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;We are setting the api token for sheryl as '1a23'&lt;/p&gt;
&lt;p&gt;You need to ensure tastypie is in INSTALLED_APPS and you have migrated before you could create ApiKey instance.&lt;/p&gt;
&lt;p&gt;The default authentication class provided by tastypie is &lt;strong&gt;Authentication&lt;/strong&gt; which allows anyone to make GET requests. We need to set ExpenseResource.Meta.authentication to ensure that only users who provide valid api key are able to get response from GET endpoints.&lt;/p&gt;
&lt;p&gt;Add the following on ExpensesResource.Meta.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;authentication&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ApiKeyAuthentication&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;You need to import ApiKeyAuthentication.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;from&lt;/span&gt; &lt;span class="n"&gt;tastypie&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;authentication&lt;/span&gt; &lt;span class="n"&gt;import&lt;/span&gt; &lt;span class="n"&gt;ApiKeyAuthentication&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Try the GET endpoint to get the list of expenses&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="nl"&gt;http:&lt;/span&gt;&lt;span class="c1"&gt;//localhost:8000/api/expense/?format=json&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;You will not see anything in response. If you see your runserver terminal, you'll notice that status code 401 is raised.&lt;/p&gt;
&lt;p&gt;Api key should be sent in the request to get proper response.&lt;/p&gt;
&lt;p&gt;Try the following url&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="nl"&gt;http:&lt;/span&gt;&lt;span class="c1"&gt;//localhost:8000/api/expense/?format=json&amp;amp;username=sheryl&amp;amp;api_key=1a23&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;With this Sheryl will be able to get proper api response.&lt;/p&gt;
&lt;p&gt;Try sending wrong api_key for sheryl and you will not see proper response.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="nl"&gt;http:&lt;/span&gt;&lt;span class="c1"&gt;//localhost:8000/api/expense/?format=json&amp;amp;username=sheryl&amp;amp;api_key=1a2&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;With these we ensure that only registered users of the system with proper api key will be able to make GET requests.&lt;/p&gt;
&lt;p&gt;Fourth commit at this point&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;git&lt;/span&gt; &lt;span class="n"&gt;checkout&lt;/span&gt; &lt;span class="mf"&gt;48725f&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;h4&gt;How this ties in with mobile app&lt;/h4&gt;
&lt;p&gt;When user installs the app, he logs in using his username and password for first time. These credentials are sent to Django server using a REST call. Django server returns the api key corresponding to this user to the mobile app. Mobile app stores this api token on mobile end and then uses this token for every subsequent REST call. User doesn't have to provide the credentials anymore.&lt;/p&gt;
&lt;h4&gt;Making unauthenticated POST requests&lt;/h4&gt;
&lt;p&gt;Unauthenticated POST requests will not work anymore&lt;/p&gt;
&lt;p&gt;Try creating an Expense without passing any api key.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;post_data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;description&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;Bought&lt;/span&gt; &lt;span class="n"&gt;Two&lt;/span&gt; &lt;span class="n"&gt;scoops&lt;/span&gt; &lt;span class="n"&gt;of&lt;/span&gt; &lt;span class="n"&gt;Django&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;amount&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;399&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="n"&gt;headers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;Content&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;type&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;application&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;requests&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;http://localhost:8000/api/expense/&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dumps&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;post_data&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;headers&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;print&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;status_code&lt;/span&gt;       &lt;span class="err"&gt;#&lt;/span&gt;&lt;span class="n"&gt;This&lt;/span&gt; &lt;span class="n"&gt;will&lt;/span&gt; &lt;span class="n"&gt;give&lt;/span&gt; &lt;span class="mi"&gt;401&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Check that Expense count isn't increased&lt;/p&gt;
&lt;h4&gt;Making authenticated POST requests&lt;/h4&gt;
&lt;p&gt;You only need to change the url to include username and api_key in the url. This will make the request authenticated.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;requests&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;http://localhost:8000/api/expense/?username=sheryl&amp;amp;api_key=1a23&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dumps&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;post_data&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;headers&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;This should have worked and Expense count should have increased.&lt;/p&gt;
&lt;p&gt;Try with wrong api_key and it will fail.&lt;/p&gt;
&lt;h3&gt;Getting only User's expense&lt;/h3&gt;
&lt;p&gt;Till now we aren't associating Expense to User. Let's add a ForeignKey to User from Expense.&lt;/p&gt;
&lt;p&gt;Expense model becomes:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;from&lt;/span&gt; &lt;span class="n"&gt;django&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;db&lt;/span&gt; &lt;span class="n"&gt;import&lt;/span&gt; &lt;span class="n"&gt;models&lt;/span&gt;
&lt;span class="n"&gt;from&lt;/span&gt; &lt;span class="n"&gt;django&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;contrib&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;auth&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;models&lt;/span&gt; &lt;span class="n"&gt;import&lt;/span&gt; &lt;span class="n"&gt;User&lt;/span&gt;


&lt;span class="n"&gt;class&lt;/span&gt; &lt;span class="n"&gt;Expense&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;models&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Model&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;description&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;models&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CharField&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;max_length&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;amount&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;models&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;IntegerField&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;models&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ForeignKey&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;User&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;null&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Since we already have some Expenses in db which aren't associated with a User, so we kept User as a nullable field.&lt;/p&gt;
&lt;p&gt;Make and run migrations&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;python&lt;/span&gt; &lt;span class="n"&gt;manage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;py&lt;/span&gt; &lt;span class="n"&gt;makemigrations&lt;/span&gt;
&lt;span class="n"&gt;python&lt;/span&gt; &lt;span class="n"&gt;manage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;py&lt;/span&gt; &lt;span class="n"&gt;migrate&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Right now our &lt;strong&gt;authorization&lt;/strong&gt; class is set to &lt;strong&gt;Authorization&lt;/strong&gt;. With this every user is &lt;strong&gt;authorized&lt;/strong&gt; to see every expense. We will have to add a custom authorization class to enforce that users see only their expenses.&lt;/p&gt;
&lt;p&gt;Add the following to expenses/api.py&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;class&lt;/span&gt; &lt;span class="n"&gt;ExpenseAuthorization&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Authorization&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;

    &lt;span class="n"&gt;def&lt;/span&gt; &lt;span class="n"&gt;read_list&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;object_list&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;bundle&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;object_list&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;bundle&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;And change &lt;strong&gt;authorization&lt;/strong&gt; on ExpenseResource.Meta so it becomes:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;class&lt;/span&gt; &lt;span class="n"&gt;ExpenseResource&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ModelResource&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;

    &lt;span class="n"&gt;class&lt;/span&gt; &lt;span class="n"&gt;Meta&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;queryset&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Expense&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;objects&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;all&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="n"&gt;resource_name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;expense&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;
        &lt;span class="n"&gt;fields&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;description&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;amount&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
        &lt;span class="n"&gt;filtering&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;amount&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;gt&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
            &lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;description&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;icontains&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="n"&gt;authorization&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ExpenseAuthorization&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="n"&gt;authentication&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ApiKeyAuthentication&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;h4&gt;Explanation of ExpenseAuthorization&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;When GET endpoint is called for expense list, object_list is created which gives all the expenses.&lt;/li&gt;
&lt;li&gt;After this, authorization is checked where further filtering could be done.&lt;/li&gt;
&lt;li&gt;In case of GET on list endpoint, authorization class' read_list() method is called. object_list is passed to read_list.&lt;/li&gt;
&lt;li&gt;In tastypie there is a variable called bundle. And bundle has access to request using bundle.request&lt;/li&gt;
&lt;li&gt;When authentication is used properly, bundle.request.user is populated with correct user.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Try expense list endpoint for Sheryl&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="nl"&gt;http:&lt;/span&gt;&lt;span class="c1"&gt;//localhost:8000/api/expense/?format=json&amp;amp;username=sheryl&amp;amp;api_key=1a23&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;You will not get any expense after adding ExpenseAuthorization&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;meta&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;limit&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;next&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;offset&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;previous&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;total_count&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;objects&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[]}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;This happenned because at this point no expense is associated with Sheryl.&lt;/p&gt;
&lt;h4&gt;Create an expense for Sheryl and try the GET endpoint&lt;/h4&gt;
&lt;p&gt;On the shell&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;u&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;User&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;objects&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;username&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;sheryl&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;Expense&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;objects&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;description&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;Paid&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;the&lt;/span&gt; &lt;span class="n"&gt;servers&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;amount&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;u&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;Expense&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;objects&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;description&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;Paid&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;CI&lt;/span&gt; &lt;span class="n"&gt;server&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;amount&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;500&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;u&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Try expense list endpoint for Sheryl again&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="nl"&gt;http:&lt;/span&gt;&lt;span class="c1"&gt;//localhost:8000/api/expense/?format=json&amp;amp;username=sheryl&amp;amp;api_key=1a23&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;You should be able to see all of Sheryl's expenses.&lt;/p&gt;
&lt;p&gt;Fifth commit here.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;git&lt;/span&gt; &lt;span class="n"&gt;checkout&lt;/span&gt; &lt;span class="mf"&gt;26f&lt;/span&gt;&lt;span class="mi"&gt;7&lt;/span&gt;&lt;span class="n"&gt;c1&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;h4&gt;How mobile app will use it.&lt;/h4&gt;
&lt;p&gt;When Sheryl installs the app, she will be asked to login for the first time. There will be a REST endpoint which takes the username and password for a user and if the credentials are right, returns the api key for the user. Sheryl's api key will be returned to the mobile app which will store it in local storage. And when Sheryl wants to see her expenses, this REST call will be made to Django server.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="nl"&gt;http:&lt;/span&gt;&lt;span class="c1"&gt;//localhost:8000/api/expense/?format=json&amp;amp;username=sheryl&amp;amp;api_key=1a23&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;This will only return Sheryl's expenses.&lt;/p&gt;
&lt;h3&gt;POST and create Sheryl's expense&lt;/h3&gt;
&lt;p&gt;Till now if a POST request is made, even if with Sheryl's api key, expense is created in db but is not associated with Sheryl.&lt;/p&gt;
&lt;p&gt;We want to add functionality where if POST request is made from Sheryl's device then expense is associated with Sheryl. If POST request is made from Mark's device then expense should be associated with Mark.&lt;/p&gt;
&lt;p&gt;Tastypie provides several hookpoints. We will use one such hookpoint. ModelResource provides a method called &lt;strong&gt;hydrate&lt;/strong&gt; which we need to override. Add the following method to ExpenseResource.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;def&lt;/span&gt; &lt;span class="n"&gt;hydrate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;bundle&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;bundle&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;obj&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;bundle&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;bundle&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;ul&gt;
&lt;li&gt;This method is called during POST/PUT calls.&lt;/li&gt;
&lt;li&gt;bundle.obj is an Expense instance about to be saved in the database.&lt;/li&gt;
&lt;li&gt;So we set &lt;strong&gt;user&lt;/strong&gt; on bundle.obj by reading it from bundle.request. We have already discussed how bundle.request is populated during authentication flow.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Make a POST request now with Sheryl's api_key.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;post_data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;description&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;Paid&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;iDoneThis&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;amount&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;700&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;requests&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;http://localhost:8000/api/expense/?username=sheryl&amp;amp;api_key=1a23&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dumps&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;post_data&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;headers&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Verify that the latest expense instance gets associated with Sheryl. You can also verify it by seeing that this object gets returned in GET expense list endpoint.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="nl"&gt;http:&lt;/span&gt;&lt;span class="c1"&gt;//localhost:8000/api/expense/?format=json&amp;amp;username=sheryl&amp;amp;api_key=1a23&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Sixth commit at this point&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;git&lt;/span&gt; &lt;span class="n"&gt;checkout&lt;/span&gt; &lt;span class="mi"&gt;17&lt;/span&gt;&lt;span class="n"&gt;b932&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;h4&gt;Try on your own&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;Create one more user in database, from shell.&lt;/li&gt;
&lt;li&gt;Create api key for this user.&lt;/li&gt;
&lt;li&gt;POST to REST endpoint with this new user's api_key and username and verify that the expense gets associated with this new user.&lt;/li&gt;
&lt;li&gt;Check GET expense list for this new user and verify that only expense created for this user is in the response.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Now is a good time to dig deeper into django-tastypie and understand about following:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Dehydrate cycle. It is used during GET calls.&lt;/li&gt;
&lt;li&gt;Hydrate cycle. It is used during POST/PUT calls. Once you read about hydrate cycle, you will understand when method &lt;strong&gt;hydrate()&lt;/strong&gt; is called.&lt;/li&gt;
&lt;li&gt;More about authorization and different methods available on &lt;strong&gt;Authorization&lt;/strong&gt; which could be overridden by you.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Want more?&lt;/h3&gt;
&lt;p&gt;I am still trying few things with tastypie. Hereafter I will not have much explanation, but I will point to the commit where I attain certain functionality change.&lt;/p&gt;
&lt;h3&gt;Authorization on detail endpoint.&lt;/h3&gt;
&lt;p&gt;Expense with id 1 is not associated with any user. But Sheryl is still able to see it at:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="nl"&gt;http:&lt;/span&gt;&lt;span class="c1"&gt;//localhost:8000/api/expense/1/?format=json&amp;amp;username=sheryl&amp;amp;api_key=1a23&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;She shouldn't be able to see it as it is not her expense.&lt;/p&gt;
&lt;p&gt;So add the following to ExpenseAuthorization&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;def&lt;/span&gt; &lt;span class="n"&gt;read_detail&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;object_list&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;bundle&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;obj&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;object_list&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;obj&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;bundle&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;After this Sheryl will not be able to see detail endpoint of any expense which doesn't belong to her. Try it&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="nl"&gt;http:&lt;/span&gt;&lt;span class="c1"&gt;//localhost:8000/api/expense/1/?format=json&amp;amp;username=sheryl&amp;amp;api_key=1a23&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Commit id for this:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;e650f3&lt;/span&gt;
&lt;span class="n"&gt;git&lt;/span&gt; &lt;span class="n"&gt;show&lt;/span&gt; &lt;span class="n"&gt;e650f3&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;h3&gt;PUT endpoint&lt;/h3&gt;
&lt;p&gt;Expense with id 5 belongs to Sheryl. She wants to &lt;strong&gt;update&lt;/strong&gt; this expense, she essentially want to change the description.&lt;/p&gt;
&lt;p&gt;Current thing is:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="nl"&gt;http:&lt;/span&gt;&lt;span class="c1"&gt;//localhost:8000/api/expense/5/?format=json&amp;amp;username=sheryl&amp;amp;api_key=1a23&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Make PUT request&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;put_url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;http://localhost:8000/api/expense/5/?username=sheryl&amp;amp;api_key=1a23&amp;quot;&lt;/span&gt;
&lt;span class="n"&gt;put_data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;description&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;Paid&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;Travis&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="n"&gt;headers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;Content&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;type&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;application&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;requests&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;put&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;put_url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dumps&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;put_data&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;headers&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Description of Expense 5 is updated as you can verify by trying the detail endpoint again.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="nl"&gt;http:&lt;/span&gt;&lt;span class="c1"&gt;//localhost:8000/api/expense/5/?format=json&amp;amp;username=sheryl&amp;amp;api_key=1a23&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Notice that amount remains unchanged. So PUT changes whatever data you provide in the api call and lets everything else remain as it is.&lt;/p&gt;
&lt;h3&gt;DELETE endpoint&lt;/h3&gt;
&lt;p&gt;First check all of Sheryl's expenses&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="nl"&gt;http:&lt;/span&gt;&lt;span class="c1"&gt;//localhost:8000/api/expense/?format=json&amp;amp;username=sheryl&amp;amp;api_key=1a23&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Sheryl wants to delete her expense with id 5. After this is done she will have one less expense in db.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;delete_url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;http://localhost:8000/api/expense/5/?username=sheryl&amp;amp;api_key=1a23&amp;quot;&lt;/span&gt;
&lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;requests&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;delete&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;delete_url&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Verify that this expense got deleted.&lt;/p&gt;
&lt;p&gt;So we were able to do Create, Read, Update and Delete with REST api calls.&lt;/p&gt;
&lt;h3&gt;Restrict POST request to certain users only&lt;/h3&gt;
&lt;p&gt;Suppose we want the users to be able to create expenses from web end but don't want to allow creating expense from mobile using the api. Yeah, weird requiremtn.&lt;/p&gt;
&lt;p&gt;Also we don't want to disallow POST for all users. We still want Sheryl to be able to POST.&lt;/p&gt;
&lt;p&gt;To try this we first need a new user with api key in our system. Create it from Django shell.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;u&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;User&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;objects&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;create_user&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;username&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;mark&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;password&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;def&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;mark&lt;/span&gt;&lt;span class="err"&gt;@&lt;/span&gt;&lt;span class="n"&gt;abc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;com&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;ApiKey&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;objects&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="n"&gt;b34&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;u&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;h4&gt;Restricting POST for everyone except Sheryl&lt;/h4&gt;
&lt;p&gt;Add following method to ExpenseAuthorization&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;def&lt;/span&gt; &lt;span class="n"&gt;create_detail&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;object_list&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;bundle&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;bundle&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;
    &lt;span class="err"&gt;#&lt;/span&gt; &lt;span class="n"&gt;Return&lt;/span&gt; &lt;span class="n"&gt;True&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;current&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt; &lt;span class="n"&gt;is&lt;/span&gt; &lt;span class="n"&gt;Sheryl&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;False&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;username&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;sheryl&amp;quot;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Try making POST request as Mark and see you will not be able to do it. If you want you can see the expense count at this point.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;post_data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;description&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;Petty&lt;/span&gt; &lt;span class="n"&gt;expense&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;amount&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;3000&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;requests&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;http://localhost:8000/api/expense/?username=mark&amp;amp;api_key=2b34&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dumps&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;post_data&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;headers&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;print&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;status_code&lt;/span&gt; &lt;span class="err"&gt;#&lt;/span&gt;&lt;span class="n"&gt;Should&lt;/span&gt; &lt;span class="n"&gt;have&lt;/span&gt; &lt;span class="n"&gt;got&lt;/span&gt; &lt;span class="mi"&gt;401&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Also you can check the expense count again to verify that expense isn't created.&lt;/p&gt;
&lt;p&gt;Status code 401 tells that you aren't authorized to do this operation.&lt;/p&gt;
&lt;h4&gt;Verify that Sheryl is still able to create expense&lt;/h4&gt;
&lt;p&gt;Try posting the same post_data as Sheryl&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;requests&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;http://localhost:8000/api/expense/?username=sheryl&amp;amp;api_key=1a23&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dumps&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;post_data&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;headers&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;print&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;status_code&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Status code must be 201 in this case which means expense is created. You will be able to see this expense at Sheryl's GET expense list endpoint.&lt;/p&gt;
&lt;h4&gt;Verify that Mark is still able to do GET&lt;/h4&gt;
&lt;p&gt;Mark or any other user should still be able to make GET request even if he isn't able to make POST request.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="nl"&gt;http:&lt;/span&gt;&lt;span class="c1"&gt;//localhost:8000/api/expense/?username=mark&amp;amp;api_key=2b34&amp;amp;format=json&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Since Mark doesn't have any expense in db, so no object is there is &lt;strong&gt;objects&lt;/strong&gt; key of response. Try creating an expense for this user from shell and then try the GET endpoint again.&lt;/p&gt;
&lt;h3&gt;Explicitly defining fields and customising them&lt;/h3&gt;
&lt;p&gt;ModelResource.Meta.fields can be dealt with in a similar way to ModelForm.Meta.fields. If you add the field to ModelResource.Meta.fields then it gets sane default behavriour. But it can be customised by adding the field explicitly on the ModelResource.&lt;/p&gt;
&lt;p&gt;Let's try customising &lt;strong&gt;description&lt;/strong&gt; field.&lt;/p&gt;
&lt;p&gt;Add it explicitly on ExpenseResource&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;description&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;fields&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CharField&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;You will need to import the following for it to work.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;from&lt;/span&gt; &lt;span class="n"&gt;tastypie&lt;/span&gt; &lt;span class="n"&gt;import&lt;/span&gt; &lt;span class="n"&gt;fields&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Try the GET endpoint&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="nl"&gt;http:&lt;/span&gt;&lt;span class="c1"&gt;//localhost:8000/api/expense/?username=sheryl&amp;amp;api_key=1a23&amp;amp;format=json&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;You will see description as null for every expense. Because we committed a mistake.&lt;/p&gt;
&lt;p&gt;While explicitly defining a field, we also need to tell the expense attribute that needs to be used for this particular field.&lt;/p&gt;
&lt;p&gt;So we need to say&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;description&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;fields&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CharField&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;attribute&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;description&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Now GET endpoint will work as it used to work earlier.&lt;/p&gt;
&lt;p&gt;But we did not achieve anything by explicitly adding the field. So what's the point of explicitly adding it.&lt;/p&gt;
&lt;p&gt;Suppose you want the description in the detail endpoint but don't want it on list endpoint. This can be achieved in following way&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;description&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;fields&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CharField&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;attribute&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;description&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;use_in&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;detail&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Try the list and detail endpoint now and notice the difference.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="nl"&gt;http:&lt;/span&gt;&lt;span class="c1"&gt;//localhost:8000/api/expense/?username=sheryl&amp;amp;api_key=1a23&amp;amp;format=json&lt;/span&gt;
&lt;span class="nl"&gt;http:&lt;/span&gt;&lt;span class="c1"&gt;//localhost:8000/api/expense/8/?username=sheryl&amp;amp;api_key=1a23&amp;amp;format=json&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;&lt;strong&gt;use_in&lt;/strong&gt; is documented &lt;a href="http://django-tastypie.readthedocs.org/en/latest/fields.html#use-in" target="_blank"&gt;here&lt;/a&gt;&lt;/p&gt;</description><guid>http://agiliq.com/blog/2015/03/getting-started-with-django-tastypie/</guid></item><item><title>Importing your old comments to Disqus site</title><link>http://agiliq.com/blog/2015/01/importing-your-old-comments-to-disqus-site/</link><description>&lt;p&gt;In one of my latest &lt;a href="http://agiliq.com/blog/2014/11/disqus-and-disqus-sso/"&gt;blogpost&lt;/a&gt; on disqus I covered topics on integrating Disqus to the website and disqus SSO. In this post, I will let you know how to migrate the older comments to Disqus. &lt;/p&gt;
&lt;p&gt;If you sneak peek in to the alluring features of disqus you may make your mind to migrate your custom commenting system on your blog to use disqus commenting system. The threaded comments and replies, powerful moderation and admin tools, RSS options and many more features come in as battaries included with Disqus which makes the commenting more interactive and easy to deal with.&lt;/p&gt;
&lt;p&gt;Let us kick start the process. Till date importing the old comments directly from the blogger and wordpress to disqus is feasible. This can be achieved by using tools and plugins that are already existing in them and its pretty straight forward. In this post our prime concern will be laid on custom XML import format. If you are using neither blogger, nor wordpress the custom XML import format which is based on the WXR (WordPress eXtended RSS) schema comes to the rescue. Disqus also supports MovableType, and IntenseDebate but preferably WXR is of more concern.&lt;/p&gt;
&lt;p&gt;I consider a case in a Django project, which does adopt a custom commenting system in which the comments are stored in a postgresql database. This process of migrating the comments to disqus comprises of two steps in this case.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Creating a WXR schema of the existing comments&lt;/li&gt;
&lt;li&gt;Importing the WXR file to Disqus site.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;1. Creating a WXR schema of the existing comments&lt;/h2&gt;
&lt;p&gt;WXR format is based on the Rss specification. This format is normally used for importing or exporting data from wordpress servers. Now the aim is to create a WXR file from the existing comments in our storage. For that we are going to write a python script. Disqus has prescribed a format of the file that we are planning to import to Disqus. The format looks in the following way.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="cp"&gt;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot;?&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;rss&lt;/span&gt; &lt;span class="na"&gt;version=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;2.0&amp;quot;&lt;/span&gt;
  &lt;span class="na"&gt;xmlns:content=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;http://purl.org/rss/1.0/modules/content/&amp;quot;&lt;/span&gt;
  &lt;span class="na"&gt;xmlns:dsq=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;http://www.disqus.com/&amp;quot;&lt;/span&gt;
  &lt;span class="na"&gt;xmlns:dc=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;http://purl.org/dc/elements/1.1/&amp;quot;&lt;/span&gt;
  &lt;span class="na"&gt;xmlns:wp=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;http://wordpress.org/export/1.0/&amp;quot;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;channel&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;item&amp;gt;&lt;/span&gt;
      &lt;span class="c"&gt;&amp;lt;!-- title of article --&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;title&amp;gt;&lt;/span&gt;Foo bar&lt;span class="nt"&gt;&amp;lt;/title&amp;gt;&lt;/span&gt;
      &lt;span class="c"&gt;&amp;lt;!-- absolute URI to article --&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;link&amp;gt;&lt;/span&gt;http://foo.com/example&lt;span class="nt"&gt;&amp;lt;/link&amp;gt;&lt;/span&gt;
      &lt;span class="c"&gt;&amp;lt;!-- body of the page or post; use cdata; html allowed (though will be formatted to DISQUS specs) --&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;content:encoded&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;&amp;lt;![&lt;/span&gt;&lt;span class="nx"&gt;CDATA&lt;/span&gt;&lt;span class="err"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;Hello&lt;/span&gt; &lt;span class="nx"&gt;world&lt;/span&gt;&lt;span class="cp"&gt;]]&amp;gt;&lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;/content:encoded&amp;gt;&lt;/span&gt;
      &lt;span class="c"&gt;&amp;lt;!-- value used within disqus_identifier; usually internal identifier of article --&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;dsq:thread_identifier&amp;gt;&lt;/span&gt;disqus_identifier&lt;span class="nt"&gt;&amp;lt;/dsq:thread_identifier&amp;gt;&lt;/span&gt;
      &lt;span class="c"&gt;&amp;lt;!-- creation date of thread (article), in GMT. Must be YYYY-MM-DD HH:MM:SS 24-hour format. --&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;wp:post_date_gmt&amp;gt;&lt;/span&gt;2010-09-20 09:13:44&lt;span class="nt"&gt;&amp;lt;/wp:post_date_gmt&amp;gt;&lt;/span&gt;
      &lt;span class="c"&gt;&amp;lt;!-- open/closed values are acceptable --&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;wp:comment_status&amp;gt;&lt;/span&gt;open&lt;span class="nt"&gt;&amp;lt;/wp:comment_status&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;wp:comment&amp;gt;&lt;/span&gt;
        &lt;span class="c"&gt;&amp;lt;!-- sso only; see docs --&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;dsq:remote&amp;gt;&lt;/span&gt;
          &lt;span class="c"&gt;&amp;lt;!-- unique internal identifier; username, user id, etc. --&amp;gt;&lt;/span&gt;
          &lt;span class="nt"&gt;&amp;lt;dsq:id&amp;gt;&lt;/span&gt;user id&lt;span class="nt"&gt;&amp;lt;/dsq:id&amp;gt;&lt;/span&gt;
          &lt;span class="c"&gt;&amp;lt;!-- avatar --&amp;gt;&lt;/span&gt;
          &lt;span class="nt"&gt;&amp;lt;dsq:avatar&amp;gt;&lt;/span&gt;http://url.to/avatar.png&lt;span class="nt"&gt;&amp;lt;/dsq:avatar&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/dsq:remote&amp;gt;&lt;/span&gt;
        &lt;span class="c"&gt;&amp;lt;!-- internal id of comment --&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;wp:comment_id&amp;gt;&lt;/span&gt;65&lt;span class="nt"&gt;&amp;lt;/wp:comment_id&amp;gt;&lt;/span&gt;
        &lt;span class="c"&gt;&amp;lt;!-- author display name --&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;wp:comment_author&amp;gt;&lt;/span&gt;Foo Bar&lt;span class="nt"&gt;&amp;lt;/wp:comment_author&amp;gt;&lt;/span&gt;
        &lt;span class="c"&gt;&amp;lt;!-- author email address --&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;wp:comment_author_email&amp;gt;&lt;/span&gt;foo@bar.com&lt;span class="nt"&gt;&amp;lt;/wp:comment_author_email&amp;gt;&lt;/span&gt;
        &lt;span class="c"&gt;&amp;lt;!-- author url, optional --&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;wp:comment_author_url&amp;gt;&lt;/span&gt;http://www.foo.bar/&lt;span class="nt"&gt;&amp;lt;/wp:comment_author_url&amp;gt;&lt;/span&gt;
        &lt;span class="c"&gt;&amp;lt;!-- author ip address --&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;wp:comment_author_IP&amp;gt;&lt;/span&gt;93.48.67.119&lt;span class="nt"&gt;&amp;lt;/wp:comment_author_IP&amp;gt;&lt;/span&gt;
        &lt;span class="c"&gt;&amp;lt;!-- comment datetime, in GMT. Must be YYYY-MM-DD HH:MM:SS 24-hour format. --&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;wp:comment_date_gmt&amp;gt;&lt;/span&gt;2010-09-20 13:19:10&lt;span class="nt"&gt;&amp;lt;/wp:comment_date_gmt&amp;gt;&lt;/span&gt;
        &lt;span class="c"&gt;&amp;lt;!-- comment body; use cdata; html allowed (though will be formatted to DISQUS specs) --&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;wp:comment_content&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;&amp;lt;![&lt;/span&gt;&lt;span class="nx"&gt;CDATA&lt;/span&gt;&lt;span class="err"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;Hello&lt;/span&gt; &lt;span class="nx"&gt;world&lt;/span&gt;&lt;span class="cp"&gt;]]&amp;gt;&lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;/wp:comment_content&amp;gt;&lt;/span&gt;
        &lt;span class="c"&gt;&amp;lt;!-- is this comment approved? 0/1 --&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;wp:comment_approved&amp;gt;&lt;/span&gt;1&lt;span class="nt"&gt;&amp;lt;/wp:comment_approved&amp;gt;&lt;/span&gt;
        &lt;span class="c"&gt;&amp;lt;!-- parent id (match up with wp:comment_id) --&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;wp:comment_parent&amp;gt;&lt;/span&gt;0&lt;span class="nt"&gt;&amp;lt;/wp:comment_parent&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;/wp:comment&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/item&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/channel&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/rss&amp;gt;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;ul&gt;
&lt;li&gt;Things to keep in mind:&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;As recommended by the Disqus we need some points to keep in mind while creating a WXR file of the existing comments.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Only use the "dsq:remote" tag (and its children) if you're using Single Sign-On; otherwise remove it.&lt;/li&gt;
&lt;li&gt;If you're manually filling in &lt;wp:comment_author_email&gt; make sure it's unique to each user or else all comments will display the same author name.&lt;/li&gt;
&lt;li&gt;Each "item" tag can parent an infinite number of "wp:comment" tags.&lt;/li&gt;
&lt;li&gt;There is a minimum character requirement for each comment message, which is 3 characters.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Every item is supposed to be a comment on the site. As I am not using the SSO in the site, we can remove the &lt;dsq:remote&gt;. The link specifies the site url to the specific post. In my case I happened to find some encoding issues with the &lt;content&gt; which does take the whole body of the post so I preferred removing it from the WXR file and it worked fine. &lt;/p&gt;
&lt;p&gt;The script appears to be in the below manner. I accessed my comment model to get the comment data. And then I created the xml file in the format prescribed by Disqus. I skipped some tags which ought to mess up encryption issues. But beware, try to create as the disqus prescribes for the easy flow. The script looks like the following way.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="nb"&gt;from&lt;/span&gt; &lt;span class="nx"&gt;mysite.models&lt;/span&gt; &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;Comment&lt;/span&gt;
&lt;span class="nb"&gt;from&lt;/span&gt; &lt;span class="nx"&gt;django.contrib.sites.models&lt;/span&gt; &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;Site&lt;/span&gt;

&lt;span class="n"&gt;site&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Site.objects.all&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="err"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="cp"&gt;]&lt;/span&gt;

comments = Comment.objects.all()
xml_data_header = &amp;quot;&amp;quot;&amp;quot;&lt;span class="cp"&gt;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot;?&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;rss&lt;/span&gt; &lt;span class="na"&gt;version=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;2.0&amp;quot;&lt;/span&gt;
                  &lt;span class="na"&gt;xmlns:content=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;http://purl.org/rss/1.0/modules/content/&amp;quot;&lt;/span&gt;
                  &lt;span class="na"&gt;xmlns:dsq=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;http://www.disqus.com/&amp;quot;&lt;/span&gt;
                  &lt;span class="na"&gt;xmlns:dc=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;http://purl.org/dc/elements/1.1/&amp;quot;&lt;/span&gt;
                  &lt;span class="na"&gt;xmlns:wp=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;http://wordpress.org/export/1.0/&amp;quot;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
                      &lt;span class="nt"&gt;&amp;lt;channel&amp;gt;&lt;/span&gt;
                  &amp;quot;&amp;quot;&amp;quot;
xml_data_footer = &amp;quot;&amp;quot;&amp;quot;
                      &lt;span class="nt"&gt;&amp;lt;/channel&amp;gt;&lt;/span&gt;
                    &lt;span class="nt"&gt;&amp;lt;/rss&amp;gt;&lt;/span&gt;
                  &amp;quot;&amp;quot;&amp;quot;
file_dis = open(&amp;#39;disqus.xml&amp;#39;,&amp;#39;wb&amp;#39;)
file_dis.write(xml_data_header)
for comment in comments:
    xml_data_all = &amp;#39;&amp;#39;
    xml_data = &amp;quot;&amp;quot;&amp;quot;
                &lt;span class="nt"&gt;&amp;lt;item&amp;gt;&lt;/span&gt;
                  &lt;span class="nt"&gt;&amp;lt;title&amp;gt;&lt;/span&gt;{0}&lt;span class="nt"&gt;&amp;lt;/title&amp;gt;&lt;/span&gt;
                  &lt;span class="nt"&gt;&amp;lt;link&amp;gt;&lt;/span&gt;http://{1}&lt;span class="nt"&gt;&amp;lt;/link&amp;gt;&lt;/span&gt;
                  &lt;span class="nt"&gt;&amp;lt;content:encoded&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;&amp;lt;![&lt;/span&gt;&lt;span class="nx"&gt;CDATA&lt;/span&gt;&lt;span class="err"&gt;[&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="cp"&gt;]]&amp;gt;&lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;/content:encoded&amp;gt;&lt;/span&gt;
                  &lt;span class="nt"&gt;&amp;lt;dsq:thread_identifier&amp;gt;&lt;/span&gt;{3}&lt;span class="nt"&gt;&amp;lt;/dsq:thread_identifier&amp;gt;&lt;/span&gt;
                  &lt;span class="nt"&gt;&amp;lt;wp:post_date_gmt&amp;gt;&lt;/span&gt;{4}&lt;span class="nt"&gt;&amp;lt;/wp:post_date_gmt&amp;gt;&lt;/span&gt;
                  &lt;span class="nt"&gt;&amp;lt;wp:comment_status&amp;gt;&lt;/span&gt;open&lt;span class="nt"&gt;&amp;lt;/wp:comment_status&amp;gt;&lt;/span&gt;
                  &lt;span class="nt"&gt;&amp;lt;wp:comment&amp;gt;&lt;/span&gt;
                    &lt;span class="nt"&gt;&amp;lt;wp:comment_id&amp;gt;&lt;/span&gt;{5}&lt;span class="nt"&gt;&amp;lt;/wp:comment_id&amp;gt;&lt;/span&gt;
                    &lt;span class="nt"&gt;&amp;lt;wp:comment_author&amp;gt;&lt;/span&gt;{6}&lt;span class="nt"&gt;&amp;lt;/wp:comment_author&amp;gt;&lt;/span&gt;
                    &lt;span class="nt"&gt;&amp;lt;wp:comment_author_email&amp;gt;&lt;/span&gt;{7}&lt;span class="nt"&gt;&amp;lt;/wp:comment_author_email&amp;gt;&lt;/span&gt;
                    &lt;span class="nt"&gt;&amp;lt;wp:comment_author_url&amp;gt;&lt;/span&gt;{8}&lt;span class="nt"&gt;&amp;lt;/wp:comment_author_url&amp;gt;&lt;/span&gt;
                    &lt;span class="nt"&gt;&amp;lt;wp:comment_author_IP&amp;gt;&lt;/span&gt;{9}&lt;span class="nt"&gt;&amp;lt;/wp:comment_author_IP&amp;gt;&lt;/span&gt;
                    &lt;span class="nt"&gt;&amp;lt;wp:comment_date_gmt&amp;gt;&lt;/span&gt;{10}&lt;span class="nt"&gt;&amp;lt;/wp:comment_date_gmt&amp;gt;&lt;/span&gt;
                    &lt;span class="nt"&gt;&amp;lt;wp:comment_content&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;&amp;lt;![&lt;/span&gt;&lt;span class="nx"&gt;CDATA&lt;/span&gt;&lt;span class="err"&gt;[&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="mi"&gt;11&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="cp"&gt;]]&amp;gt;&lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;/wp:comment_content&amp;gt;&lt;/span&gt;
                    &lt;span class="nt"&gt;&amp;lt;wp:comment_approved&amp;gt;&lt;/span&gt;1&lt;span class="nt"&gt;&amp;lt;/wp:comment_approved&amp;gt;&lt;/span&gt;
                  &lt;span class="nt"&gt;&amp;lt;/wp:comment&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;/item&amp;gt;&lt;/span&gt;

                &amp;quot;&amp;quot;&amp;quot;.format(comment.comment_for.title.encode(&amp;#39;utf-8&amp;#39;), site.domain+comment.comment_for.get_absolute_url().encode(&amp;#39;utf-8&amp;#39;), comment.comment_for.text.raw.encode(&amp;#39;utf-8&amp;#39;), comment.comment_for.pk, comment.comment_for.created_on, comment.pk, \
                    comment.user_name.encode(&amp;#39;utf-8&amp;#39;), comment.email_id.encode(&amp;#39;utf-8&amp;#39;), comment.user_ip, comment.created_on, comment.text.encode(&amp;#39;utf-8&amp;#39;), \
                    )
    # xml_data_all += xml_data
    file_dis.write(xml_data)

file_dis.write(xml_data_footer)
file_dis.close()
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Once you run the above script the resultant will be a "disqus.xml" file. An example output of the file looks like this:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="cp"&gt;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot;?&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;rss&lt;/span&gt; &lt;span class="na"&gt;version=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;2.0&amp;quot;&lt;/span&gt;
              &lt;span class="na"&gt;xmlns:content=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;http://purl.org/rss/1.0/modules/content/&amp;quot;&lt;/span&gt;
              &lt;span class="na"&gt;xmlns:dsq=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;http://www.disqus.com/&amp;quot;&lt;/span&gt;
              &lt;span class="na"&gt;xmlns:dc=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;http://purl.org/dc/elements/1.1/&amp;quot;&lt;/span&gt;
              &lt;span class="na"&gt;xmlns:wp=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;http://wordpress.org/export/1.0/&amp;quot;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
                  &lt;span class="nt"&gt;&amp;lt;channel&amp;gt;&lt;/span&gt;                  
                    &lt;span class="nt"&gt;&amp;lt;item&amp;gt;&lt;/span&gt;
                      &lt;span class="nt"&gt;&amp;lt;title&amp;gt;&lt;/span&gt;Google Appengine - First Impressions&lt;span class="nt"&gt;&amp;lt;/title&amp;gt;&lt;/span&gt;
                      &lt;span class="nt"&gt;&amp;lt;link&amp;gt;&lt;/span&gt;http://agiliq.com/blog/2008/04/google-appengine-first-impressions/&lt;span class="nt"&gt;&amp;lt;/link&amp;gt;&lt;/span&gt;
                      &lt;span class="nt"&gt;&amp;lt;content:encoded&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;&amp;lt;![&lt;/span&gt;&lt;span class="nx"&gt;CDATA&lt;/span&gt;&lt;span class="err"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;245&lt;/span&gt;&lt;span class="cp"&gt;]]&amp;gt;&lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;/content:encoded&amp;gt;&lt;/span&gt;
                      &lt;span class="nt"&gt;&amp;lt;dsq:thread_identifier&amp;gt;&lt;/span&gt;245&lt;span class="nt"&gt;&amp;lt;/dsq:thread_identifier&amp;gt;&lt;/span&gt;
                      &lt;span class="nt"&gt;&amp;lt;wp:post_date_gmt&amp;gt;&lt;/span&gt;2008-04-09 04:02:57&lt;span class="nt"&gt;&amp;lt;/wp:post_date_gmt&amp;gt;&lt;/span&gt;
                      &lt;span class="nt"&gt;&amp;lt;wp:comment_status&amp;gt;&lt;/span&gt;open&lt;span class="nt"&gt;&amp;lt;/wp:comment_status&amp;gt;&lt;/span&gt;
                      &lt;span class="nt"&gt;&amp;lt;wp:comment&amp;gt;&lt;/span&gt;
                        &lt;span class="nt"&gt;&amp;lt;wp:comment_id&amp;gt;&lt;/span&gt;482&lt;span class="nt"&gt;&amp;lt;/wp:comment_id&amp;gt;&lt;/span&gt;
                        &lt;span class="nt"&gt;&amp;lt;wp:comment_author&amp;gt;&lt;/span&gt;Ivan&lt;span class="nt"&gt;&amp;lt;/wp:comment_author&amp;gt;&lt;/span&gt;
                        &lt;span class="nt"&gt;&amp;lt;wp:comment_author_email&amp;gt;&lt;/span&gt;suchy.ivan@gmail.com&lt;span class="nt"&gt;&amp;lt;/wp:comment_author_email&amp;gt;&lt;/span&gt;
                        &lt;span class="nt"&gt;&amp;lt;wp:comment_author_url&amp;gt;&amp;lt;/wp:comment_author_url&amp;gt;&lt;/span&gt;
                        &lt;span class="nt"&gt;&amp;lt;wp:comment_author_IP&amp;gt;&lt;/span&gt;None&lt;span class="nt"&gt;&amp;lt;/wp:comment_author_IP&amp;gt;&lt;/span&gt;
                        &lt;span class="nt"&gt;&amp;lt;wp:comment_date_gmt&amp;gt;&lt;/span&gt;2008-04-09 08:48:53&lt;span class="nt"&gt;&amp;lt;/wp:comment_date_gmt&amp;gt;&lt;/span&gt;
                        &lt;span class="nt"&gt;&amp;lt;wp:comment_content&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;&amp;lt;![&lt;/span&gt;&lt;span class="nx"&gt;CDATA&lt;/span&gt;&lt;span class="err"&gt;[&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="k"&gt;On&lt;/span&gt; &lt;span class="nx"&gt;dev&lt;/span&gt; &lt;span class="nx"&gt;server&lt;/span&gt; &lt;span class="kd"&gt;data&lt;/span&gt; &lt;span class="nx"&gt;is&lt;/span&gt; &lt;span class="n"&gt;stored&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="p"&gt;/&lt;/span&gt;&lt;span class="nx"&gt;tmp&lt;/span&gt; &lt;span class="nx"&gt;folder&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;]]&amp;gt;&lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;/wp:comment_content&amp;gt;&lt;/span&gt;
                        &lt;span class="nt"&gt;&amp;lt;wp:comment_approved&amp;gt;&lt;/span&gt;1&lt;span class="nt"&gt;&amp;lt;/wp:comment_approved&amp;gt;&lt;/span&gt;
                      &lt;span class="nt"&gt;&amp;lt;/wp:comment&amp;gt;&lt;/span&gt;
                    &lt;span class="nt"&gt;&amp;lt;/item&amp;gt;&lt;/span&gt;

                     &lt;span class="nt"&gt;&amp;lt;/channel&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;/rss&amp;gt;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Once we are done with creating the WXR schema we should import it to the disqus site.&lt;/p&gt;
&lt;h2&gt;2.Importing the WXR file to Disqus site.&lt;/h2&gt;
&lt;p&gt;To attain the second part you need to have a disqus account and a disqus site available for you. You can get to know more about creating a disqus site in the linked &lt;a href="http://agiliq.com/blog/2014/11/disqus-and-disqus-sso/"&gt;blogpost&lt;/a&gt; &lt;/p&gt;
&lt;p&gt;Once you are done with the creation of disqus site go to the settings which can be accessible on admin panel. There appears the settings page, click on the discussion on the right top panel. Click "import" tab and there appears the different types of import formats that disqus supports. Select generic(WXR) and click on browse. Upload the disqus.xml file and once the process get completed it shows up if there are any errors in the uploaded file. If there are any errors, the process of importing comments will be kept on hold. If the comments are successfully imported it takes some time to get those comments reflected in your site.&lt;/p&gt;
&lt;p&gt;TIP: The best practice would be to try importing in to test disqus site and once it works perfectly, move towards importing them to the main site.&lt;/p&gt;</description><guid>http://agiliq.com/blog/2015/01/importing-your-old-comments-to-disqus-site/</guid></item><item><title>Building a RESTful API with Django-rest-framework</title><link>http://agiliq.com/blog/2014/12/building-a-restful-api-with-django-rest-framework/</link><description>&lt;p&gt;API's turned to be the heart of every application in our time. With the rise of social media, API's are being developed at a faster pace and gaining a lot of attention. Gone are the days where RPC architectures like CORBA and XML-RPC are used to enable the exchange of information and REST has taken its place making its mark in getting the things pretty straight forward.&lt;/p&gt;
&lt;p&gt;We use APIs in our everyday life. Take an instance booking a ticket for a movie through some website. Here is the process that takes place in the background. When dealing with the payment for the ticket, the website connects to the bank and sends your credit card details to the remote application and it gets verified. And once, the payment is confirmed by the remote application, it sends a confirmation response to the movie booking website to issue the tickets. The payment stuff turned possible here as the bank facilitates an API through which a website can connect to it and deal with the payments which resulted us an effective and seamless transaction.&lt;/p&gt;
&lt;p&gt;In this post we will get to know how to build a Restful API for an application using a Django-rest-framework. Before dipping ourselves in the API building stuff, let us acquire a picture on REST.&lt;/p&gt;
&lt;h2&gt;REST&lt;/h2&gt;
&lt;p&gt;In simple words REST is a web architecture which lives on top of HTTP. It's a way in which we should use HTTP where it acts as a set of guiding principles behind the given application. It allows the clients and servers to communicate with each other in all the possible ways like getting the resource, posting the resource, deleting etc. REST is a resource based on which we use an HTTP verb to dictate what operation we want to do on a URI which can be GET, POST and so on. In REST we represent the resource data in JSON and XML format. An API is called a Restful API if it adheres to all the interaction constraints of REST.&lt;/p&gt;
&lt;h2&gt;Django-rest-framework&lt;/h2&gt;
&lt;p&gt;Django-rest-framework makes the process of building web API's simple and flexible. With its batteries included it won't be a tedious task to create an API. Before creating our own API let us look into some vital parts of the REST framework
The important parts of Django-rest-framework are:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Serialization and Deserialization: 
The first part in the process of building an API is to provide a way to serialize and deserialize the instances into representations. Serialization is the process of making a streamable representation of the data which will help in the data transfer over the network. Deserialization is its reverse process. In our process of building an API we render data into JSON format. To achieve this Django-rest-framework provides JSONRenderer and JSONParser. 
JSONRenderer renders the request data into JSON, using utf-8 encoding and JSONParser parses the JSON request content.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Without dipping inside the technicalities let us see how it takes place.&lt;/p&gt;
&lt;p&gt;Serializing data with JSONRenderer:&lt;/p&gt;
&lt;p&gt;A JSONRenderer converts the request data into JSON using utf-8 encoding. Normally we use this when we want our data to be streamable.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;cal_id&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;u&lt;/span&gt;&lt;span class="sc"&gt;&amp;#39;2&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;username&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;u&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;tester&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;content&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;JSONRenderer&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="n"&gt;render&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;content&lt;/span&gt;
&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;cal_id&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;2&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;username&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;tester&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Deserializing data with JSONParser:&lt;/p&gt;
&lt;p&gt;A JSONParser parses the JSON request content. Firstly, we parse a stream into Python native datatypes with BytesIO and then we will restore those native datatypes into to a fully populated object instance afterwards. We use JSONParser to desrialize the data.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;content&lt;/span&gt;
&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;cal_id&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;2&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;username&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;tester&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;stream&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;BytesIO&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;content&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;JSONParser&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="n"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;stream&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;u&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;username&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;u&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;tester&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;u&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;cal_id&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;u&lt;/span&gt;&lt;span class="sc"&gt;&amp;#39;2&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;ul&gt;
&lt;li&gt;Requests and Responses&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Requests and responses are the essential parts of Django-rest-framework which provides flexibility while parsing.&lt;/p&gt;
&lt;p&gt;Request objects:&lt;/p&gt;
&lt;p&gt;The request object in REST framework has more abilities. The attribute request.DATA in Request object is similar to Request.POST added with the capabilities of handling arbitrary data which works for 'POST', 'PUT' and 'PATCH' methods. And also we can use the different attributes like request.FILES, request.QUERY_PARAMS, request.parsers, request.stream which will help in dealing with the request a hassle free task.&lt;/p&gt;
&lt;p&gt;Response objects:&lt;/p&gt;
&lt;p&gt;The Response object helps to render the correct content type as requested by the client unlike the normal HttpResponse.&lt;/p&gt;
&lt;p&gt;Syntax: Response(data, status=None, template_name=None, headers=None, content_type=None)&lt;/p&gt;
&lt;p&gt;Status Codes: 
Instead of using the normal HTTP status codes, we will make use of explicit identifiers for every status code to make the process of reading the status code much simple. Here are some status codes that we represent in a REST framework we use normally.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;HTTP_200_OK&lt;/span&gt;
&lt;span class="n"&gt;HTTP_201_CREATED&lt;/span&gt;
&lt;span class="n"&gt;HTTP_400_BAD_REQUEST&lt;/span&gt;
&lt;span class="n"&gt;HTTP_401_UNAUTHORIZED&lt;/span&gt;
&lt;span class="n"&gt;HTTP_403_FORBIDDEN&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;ul&gt;
&lt;li&gt;Views:
APIView is a view provided by Django-rest-framework which subclasses the Django's view class. If we use this view the requests passed to the handler methods will no more Django's HttpRequest instances and they will be REST framework's Request instances.
And while dealing with the responses they work to set the correct renderer on the response. The process of authentication and the permissions stuff also will be dealt with it.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Creating an API with Django-rest-framework&lt;/h2&gt;
&lt;p&gt;Using all the above stuff lets us build a simple API which gives the details of a user. The procedure goes the following way:&lt;/p&gt;
&lt;p&gt;We will be using Django's built in user in this example. We will create a serializers.py file where we create serializers which are similar to Django forms. Just like model forms we have got model serializers here, which will stop replication of code. And we create a view which lists all the users, creates a new user, retrieve a user and update a user.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Here we go with the installation with virtual environment activated:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;pip&lt;/span&gt; &lt;span class="n"&gt;install&lt;/span&gt; &lt;span class="n"&gt;djangorestframework&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Create a Django project and an app. I created it with a name rest_example and restapp&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;django&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;admin&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;py&lt;/span&gt; &lt;span class="n"&gt;startproject&lt;/span&gt; &lt;span class="n"&gt;rest_example&lt;/span&gt;
&lt;span class="n"&gt;cd&lt;/span&gt; &lt;span class="n"&gt;rest_example&lt;/span&gt;
&lt;span class="n"&gt;python&lt;/span&gt; &lt;span class="n"&gt;manage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;py&lt;/span&gt; &lt;span class="n"&gt;startapp&lt;/span&gt; &lt;span class="n"&gt;restapp&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Add rest_framework and the app name to the installed apps. &lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;INSTALLED_APPS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;...&lt;/span&gt;
    &lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;rest_framework&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;restapp&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Run syncdb command&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;python&lt;/span&gt; &lt;span class="n"&gt;manage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;py&lt;/span&gt; &lt;span class="n"&gt;syncdb&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Create a restapp/serializers.py which should look like the below way.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;from&lt;/span&gt; &lt;span class="n"&gt;django&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;contrib&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;auth&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;models&lt;/span&gt; &lt;span class="n"&gt;import&lt;/span&gt; &lt;span class="n"&gt;User&lt;/span&gt;

&lt;span class="n"&gt;from&lt;/span&gt; &lt;span class="n"&gt;rest_framework&lt;/span&gt; &lt;span class="n"&gt;import&lt;/span&gt; &lt;span class="n"&gt;serializers&lt;/span&gt;

&lt;span class="n"&gt;class&lt;/span&gt; &lt;span class="n"&gt;UserSerializer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;serializers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ModelSerializer&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;class&lt;/span&gt; &lt;span class="n"&gt;Meta&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;model&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;User&lt;/span&gt;
        &lt;span class="n"&gt;fields&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;username&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;first_name&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;last_name&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Create a restapp/views.py file for listing all users, creating a new user and so on.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;from&lt;/span&gt; &lt;span class="n"&gt;django&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;contrib&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;auth&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;models&lt;/span&gt; &lt;span class="n"&gt;import&lt;/span&gt; &lt;span class="n"&gt;User&lt;/span&gt;
&lt;span class="n"&gt;from&lt;/span&gt; &lt;span class="n"&gt;django&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;http&lt;/span&gt; &lt;span class="n"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Http404&lt;/span&gt;

&lt;span class="n"&gt;from&lt;/span&gt; &lt;span class="n"&gt;restapp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;serializers&lt;/span&gt; &lt;span class="n"&gt;import&lt;/span&gt; &lt;span class="n"&gt;UserSerializer&lt;/span&gt;
&lt;span class="n"&gt;from&lt;/span&gt; &lt;span class="n"&gt;rest_framework&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;views&lt;/span&gt; &lt;span class="n"&gt;import&lt;/span&gt; &lt;span class="n"&gt;APIView&lt;/span&gt;
&lt;span class="n"&gt;from&lt;/span&gt; &lt;span class="n"&gt;rest_framework&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="n"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Response&lt;/span&gt;
&lt;span class="n"&gt;from&lt;/span&gt; &lt;span class="n"&gt;rest_framework&lt;/span&gt; &lt;span class="n"&gt;import&lt;/span&gt; &lt;span class="n"&gt;status&lt;/span&gt;

&lt;span class="n"&gt;class&lt;/span&gt; &lt;span class="n"&gt;UserList&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;APIView&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
&lt;span class="s"&gt;&amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;
&lt;span class="n"&gt;List&lt;/span&gt; &lt;span class="n"&gt;all&lt;/span&gt; &lt;span class="n"&gt;users&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;or&lt;/span&gt; &lt;span class="n"&gt;create&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="n"&gt;new&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
&lt;span class="s"&gt;&amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;
    &lt;span class="n"&gt;def&lt;/span&gt; &lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;format&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;None&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;users&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;User&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;objects&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;all&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="n"&gt;serializer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;UserSerializer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;users&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;many&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;Response&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;serializer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;def&lt;/span&gt; &lt;span class="n"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;format&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;None&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;serializer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;UserSerializer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DATA&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;serializer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;is_valid&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;serializer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;save&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;Response&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;serializer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;status&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;status&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;HTTP_201_CREATED&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;Response&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;serializer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;errors&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;status&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;status&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;HTTP_400_BAD_REQUEST&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;def&lt;/span&gt; &lt;span class="n"&gt;delete&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;pk&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;format&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;None&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get_object&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pk&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;delete&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;Response&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;status&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;status&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;HTTP_204_NO_CONTENT&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;class&lt;/span&gt; &lt;span class="n"&gt;UserDetail&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;APIView&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
    &lt;span class="s"&gt;&amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;
    &lt;span class="n"&gt;Retrieve&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;update&lt;/span&gt; &lt;span class="n"&gt;or&lt;/span&gt; &lt;span class="n"&gt;delete&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt; &lt;span class="n"&gt;instance&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
    &lt;span class="s"&gt;&amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;
    &lt;span class="n"&gt;def&lt;/span&gt; &lt;span class="n"&gt;get_object&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;pk&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
        &lt;span class="nl"&gt;try:&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;User&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;objects&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pk&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;pk&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;except&lt;/span&gt; &lt;span class="n"&gt;User&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DoesNotExist&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;raise&lt;/span&gt; &lt;span class="n"&gt;Http404&lt;/span&gt;

    &lt;span class="n"&gt;def&lt;/span&gt; &lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;pk&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;format&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;None&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get_object&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pk&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;UserSerializer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;Response&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;def&lt;/span&gt; &lt;span class="n"&gt;put&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;pk&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;format&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;None&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get_object&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pk&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;serializer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;UserSerializer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DATA&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;serializer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;is_valid&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;serializer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;save&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;Response&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;serializer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;Response&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;serializer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;errors&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;status&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;status&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;HTTP_400_BAD_REQUEST&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;def&lt;/span&gt; &lt;span class="n"&gt;delete&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;pk&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;format&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;None&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get_object&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pk&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;delete&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;Response&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;status&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;status&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;HTTP_204_NO_CONTENT&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Update the root urls.py&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="nb"&gt;from&lt;/span&gt; &lt;span class="nx"&gt;django.conf.urls&lt;/span&gt; &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;patterns&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;include&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;url&lt;/span&gt;
&lt;span class="nb"&gt;from&lt;/span&gt; &lt;span class="nx"&gt;django.contrib&lt;/span&gt; &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;admin&lt;/span&gt;

&lt;span class="nb"&gt;from&lt;/span&gt; &lt;span class="nx"&gt;restapp&lt;/span&gt; &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;views&lt;/span&gt;

&lt;span class="nx"&gt;admin.autodiscover&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="n"&gt;urlpatterns&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;patterns&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nb"&gt;url&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;r&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;^admin/&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;include&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;admin.site.urls&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt;
    &lt;span class="nb"&gt;url&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;r&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;^users/&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;views.UserList.as_view&lt;/span&gt;&lt;span class="p"&gt;()),&lt;/span&gt;
    &lt;span class="nb"&gt;url&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;r&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;^users/(?P&amp;lt;pk&amp;gt;[0-9]+)/$&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;views.UserDetail.as_view&lt;/span&gt;&lt;span class="p"&gt;()),)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Voila!! we are done creating our API. &lt;/p&gt;
&lt;p&gt;Let us test our API now.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;python&lt;/span&gt; &lt;span class="n"&gt;manage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;py&lt;/span&gt; &lt;span class="n"&gt;runserver&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Now go to your browser and try localhost:8000/users/1/ or use curl on your command line&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;curl&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="c1"&gt;//127.0.0.1:8000/users/1/&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;You can get the user details what you have filled while creating the super user. which would look like this.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;id&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;username&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;restapp&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;first_name&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;last_name&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;email&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;rakesh@agiliq.com&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Now we can try posting data:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;curl&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;X&lt;/span&gt; &lt;span class="n"&gt;POST&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="c1"&gt;//127.0.0.1:8000/users/ -d &amp;#39;{&amp;quot;username&amp;quot;:&amp;quot;rakhi&amp;quot;, &amp;quot;email&amp;quot;:&amp;quot;rakhi@agiliq.com&amp;quot;}&amp;#39; -H &amp;quot;Content-Type: application/json&amp;quot;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;And it creates a new user with the username "rakhi" and email "rakhi@agiliq.com"&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;    &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;id&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;username&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;rakhi&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;first_name&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;last_name&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;email&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;rakhi@gmail.com&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;You can check out the example application on &lt;a href="https://github.com/krvc/rest_example"&gt;github&lt;/a&gt;&lt;/p&gt;</description><guid>http://agiliq.com/blog/2014/12/building-a-restful-api-with-django-rest-framework/</guid></item><item><title>Disqus and Disqus SSO</title><link>http://agiliq.com/blog/2014/11/disqus-and-disqus-sso/</link><description>&lt;p&gt;Outsourcing the comments and discussions part to a third party widget always helps us to save a lot of effort. When you feel that if it is okay to share your thoughts and discussions with someone out there who serves the capabilities of social integration and spam detection won't it be a cake walk?&lt;/p&gt;
&lt;p&gt;Disqus is such a kind of blog comment hosting service which is platform-agnostic and URL-agnostic. It is built with javascript and backend technology, Python using Django. Let us get to know how to add this to our Django app.&lt;/p&gt;
&lt;p&gt;Adding Disqus widget to a site is pretty straight forward and effortless. Here are the steps to follow:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Create an account on Disqus and fill the details at https://disqus.com/admin/create/&lt;/li&gt;
&lt;li&gt;Once you finish registration, access the universal code&lt;/li&gt;
&lt;li&gt;In the next following page, get the script and use it wherever we want to display comments&lt;/li&gt;
&lt;li&gt;Update the settings file with DISQUS_SHORTNAME&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The first step includes signing up in to Disqus and getting an account. Once we are done with it, we will be heading to a home page where we can find "Add disqus to your site" on top left. If we click it, we will be redirected to site profile page where we should fill the details like the site name and unique Disqus URL which we call it as "disqus_shortname". Once the registration is completed it will show up the general settings page where we can select the platform i.e univeral code, wordpress, blogger, Tumblr, square space and so on. As we are planning to add Disqus to Django app we should select Universal code. The Universal code is a script which looks like this:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;disqus_thread&amp;quot;&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;script&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;text/javascript&amp;quot;&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    /* * * CONFIGURATION VARIABLES: EDIT BEFORE PASTING INTO YOUR WEBPAGE * * */
    var disqus_shortname = &amp;#39;try1&amp;#39;; // required: replace example with your forum shortname

    /* * * DON&amp;#39;T EDIT BELOW THIS LINE * * */
    (function() {
        var dsq = document.createElement(&amp;#39;script&amp;#39;); dsq.type = &amp;#39;text/javascript&amp;#39;; dsq.async = true;
        dsq.src = &amp;#39;//&amp;#39; + disqus_shortname + &amp;#39;.disqus.com/embed.js&amp;#39;;
        (document.getElementsByTagName(&amp;#39;head&amp;#39;)&lt;span class="cp"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="cp"&gt;]&lt;/span&gt; || document.getElementsByTagName(&amp;#39;body&amp;#39;)&lt;span class="cp"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="cp"&gt;]&lt;/span&gt;).appendChild(dsq);
    })();
&lt;span class="nt"&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;noscript&amp;gt;&lt;/span&gt;Please enable JavaScript to view the &lt;span class="nt"&gt;&amp;lt;a&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;http://disqus.com/?ref_noscript&amp;quot;&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;comments powered by Disqus.&lt;span class="nt"&gt;&amp;lt;/a&amp;gt;&amp;lt;/noscript&amp;gt;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;The script can be used in the template wherever we want our comments section to show up. That delivers us the comments section in our app with one step remaining. Access the "disqus_shortname" i.e. the unique Disqus URL that we specified in the process of registration and add it in the settings file of the Django app.&lt;/p&gt;
&lt;p&gt;eg.
    DISQUS_WEBSITE_SHORTNAME = "mydjangoapp"&lt;/p&gt;
&lt;h2&gt;Disqus SSO&lt;/h2&gt;
&lt;p&gt;Commenting on a thread requires a person to log in with their social accounts. It would be an extra step for the people to log in again for commenting after logging in to the app. To abate this fatigue of logging in again we can use the "single sign on".&lt;/p&gt;
&lt;p&gt;As of now SSO is available to Disqus as a free add on. To add to our app we should request the support team of Disqus through a contact form. Once we send a request to support team it takes like 24 hours to get the access to SSO console.&lt;/p&gt;
&lt;p&gt;Steps to register Disqus application&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Register the application at https://disqus.com/api/applications/register/&lt;/li&gt;
&lt;li&gt;Once the registration is completed the secret keys and the public keys can be accessed at https://disqus.com/api/applications/&lt;/li&gt;
&lt;li&gt;Add the keys to settings file as DISQUS_PUBLIC_KEY and DISQUS_SECRET_KEY&lt;/li&gt;
&lt;li&gt;To avail console, SSO and stuff we can go to https://disqus.com/api/applications/&lt;/li&gt;
&lt;li&gt;Pass existing user data&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The first part to start using it is creating a Remote Domain which can be used as a reference between Disqus and the user accounts. We can do it right away at https://disqus.com/api/sso/. Add the public key and secret key of the application in the settings. We can access the keys at https://disqus.com/api/applications/ under the app name. Use HMAC-SHA1 to pass the user details to the Disqus to authenticate. The message that we pass should contain id, username and email. We can generate the HMAC-SHA1 the following way:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;HMAC&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;SHA1&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;secret_key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;message&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="sc"&gt;&amp;#39; &amp;#39;&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;timestamp&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Once the message is generated the following script need to be used in the page where we want the Disqus to show up.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="n"&gt;disqus_config&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;function&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; 
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// The generated payload which authenticates users with Disqus&lt;/span&gt;
    &lt;span class="n"&gt;this.page.remote_auth_s3&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;&amp;lt;message&amp;gt; &amp;lt;hmac&amp;gt; &amp;lt;timestamp&amp;gt;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;this.page.api_key&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;public_api_key&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;In Django we can accomplish this by registering a simple tag with function to generate the HMAC-SHA1 and using that tag in the template where we are displaying the Disqus comments. The flow moves on the following way:&lt;/p&gt;
&lt;p&gt;Firstly, we should access the value of the DISQUS_SECRET key from the settings. In the next step we should create a json packet of the data attributes, i.e 'id', 'username', 'email'. Then we should encode the json packet to base64 and we should generate a time stamp for signing the message. To pass the secret key and the user details we should generate the HMAC signature. Thus acquired HMAC signature should be returned as a script tag to insert the SSO message. At the end the function appears as in the following code. Check out the &lt;a href="https://gist.github.com/krvc/9afc17db9eb8d01b7655"&gt;Disqus SSO Example&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;The template tag should be used in the place where we want the Disqus comments to appear. &lt;/p&gt;
&lt;p&gt;And that ends up the process of adding SSO to Disqus.&lt;/p&gt;</description><guid>http://agiliq.com/blog/2014/11/disqus-and-disqus-sso/</guid></item><item><title>Travis and coveralls for private repo</title><link>http://agiliq.com/blog/2014/08/travis-and-coveralls-for-private-repo/</link><description>&lt;p&gt;Before we begin, i recommend you to read this first &lt;a href="https://agiliq.com/blog/2014/05/continuous-integration-with-travis-and-coverallsio/"&gt;Continous integration with travis and coveralls.io for Django apps&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Here is how &lt;code&gt;.travis.yml&lt;/code&gt; example file looks like:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;language&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;python&lt;/span&gt;
&lt;span class="n"&gt;python&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
  &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mf"&gt;2.7&lt;/span&gt;
&lt;span class="n"&gt;install&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
  &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;pip&lt;/span&gt; &lt;span class="n"&gt;install&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="n"&gt;requirements&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;txt&lt;/span&gt;
  &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;pip&lt;/span&gt; &lt;span class="n"&gt;install&lt;/span&gt; &lt;span class="n"&gt;coveralls&lt;/span&gt;
&lt;span class="n"&gt;script&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
  &lt;span class="n"&gt;coverage&lt;/span&gt; &lt;span class="n"&gt;run&lt;/span&gt; &lt;span class="n"&gt;manage&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;py&lt;/span&gt; &lt;span class="n"&gt;test&lt;/span&gt;
&lt;span class="n"&gt;after_success&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
  &lt;span class="n"&gt;coveralls&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Setting up coveralls for private repositories requires you to add just one more file &lt;code&gt;.coveralls.yml&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;1) Create a &lt;code&gt;.coveralls.yml&lt;/code&gt; and make sure it resides in your project's root directory.&lt;/p&gt;
&lt;p&gt;2) Add the following to this file:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;service_name&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;travis&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;pro&lt;/span&gt;
&lt;span class="n"&gt;repo_token&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="o"&gt;****&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;&lt;code&gt;service_name&lt;/code&gt; is to specify where Coveralls should look to find additional information about your builds.&lt;/p&gt;
&lt;p&gt;You can get the &lt;code&gt;repo_token&lt;/code&gt; from your repository's page on Coveralls, if you have the admin privileges. This is to tell which project on Coveralls your project maps to.&lt;/p&gt;
&lt;p&gt;Make sure your &lt;code&gt;repo_token&lt;/code&gt; remains secret and do not add this to your public repository.&lt;/p&gt;
&lt;p&gt;3) Add the file, commit it and make a git push.&lt;/p&gt;
&lt;p&gt;4) If everything is OK you should see some thing like the below in your travis build:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;Submitting&lt;/span&gt; &lt;span class="n"&gt;coverage&lt;/span&gt; &lt;span class="n"&gt;to&lt;/span&gt; &lt;span class="n"&gt;coveralls&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;io&lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;
&lt;span class="n"&gt;Coverage&lt;/span&gt; &lt;span class="n"&gt;submitted&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;
&lt;span class="n"&gt;Job&lt;/span&gt; &lt;span class="err"&gt;#&lt;/span&gt;&lt;span class="mf"&gt;22.1&lt;/span&gt;
&lt;span class="nl"&gt;https:&lt;/span&gt;&lt;span class="c1"&gt;//coveralls.io/jobs/54864565&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Thats it now get a coverage badge from coveralls and add this badge in your repo's README.md.&lt;/p&gt;</description><guid>http://agiliq.com/blog/2014/08/travis-and-coveralls-for-private-repo/</guid></item><item><title>Passing parameters to Django admin action</title><link>http://agiliq.com/blog/2014/08/passing-parameters-to-django-admin-action/</link><description>&lt;p&gt;This post will show how to pass parameters to custom Django admin actions.&lt;/p&gt;
&lt;p&gt;This post assumes that you have an idea of &lt;a href="https://docs.djangoproject.com/en/dev/ref/contrib/admin/actions/" target="_blank"&gt;Django actions.&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Django provides a default admin action which is 'Delete selected rows'. Changelist page for all the models registered with admin has this action available. This action allows to select multiple rows and delete them in a single POST request.&lt;/p&gt;
&lt;h3&gt;Problem statement&lt;/h3&gt;
&lt;p&gt;We want to allow following Django action from admin.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;There is a model called &lt;strong&gt;Instrument&lt;/strong&gt;. It has a field &lt;strong&gt;price&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Allow selecting multiple rows for this model and update the value of &lt;code&gt;price&lt;/code&gt; for selected rows.&lt;/li&gt;
&lt;li&gt;Price should not be hardcoded. Admin should be able to enter the price.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;We should be able to achieve something like:&lt;/p&gt;
&lt;p&gt;&lt;img src="http://agiliq.com/dumps/images/20140806/final-action.png" style="width: 443px;"/&gt;&lt;/p&gt;
&lt;h3&gt;Solution&lt;/h3&gt;
&lt;p&gt;Setup the project first.&lt;/p&gt;
&lt;h4&gt;Setup project&lt;/h4&gt;
&lt;p&gt;Start a Django project inside virtual environment&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;tmp&lt;/span&gt; &lt;span class="err"&gt;$&lt;/span&gt; &lt;span class="n"&gt;mkvirtualenv&lt;/span&gt; &lt;span class="n"&gt;custom&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;actions&lt;/span&gt;

&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;custom&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;actions&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;tmp&lt;/span&gt; &lt;span class="err"&gt;$&lt;/span&gt; &lt;span class="n"&gt;django&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;admin&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;py&lt;/span&gt; &lt;span class="n"&gt;startproject&lt;/span&gt; &lt;span class="n"&gt;actions&lt;/span&gt;
&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;custom&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;actions&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;tmp&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;actions&lt;/span&gt; &lt;span class="err"&gt;$&lt;/span&gt; &lt;span class="n"&gt;python&lt;/span&gt; &lt;span class="n"&gt;manage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;py&lt;/span&gt; &lt;span class="n"&gt;startapp&lt;/span&gt; &lt;span class="n"&gt;instruments&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Writing the model in instruments/models.py&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;class&lt;/span&gt; &lt;span class="n"&gt;Instrument&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;models&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Model&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;models&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CharField&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;max_length&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;price&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;models&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;IntegerField&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="n"&gt;def&lt;/span&gt; &lt;span class="n"&gt;__unicode__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Add &lt;strong&gt;instruments&lt;/strong&gt; to INSTALLED_APPS&lt;/p&gt;
&lt;p&gt;Run syncdb&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;custom&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;actions&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;tmp&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;actions&lt;/span&gt; &lt;span class="err"&gt;$&lt;/span&gt; &lt;span class="n"&gt;python&lt;/span&gt; &lt;span class="n"&gt;manage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;py&lt;/span&gt; &lt;span class="n"&gt;syncdb&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Register this model with admin in instruments/admin.py&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;from&lt;/span&gt; &lt;span class="n"&gt;django&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;contrib&lt;/span&gt; &lt;span class="n"&gt;import&lt;/span&gt; &lt;span class="n"&gt;admin&lt;/span&gt;

&lt;span class="n"&gt;from&lt;/span&gt; &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;models&lt;/span&gt; &lt;span class="n"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Instrument&lt;/span&gt;

&lt;span class="n"&gt;admin&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;site&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;register&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Instrument&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;You should be able to see Instrument changelist page at &lt;a href="http://localhost:8000/admin/instruments/instrument/" target="_blank"&gt;http://localhost:8000/admin/instruments/instrument/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Create few instrument instances. You can also use the fixture provided at the &lt;a href="https://github.com/akshar-raaj/django-custom-actions" target="_blank"&gt;github repo&lt;/a&gt; accompanying this blog.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;python&lt;/span&gt; &lt;span class="n"&gt;manage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;py&lt;/span&gt; &lt;span class="n"&gt;loaddata&lt;/span&gt; &lt;span class="n"&gt;instruments&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;fixtures&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;instruments&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;json&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;You should be able to see Action &lt;strong&gt;Delete selected instruments&lt;/strong&gt; in dropdown of Instrument changelist page.&lt;/p&gt;
&lt;p&gt;&lt;img src="http://agiliq.com/dumps/images/20140806/delete-selected.png" alt="Default delete selected instruments" style="width: 443px;"/&gt;&lt;/p&gt;
&lt;h4&gt;Writing our custom action.&lt;/h4&gt;
&lt;p&gt;We want to pass a parameter which will be used to set price on selected rows. This requires showing a Form field.&lt;/p&gt;
&lt;p&gt;When we &lt;a href="https://docs.djangoproject.com/en/dev/ref/contrib/admin/" target="_blank"&gt;customize the admin &lt;/a&gt;, like adding list_display, list_filter, inlines etc, we write a class which extends from ModelAdmin. ModelAdmin has an attribute called &lt;strong&gt;action_form&lt;/strong&gt; which determines the form that gets used for action selection dropdown.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;See&lt;/span&gt; &lt;span class="n"&gt;https&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="c1"&gt;//github.com/django/django/blob/1.6/django/contrib/admin/options.py#L396&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;action_form is django.contrib.admin.helpers.ActionForm.&lt;/p&gt;
&lt;p&gt;Instead of using Django provided &lt;strong&gt;ActionForm&lt;/strong&gt;, we will use a custom form. This form should extend from Django provided ActionForm because we want to retain the functionality provided by Django while adding an additional field of our own.&lt;/p&gt;
&lt;p&gt;This form would be:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;from&lt;/span&gt; &lt;span class="n"&gt;django&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;contrib&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;admin&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;helpers&lt;/span&gt; &lt;span class="n"&gt;import&lt;/span&gt; &lt;span class="n"&gt;ActionForm&lt;/span&gt;

&lt;span class="n"&gt;class&lt;/span&gt; &lt;span class="n"&gt;UpdateActionForm&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ActionForm&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;price&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;forms&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;IntegerField&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Django provides a default action 'Delete selected' and this same form would be used for the default action too. So, we should be keeping the &lt;strong&gt;price&lt;/strong&gt; field as optional so 'Delete selected' functionality keeps working even if we don't input anything in &lt;strong&gt;price&lt;/strong&gt; field.&lt;/p&gt;
&lt;p&gt;And we should be setting this form as &lt;strong&gt;action_form&lt;/strong&gt; attribute of our ModelAdmin subclass.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;class&lt;/span&gt; &lt;span class="n"&gt;InstrumentAdmin&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;admin&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ModelAdmin&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;action_form&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;UpdateActionForm&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;And this InstrumentAdmin should be used while registering model Instrument with admin.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;admin&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;site&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;register&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Instrument&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;InstrumentAdmin&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Final content of instrument/admin.py becomes&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;from&lt;/span&gt; &lt;span class="n"&gt;django&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;contrib&lt;/span&gt; &lt;span class="n"&gt;import&lt;/span&gt; &lt;span class="n"&gt;admin&lt;/span&gt;
&lt;span class="n"&gt;from&lt;/span&gt; &lt;span class="n"&gt;django&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;contrib&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;admin&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;helpers&lt;/span&gt; &lt;span class="n"&gt;import&lt;/span&gt; &lt;span class="n"&gt;ActionForm&lt;/span&gt;
&lt;span class="n"&gt;from&lt;/span&gt; &lt;span class="n"&gt;django&lt;/span&gt; &lt;span class="n"&gt;import&lt;/span&gt; &lt;span class="n"&gt;forms&lt;/span&gt;

&lt;span class="n"&gt;from&lt;/span&gt; &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;models&lt;/span&gt; &lt;span class="n"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Instrument&lt;/span&gt;

&lt;span class="n"&gt;class&lt;/span&gt; &lt;span class="n"&gt;UpdateActionForm&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ActionForm&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;price&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;forms&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;IntegerField&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;required&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;False&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;class&lt;/span&gt; &lt;span class="n"&gt;InstrumentAdmin&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;admin&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ModelAdmin&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;action_form&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;UpdateActionForm&lt;/span&gt;

&lt;span class="n"&gt;admin&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;site&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;register&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Instrument&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;InstrumentAdmin&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;With this your action form would contain a &lt;strong&gt;Price&lt;/strong&gt; field. Verify it on Instrument changelist page.&lt;/p&gt;
&lt;p&gt;&lt;img src="http://agiliq.com/dumps/images/20140806/added-price-field.png" style="width: 443px;"/&gt;&lt;/p&gt;
&lt;p&gt;Confirm that you are still able to delete rows using 'Delete selected instruments' action without the Price fields interfering with the existing functionality.&lt;/p&gt;
&lt;p&gt;If you have written Django actions earlier, writing the function to handle our action should be a no brainer.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;def&lt;/span&gt; &lt;span class="n"&gt;update_price&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;modeladmin&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;queryset&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;price&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;POST&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;price&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="n"&gt;price&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;price&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;queryset&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;update&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;price&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;price&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;update_price&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;short_description&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;Update&lt;/span&gt; &lt;span class="n"&gt;price&lt;/span&gt; &lt;span class="n"&gt;of&lt;/span&gt; &lt;span class="n"&gt;selected&lt;/span&gt; &lt;span class="n"&gt;rows&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;And add it as &lt;strong&gt;actions&lt;/strong&gt; of InstrumentAdmin.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;class&lt;/span&gt; &lt;span class="n"&gt;InstrumentAdmin&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;admin&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ModelAdmin&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;action_form&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;UpdateActionForm&lt;/span&gt;
    &lt;span class="n"&gt;actions&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;update_price&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;With this you should get 'Update price of selected rows' in actions dropdown.&lt;/p&gt;
&lt;p&gt;&lt;img src="http://agiliq.com/dumps/images/20140806/update-price-in-dropdown.png" style="width: 443px;"/&gt;&lt;/p&gt;
&lt;p&gt;You might argue, why did we use request.POST to get the price and not use action_form.cleaned_data. Have some patience, I will answer that.&lt;/p&gt;
&lt;p&gt;Now try selecting some rows and input a price in the form and verify if your code works properly. It must work.&lt;/p&gt;
&lt;p&gt;&lt;img src="http://agiliq.com/dumps/images/20140806/input-update-price.png" style="width: 443px;"/&gt;&lt;/p&gt;
&lt;p&gt;We used request.POST and not action_form.cleaned_data because we don't have access to the instance of action_form, i.e instance of UpdateActionForm, in any way inside function update_price. If we try modeladmin.action_form, it will return us class UpdateActionForm and not instance of UpdateActionForm&lt;/p&gt;
&lt;p&gt;We can make update_price better by showing a message after the instances' price has been updated.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;def&lt;/span&gt; &lt;span class="n"&gt;update_price&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;modeladmin&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;queryset&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;price&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;POST&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;price&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="n"&gt;price&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;price&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;queryset&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;update&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;price&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;price&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;modeladmin&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;message_user&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Successfully updated price for %d rows&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;queryset&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;count&lt;/span&gt;&lt;span class="p"&gt;(),),&lt;/span&gt; &lt;span class="n"&gt;messages&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SUCCESS&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;For message to display, Django message framework should be enabled. It is enabled by default, so unless you have played with settings.py, message will just work.&lt;/p&gt;</description><guid>http://agiliq.com/blog/2014/08/passing-parameters-to-django-admin-action/</guid></item><item><title>Heroku Django S3 for serving Media files</title><link>http://agiliq.com/blog/2014/06/heroku-django-s3-for-serving-media-files/</link><description>&lt;h3&gt;Why should i store my media files on AWS S3?&lt;/h3&gt;
&lt;p&gt;Heroku dynos have limited life span, and when they die and get replaced, the files within them are lost. So you should set up Django media handler to put the files somewhere permanent.&lt;/p&gt;
&lt;h3&gt;Let's begin:&lt;/h3&gt;
&lt;p&gt;1) Install dependencies:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="err"&gt;$&lt;/span&gt; &lt;span class="n"&gt;pip&lt;/span&gt; &lt;span class="n"&gt;install&lt;/span&gt; &lt;span class="n"&gt;django&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;storages&lt;/span&gt; &lt;span class="n"&gt;boto&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;(Update your &lt;code&gt;requirements.txt using &lt;code&gt;pip freeze &amp;gt; requirements.txt&lt;/code&gt;)&lt;/p&gt;
&lt;p&gt;2) Update &lt;code&gt;INSTALLED_APPS&lt;/code&gt; in your settings.py:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;INSTALLED_APPS&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;storages&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;3) Sign in to &lt;a href="http://aws.amazon.com/console/"&gt;AWS Console&lt;/a&gt;, select &lt;code&gt;S3&lt;/code&gt; under &lt;code&gt;Storage &amp;amp; Content Delivery&lt;/code&gt; and create a bucket.&lt;/p&gt;
&lt;p&gt;4) Don't forget to generate &lt;code&gt;AWS_ACCESS_KEY_ID&lt;/code&gt; and &lt;code&gt;AWS_SECRET_ACCESS_KEY&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;5) Add the below to your settings file:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;AWS_QUERYSTRING_AUTH&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;False&lt;/span&gt;
&lt;span class="n"&gt;AWS_ACCESS_KEY_ID&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;environ&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;AWS_ACCESS_KEY_ID&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="n"&gt;AWS_SECRET_ACCESS_KEY&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;environ&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;AWS_SECRET_ACCESS_KEY&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="n"&gt;AWS_STORAGE_BUCKET_NAME&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;environ&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;S3_BUCKET_NAME&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="n"&gt;MEDIA_URL&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="c1"&gt;//%s.s3.amazonaws.com/your-folder/&amp;#39; % AWS_STORAGE_BUCKET_NAME&lt;/span&gt;
&lt;span class="n"&gt;DEFAULT_FILE_STORAGE&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;storages.backends.s3boto.S3BotoStorage&amp;quot;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Note: You should never expose your &lt;code&gt;AWS_ACCESS_KEY_ID&lt;/code&gt; and &lt;code&gt;AWS_SECRET_ACCESS_KEY&lt;/code&gt; there is some reason why they are called SECRET.&lt;/p&gt;
&lt;p&gt;6) Install &lt;a href="http://docs.aws.amazon.com/cli/latest/userguide/cli-chap-getting-set-up.html"&gt;AWS CLI&lt;/a&gt; on your machine.&lt;/p&gt;
&lt;p&gt;7) Its time to move your files to AWS S3 bucket.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="err"&gt;$&lt;/span&gt; &lt;span class="n"&gt;aws&lt;/span&gt; &lt;span class="n"&gt;s3&lt;/span&gt; &lt;span class="n"&gt;cp&lt;/span&gt; &lt;span class="n"&gt;myfolder&lt;/span&gt; &lt;span class="n"&gt;s3&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="c1"&gt;//mybucket/myfolder --recursive&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;8) After the previous step you can use the following command to view the contents of your bucket.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="err"&gt;$&lt;/span&gt; &lt;span class="n"&gt;aws&lt;/span&gt; &lt;span class="n"&gt;s3&lt;/span&gt; &lt;span class="n"&gt;ls&lt;/span&gt; &lt;span class="n"&gt;s3&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="c1"&gt;//mybucket&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;9) Grant public-read permission to everyone, add the below to your S3 bucket policy.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="s"&gt;&amp;quot;Version&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;2008-10-17&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="s"&gt;&amp;quot;Statement&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="p"&gt;[{&lt;/span&gt;
    &lt;span class="s"&gt;&amp;quot;Sid&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;AllowPublicRead&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="s"&gt;&amp;quot;Effect&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Allow&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="s"&gt;&amp;quot;Principal&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="s"&gt;&amp;quot;AWS&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;*&amp;quot;&lt;/span&gt;
         &lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="s"&gt;&amp;quot;Action&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;s3:GetObject&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
      &lt;span class="s"&gt;&amp;quot;Resource&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;arn:aws:s3:::bucket/*&amp;quot;&lt;/span&gt;
      &lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;You can also grant full access to specific IP addresses check this &lt;a href="http://s3browser.com/working-with-amazon-s3-bucket-policies.php"&gt;Bucket Policies&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Thats it now your django app should be able to serve your media files.If not please check your bucket policy, you can check the url link under S3 Management Console-&amp;gt;Properties.&lt;/p&gt;
&lt;p&gt;Any problem or feedback? feel free to leave your comments below.&lt;/p&gt;</description><guid>http://agiliq.com/blog/2014/06/heroku-django-s3-for-serving-media-files/</guid></item><item><title>Supervisor with Django and Gunicorn</title><link>http://agiliq.com/blog/2014/05/supervisor-with-django-and-gunicorn/</link><description>&lt;p&gt;Supervisor with Django: A starter guide&lt;/p&gt;
&lt;p&gt;This post assumes that you have used gunicorn and know what it does. I will try everything inside a virtual environment and hope you do the same.&lt;/p&gt;
&lt;h4&gt;What is supervisor.&lt;/h4&gt;
&lt;p&gt;Supervisor is a monitoring tool that can monitor your processes. It can restart the process if the process dies or gets killed for some reason.&lt;/p&gt;
&lt;h4&gt;Use of supervisor: Why I started using it.&lt;/h4&gt;
&lt;p&gt;In production, I use gunicorn as web server. I started a gunicorn process as a daemon and logged out from the server. My site ran as expected for few days. All of a sudden, we started getting '502 Bad Gateway' and I had no idea why. I had to ssh to the server to find out what went wrong. After &lt;code&gt;ps aux | grep gunicorn&lt;/code&gt;, I found out gunicorn wasn't running anymore. My gunicorn process died on its own, and I had no idea when and why. Had I used supervisor, supervisor would have been controlling the gunicorn process. It must have recieved a signal when gunicorn died and it would have created a new gunicorn process in such scenario. And my site would have kept running as expected.&lt;/p&gt;
&lt;h5&gt;Other scenario&lt;/h5&gt;
&lt;p&gt;We want to run a process which doesn't allow deamonizing. eg: I wanted to keep &lt;code&gt;celery&lt;/code&gt;, a Python worker, running on the production server. I could not run it in the foreground because I had to logout from the server. I did not find an easy way to run celery as a daemon. Here too, supervisor came handy.&lt;/p&gt;
&lt;h4&gt;Project setup&lt;/h4&gt;
&lt;p&gt;I am setting up a new Django project so you will have proper idea of the path and how to use paths in supervisor configuration file.&lt;/p&gt;
&lt;p&gt;We will use Django 1.6.&lt;/p&gt;
&lt;p&gt;Create a new Django project:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;(PythonEnv)/tmp $ django-admin.py startproject testproj
(PythonEnv)/tmp $ cd testproj/
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Project structure looks like:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;(PythonEnv)/tmp/testproj $ tree
manage.py
testproj
    __init__.py
    settings.py
    urls.py
    wsgi.py
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Run syncdb and runserver. Hereafter, we will run all our commands from directory &lt;strong&gt;/tmp/testproj/&lt;/strong&gt; with &lt;strong&gt;PythonEnv&lt;/strong&gt; activated.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;python manage.py syncdb
python manage.py runserver
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And then access the '/admin/'. You should be able to see django admin.&lt;/p&gt;
&lt;p&gt;Let's use &lt;code&gt;gunicorn&lt;/code&gt; instead of using &lt;code&gt;runserver&lt;/code&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;pip install gunicorn

gunicorn testproj.wsgi:application --bind 127.0.0.1:8000
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Make sure you can still see &lt;code&gt;/admin/&lt;/code&gt;. You will not be able to view static files now, because we aren't using Django development server anymore. Read &lt;a href="http://agiliq.com/blog/2013/08/minimal-nginx-and-gunicorn-configuration-for-djang/"&gt;this post&lt;/a&gt; if you want to know how to serve static files using nginx. Though you don't need to do this now, our motive is not to see static files.&lt;/p&gt;
&lt;p&gt;Let's run gunicorn as a daemon. Also, we will tell gunicorn to use a file to keep track of process id, so that we can use that process id to kill gunicorn whenever we want.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;gunicorn testproj.wsgi:application --bind 127.0.0.1:8000 --pid /tmp/gunicorn.pid --daemon
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The problem with this approach is, gunicorn might die at any moment and you will not know about it immediately. Since we are working on dev environment, it is acceptable but gunicorn dying on a server is not acceptable. Your site will loose too many users/customers.&lt;/p&gt;
&lt;p&gt;Kill this gunicorn process, we will let supervisor handle gunicorn hereafter.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;(PythonEnv)/tmp/testproj $ cat /tmp/gunicorn.pid 
19363
(PythonEnv)/tmp/testproj $ kill -9 19363
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;Using supervisor&lt;/h4&gt;
&lt;p&gt;Let's install supervisor inside our virtual environment.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;(PythonEnv)/tmp/testproj $ pip install supervisor
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;With this, you should have a &lt;code&gt;echo_supervisord_conf&lt;/code&gt; command available. Get a stub supervisor file in your current directory using it.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;echo_supervisord_conf &amp;gt; ./supervisord.conf
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;With this, your directory structure should look like:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;db.sqlite3
manage.py
supervisord.conf
testproj
    __init__.py
    settings.py
    urls.py
    wsgi.py
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You can remove most of the sections of this supervisor configuration file if you want. Initially we can only keep:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;[supervisord]
logfile=/tmp/supervisord.log ; (main log file;default $CWD/supervisord.log)
logfile_maxbytes=50MB        ; (max main logfile bytes b4 rotation;default 50MB)
logfile_backups=10           ; (num of main logfile rotation backups;default 10) 
loglevel=info                ; (log level;default info; others: debug,warn,trace)
pidfile=/tmp/supervisord.pid ; (supervisord pidfile;default supervisord.pid)
nodaemon=true               ; (start in foreground if true;default false)
minfds=1024                  ; (min. avail startup file descriptors;default 1024)
minprocs=200                 ; (min. avail process descriptors;default 200)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;From &lt;a href="http://supervisord.org/running.html"&gt;supervisor docs&lt;/a&gt;:&lt;/p&gt;
&lt;p&gt;Before supervisord will do anything useful for you, you’ll need to add at least one &lt;strong&gt;program&lt;/strong&gt; section to its configuration. The program section will define a program that is run and managed when you invoke the supervisord command. To add a program, you’ll need to edit the supervisord.conf file.&lt;/p&gt;
&lt;p&gt;So, we'll add a &lt;strong&gt;program&lt;/strong&gt; section for gunicorn to supervisord.conf. Add it after the [supervisord] section.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;[program:gunicorn]
command=/home/akshar/.virtualenvs/PythonEnv/bin/gunicorn testproj.wsgi:application --bind 127.0.0.1:8000 --pid /tmp/gunicorn.pid ;
directory=/tmp/testproj/ ;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You need to change &lt;strong&gt;command&lt;/strong&gt; and &lt;strong&gt;directory&lt;/strong&gt; depending on your environment. My gunicorn executable resides at &lt;code&gt;/home/akshar/.virtualenvs/PythonEnv/bin/gunicorn&lt;/code&gt;. Find where your gunicorn executable is and use that in &lt;code&gt;command&lt;/code&gt; section of &lt;code&gt;program&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;We passed &lt;code&gt;testproject.wsgi:application&lt;/code&gt; as application object to gunicorn, so &lt;code&gt;testproject&lt;/code&gt; need to be available on the PATH for this to work. And for something to be available on the path, you need to be in correct directory. That's why we need the &lt;code&gt;directory&lt;/code&gt; setting inside &lt;code&gt;program&lt;/code&gt; section.&lt;/p&gt;
&lt;p&gt;Make sure neither a gunicorn nor a supervisor process exists till here:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;(PythonEnv)/tmp/testproj $ ps aux | grep supervisord
(PythonEnv)/tmp/testproj $ ps aux | grep gunicorn
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Run &lt;code&gt;supervisord&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;(PythonEnv)/tmp/testproj $ supervisord
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now a supervisor process as well as a gunicorn process should be running. Even though you did not explicitly start a gunicorn process, supervisor started gunicorn for you. Verify that supervisor as well as gunicorn process exists. You need to check these on a different terminal, because &lt;code&gt;supervisord&lt;/code&gt; must be running on your first terminal in the foreground, since it wasn't daemonized.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;(PythonEnv)/tmp/testproj $ ps aux | grep supervisord
(PythonEnv)/tmp/testproj $ ps aux | grep gunicorn
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Access &lt;code&gt;http://localhost:8000/admin/&lt;/code&gt; to make sure your site is running fine.&lt;/p&gt;
&lt;p&gt;Kill &lt;code&gt;supervisord&lt;/code&gt; process(Ctrl+c), we will deamonize it now. Change &lt;strong&gt;nodaemon=true&lt;/strong&gt; in your supervisord.conf to &lt;strong&gt;nodaemon=false&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Run supervisord again&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;(PythonEnv)/tmp/testproj $ supervisord
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Supervisor should no more be running in foreground. Verify that you have a gunicorn process running too, gunicorn was started by supervisor.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;(PythonEnv)/tmp/testproj $ ps aux | grep gunicorn
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Also, match the process id given by 'ps aux' with pid shown in /tmp/gunicorn.pid&lt;/p&gt;
&lt;p&gt;Verify that &lt;code&gt;/admin/&lt;/code&gt; is still accessible.&lt;/p&gt;
&lt;h4&gt;Supervisor client&lt;/h4&gt;
&lt;p&gt;Supervisor also provides a client using which you can see currently managed process by this supervisor instance. Add the following sections between &lt;code&gt;supervisord&lt;/code&gt; and &lt;code&gt;program&lt;/code&gt; section.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;[inet_http_server]
port=127.0.0.1:9001   ;

[rpcinterface:supervisor]
supervisor.rpcinterface_factory = supervisor.rpcinterface:make_main_rpcinterface

[supervisorctl]
serverurl=http://127.0.0.1:9001 ;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You need to restart supervisor to see these changes taking effect. Kill the existing supervisor process by checking its id from supervisor pid file. Notice that you have a &lt;code&gt;pidfile&lt;/code&gt; option under your &lt;code&gt;supervisord&lt;/code&gt; section, which tells the file which stores process id of supervisor.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;(PythonEnv)/tmp/testproj $ cat /tmp/supervisord.pid 
9820
(PythonEnv)/tmp/testproj $ kill -9 9820
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This killed the exising supervisor process.&lt;/p&gt;
&lt;p&gt;Also, you need to kill the running gunicorn process. Else supervisor will fail to start another gunicorn process because the current gunicorn process has already occupied port 8000.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;(PythonEnv)/tmp/testproj $ cat /tmp/gunicorn.pid 
9824
(PythonEnv)/tmp/testproj $ kill -9 9824
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Run &lt;code&gt;supervisord&lt;/code&gt; again &lt;/p&gt;
&lt;pre&gt;&lt;code&gt;(PythonEnv)/tmp/testproj $ supervisord
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Again verify that gunicorn process was started by supervisor.&lt;/p&gt;
&lt;p&gt;Start supervisor client by issuing following command:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;(PythonEnv)/tmp/testproj $ supervisorctl
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It should tell you that a process for gunicorn is being managed by supervisor. Output should be something like:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;gunicorn                         RUNNING    pid 9950, uptime 0:01:01
supervisor&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Suppose you made some change in your Django code and you need to restart gunicorn for that change to take effect. You can easily do it from supervisor client.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;supervisor&amp;gt; restart gunicorn
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Output should be:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;gunicorn: stopped
gunicorn: started
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You can verify that the pid of gunicorn changes everytime you restart gunicorn from supervisorctl.&lt;/p&gt;
&lt;p&gt;supervisorctl provides a host of other functionalities too. Use command &lt;code&gt;help&lt;/code&gt; on supervisorctl to know more.&lt;/p&gt;
&lt;h5&gt;Surprise&lt;/h5&gt;
&lt;p&gt;You have a running gunicorn process. Kill it.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;(PythonEnv)/tmp/testproj $ cat /tmp/gunicorn.pid 
10137
(PythonEnv)/tmp/testproj $ kill -9 10137
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now gunicorn should be killed and you should not be able to access &lt;code&gt;/admin/&lt;/code&gt;. But you will be able to access it, try it. Surprised? Check the pid of gunicorn now.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;(PythonEnv)/tmp/testproj $ cat /tmp/gunicorn.pid 
10301
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;So, somehow a new gunicorn process was created as soon as we killed gunicorn, and the process id for that gunicorn process was written in /tmp/gunicorn.pid.&lt;/p&gt;
&lt;h6&gt;Why did it happen.&lt;/h6&gt;
&lt;p&gt;When you killed gunicorn, supervisor came to know that gunicorn process died. And it's supervisor's duty to restart any process if it dies, if supervisor controls that process. Since gunicorn was being controlled by supervisor, supervisor made sure to restart gunicorn. So, be assured that if you are using supervisor and let it control gunicorn, then supervisor will make sure to always keep gunicorn running. And your site will never be down.&lt;/p&gt;
&lt;p&gt;This is how we used supervisor on our development environment. You can similarly use supervisor on a production server.&lt;/p&gt;
&lt;p&gt;It is worth mentioning that supervisor conf can have multiple &lt;code&gt;program&lt;/code&gt; section. So, you can use single supervisor instance to control gunicorn, celery and any other process you want.&lt;/p&gt;</description><guid>http://agiliq.com/blog/2014/05/supervisor-with-django-and-gunicorn/</guid></item><item><title>Continuous integration with travis and coveralls.io for Django apps</title><link>http://agiliq.com/blog/2014/05/continuous-integration-with-travis-and-coverallsio/</link><description>&lt;p&gt;Maintaining a solid rapport with the ongoing software development process always turns out to be a walk on air.
Ensuring a software build integrity and quality in every single commit makes it much more exciting.&lt;/p&gt;
&lt;p&gt;If the current software bulid is constantly available for testing, demo or release isn't it a developer's paradise on earth?&lt;/p&gt;
&lt;p&gt;Giving a cold shoulder to "Integration hell" the 'Continuous integration' process stands out to deliver all the above assets.&lt;/p&gt;
&lt;h2&gt;What's Continuous integration?&lt;/h2&gt;
&lt;p&gt;Continuous integration is a development practice that requires a developer to integrate code into a shared repository in which isolated changes are immediately tested and reported on when they are added to a larger code base.&lt;/p&gt;
&lt;p&gt;Continuous integration (CI) originated from within the extreme programming paradigm, but the principles can be applied to any iterative programming model, such as agile programming. As critics noted several potential drawbacks on extreme programming many organizations have adopted CI without all of the extreme programming concepts.&lt;/p&gt;
&lt;h2&gt;Principles of CI:&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Maintain a single source repository&lt;/li&gt;
&lt;li&gt;Automate the build&lt;/li&gt;
&lt;li&gt;Make the build self-testing&lt;/li&gt;
&lt;li&gt;Keep the build fast&lt;/li&gt;
&lt;li&gt;Everyone can see the results of the latest build&lt;/li&gt;
&lt;li&gt;Automate deployment&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Keywords:&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;Build: All steps necessary to compile and create deliverables.&lt;/li&gt;
&lt;li&gt;Commit: The operation follows the validation of updates to existing code.&lt;/li&gt;
&lt;li&gt;Update: This operation allows the update from the repository of the configuration management tool.&lt;/li&gt;
&lt;li&gt;Checkout: This is the operation to extract a version of a project under development from the repository of the configuration manager.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;Spices for the recipe:&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Use of a version control tool (Git, SVN, etc.)&lt;/li&gt;
&lt;li&gt;An automated build and product release process.&lt;/li&gt;
&lt;li&gt;Instrumentation of the build process to trigger unit and acceptance tests for evey change that is commited&lt;/li&gt;
&lt;li&gt;A notifying process that notifies for every single test fail and alerts the team.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;The approach:&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;The developer makes a commit to the repository&lt;/li&gt;
&lt;li&gt;The integration server detects the commit, makes a checkout, launches operations and testing.&lt;/li&gt;
&lt;li&gt;Eventually the repository may become so different from the developers baseline referred to as "Merge hell"&lt;/li&gt;
&lt;li&gt;In case of a failure in the testing process a notification is generated to the team.&lt;/li&gt;
&lt;li&gt;The developers may discard the changes or fix the bugs to make it progress successfully.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;So this makes us fancy trying out continuous integration. Let's study a CI software now.&lt;/p&gt;
&lt;h2&gt;Travis CI&lt;/h2&gt;
&lt;p&gt;Travis CI is a distributed build system for the open source community. Its a CI service used to build and test projects hosted on Github.&lt;/p&gt;
&lt;p&gt;Travis is configured by adding a file named .travis.yml which is a YAML(a human-readable data serialization format) text file.
It automatically detects when a commit has been made and pushed to a GitHub repository that is using Travis CI, and each time this happens, it will try to build the project and run tests. It also builds and runs pull requests and once it is completed it notifies the developer in the way it is configured.&lt;/p&gt;
&lt;h2&gt;Steps to use Travis CI:&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;Sign-in: To get started with Travis CI we should sign-in to our github account.&lt;/li&gt;
&lt;li&gt;Activate Github webhook: Once the Signup process gets completed we need to enable the service hook in the github profile page.&lt;/li&gt;
&lt;li&gt;Add .travis.yml: We should add the yml file to the project.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;Writing .travis.yml file:&lt;/h2&gt;
&lt;p&gt;In order for Travis CI to build our project we need to tell the system a little bit about it. we will be needed to add a file named .travis.yml to the root of our repository.
The basic options in the .travis.yml should contain are language key which tells which language environment to select for our project and other options include the version of the language and scripts to run the tests, etc.&lt;/p&gt;
&lt;p&gt;Example for travis.yml for python project:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;language: python
python:
  - "2.7"

# command to install dependencies
install:
  - "pip install -r requirements.txt"

# command to run tests
script: python manage.py test
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Explanation:&lt;/p&gt;
&lt;p&gt;In the first line we have specified python as the language environment, the next specifies the version of python. Travis will then make sure that the project runs well with all the python versions. If we have any python dependencies Travis will test our code in a virtualenv, so all we need to write a requirments.txt and tell Travis to install it and the script command will run tests when excited.&lt;/p&gt;
&lt;h2&gt;The complete Lifecycle&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;&lt;code&gt;before_install&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;install&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;after_install&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;before_script&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;script&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;after_script&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;after_success or after_failure&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;Configuring .travis.yml&lt;/h2&gt;
&lt;p&gt;Build only specific branches:&lt;/p&gt;
&lt;p&gt;Per default travis will build once we push to a branch on Github. That behavior can be annoying if we are committing often to development branches. We can restrict which branches Travis is monitoring for changes in the .travis.yml. Either we can blacklist the branches or whitelist them:&lt;/p&gt;
&lt;p&gt;.travis.yml&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# Whitelisting example
branches:
  only:
    - master

# Blacklisting example
branches:
  except:
    - develop
    - feature
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Getting notified with lint errors:&lt;/p&gt;
&lt;p&gt;We can also get notified or make bulid fail if there are any lint errors in the commit. For this we can use the option before-script.
We can create a lint.sh file and we can specify it in the before-script option so that the bulid fails and notifies when lint error occurs.&lt;/p&gt;
&lt;p&gt;.travis.yml&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;before_script:
    -./lint.sh
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Using coveralls with travis CI:&lt;/h2&gt;
&lt;p&gt;Coveralls is web service to help us track our code coverage over time and ensure that all our new code is fully covered.&lt;/p&gt;
&lt;p&gt;Steps to use coveralls:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;First, log in via Github and add your repo on Coveralls website.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Add pip install coveralls to install section of .travis.yml&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Make sure you run your tests with coverage during the build in script part.&lt;/p&gt;
&lt;p&gt;script:
    coverage run --source=yourpackagename setup.py test&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Execute run &lt;code&gt;coveralls&lt;/code&gt; in &lt;code&gt;after_success&lt;/code&gt; section.&lt;/p&gt;
&lt;p&gt;after_success:
    coveralls&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Example:&lt;/p&gt;
&lt;p&gt;travis.yml&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;language: python
python:
  - 2.7
install:
  - pip install -r requirements.txt
  - pip install coveralls
script:
  coverage run --source=moscowdjango,meetup manage.py test
after_success:
  coveralls
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The above code makes custom report for data generated by coverage.py package and sends it to json API of coveralls.io service. All python files in our coverage analysis are posted to this service along with coverage stats&lt;/p&gt;</description><guid>http://agiliq.com/blog/2014/05/continuous-integration-with-travis-and-coverallsio/</guid></item><item><title>Writing styled forms with absolutely minimal HTML (Part-2)</title><link>http://agiliq.com/blog/2014/04/writing-styled-forms-with-absolutely-minimal-html2/</link><description>&lt;p&gt;In the &lt;a href="http://agiliq.com/blog/2014/04/writing-styled-forms-with-absolutely-minimal-html-/"&gt;earlier post&lt;/a&gt; we have cruised through the fundamentals of using crispy forms for writing styled forms with minimal HTML.&lt;/p&gt;
&lt;p&gt;At this time, let us dip into getting a clear understanding on how to customize the crispy forms.&lt;/p&gt;
&lt;p&gt;Before diving into the crux of this post we will become aware with the following key words:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;FormHelper&lt;/li&gt;
&lt;li&gt;Layout&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;FormHelper&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Django-crispy-forms  implements a class called FormHelper to define the form rendering behavior.&lt;/li&gt;
&lt;li&gt;Helpers give us a way to control the form attributes and its layout.&lt;/li&gt;
&lt;li&gt;They control global form rendering behavior.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Layout&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;It is an another powerful class of Django-crispy-forms which allow us to change the way the form fields are rendered.&lt;/li&gt;
&lt;li&gt;This allows us to set the order of the fields, wrap them in divs or other structure, etc.&lt;/li&gt;
&lt;li&gt;Custom output&lt;/li&gt;
&lt;li&gt;Flexible and highly reususable&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In the first place we will get to know how to render a model form and then we will be customizing the divs and fields in the template.&lt;/p&gt;
&lt;h2&gt;Handling ModelForm with a Django-crispy-form.&lt;/h2&gt;
&lt;p&gt;As we know ModelForms render Model fields as HTML, let us do this using the crispy-forms now.&lt;/p&gt;
&lt;p&gt;Now lets render an Address form containing the fields like name, street, landmark and so on...&lt;/p&gt;
&lt;p&gt;The basic form stays the same except that we will be appending a FormHelper class.&lt;/p&gt;
&lt;p&gt;The snippet of forms.py:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;class AddressModelForm(forms.ModelForm):
    def __init__(self, *args, **kwargs):
        super(AddressModelForm, self).__init__(*args, **kwargs)
        self.helper = FormHelper(self)

    class Meta:
        model = Address
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In the above code when the AddressModelForm is called the crispy-forms builds a default layout using form.fields for us, so we don't have to manually list all the fields whatever number of fields it may contain.&lt;/p&gt;
&lt;p&gt;Then creation of the views stays the normal way as we do for a normal model-form like this:&lt;/p&gt;
&lt;p&gt;views.py:
    &lt;code&gt;form = AddressModelForm()&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;In the template we just need to add the crispy form tag and that's it and our mission is accomplished.&lt;/p&gt;
&lt;p&gt;address.html&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;{% load crispy_form_tags %}
{% crispy form %}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That gets us done with handling ModelForm with a Django-crispy-form.&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;Customizing the form&lt;/h2&gt;
&lt;p&gt;Now in the second phase we shall start customizing our form using the powerful classes of crispy-forms -- Layouts and FormHelper.&lt;/p&gt;
&lt;p&gt;In the above example, we could just render the form fields, but we are couldn't able to assign any attributes to the form.&lt;/p&gt;
&lt;p&gt;In the normal scenario we tend to use the form_action and form_method in the template's form attributes, but in the crispy-forms we can do it by specifying them in the form itself. For this we take the help of FormHelper.&lt;/p&gt;
&lt;p&gt;Here is the above example rewritten to get the needed task done:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;The snippet of forms.py:

class AddressModelForm(forms.ModelForm):
    def __init__(self, *args, **kwargs):
        super(AddressModelForm, self).__init__(*args, **kwargs)
        form_method = 'post'
        form_id = 'address-form-id'
        form_show_errors = True
        render_hidden_fields = False
        self.helper = FormHelper(self)

    class Meta:
        model = Address
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Additionally, we have got the capability to add custom helper attributes and Bootstrap Helper attibutes:&lt;/p&gt;
&lt;p&gt;Examples for Bootstrap helper attributes:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;`help_text_inline`
`error_text_inline`
`label_class`
`field_class` and so on..
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Reorder the form fields&lt;/h2&gt;
&lt;p&gt;Now it's time for learning the approach to render the form of a template in the customized way. For this we can use the Layout class.&lt;/p&gt;
&lt;p&gt;With Layout class we can arrange the fields according to the requirement.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;What if we want to reorder the fields? And what if I have 100 such fields?&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Example: forms.py&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;class ExampleFieldForm(forms.Form):
    helper = FormHelper()
    helper.layout = Layout('name', 'email', 'password')
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Power of Layouts:&lt;/h2&gt;
&lt;p&gt;The Power of Layouts becomes much more powerful with layout objects.
Every layout object has an associated template.&lt;/p&gt;
&lt;p&gt;There are three types of layout objects.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Universal layout objects (Div, HTML, Field, Fieldset..)&lt;/li&gt;
&lt;li&gt;Uniform layout objects (ButtonHolder, MultiField)&lt;/li&gt;
&lt;li&gt;Bootstrap layout objects (FormActions, AppendedText, Alert...)&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Using the layout objects will result in tailor made outputs in the relatively simplest way.&lt;/p&gt;
&lt;p&gt;Example:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;class RegistrationForm(forms.Form):
[...]
def __init__(self, *args, **kwargs):
    super(RegistrationForm, self).__init__(*args, **kwargs)
    self.helper = FormHelper()
    self.helper.layout = Layout(
        Fieldset(
            'Registration form',
            'name',
            'Father's name,
            'email',
           ),
        Div(
            'Address',
            'City',
            'pincode'
            css_id = 'coloured_fields'
            ),
        Button(
            Submit('submit', 'Submit'),
        HTML(" {% if success %} &amp;lt;p&amp;gt; Successfully submitted &amp;lt;/p&amp;gt; {% endif %}")
        )
    )
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Explaination:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;The fieldset attribute renders the name, fathers's name, email fields wrapped in a fieldset and the first argument in the fieldset is rendered as a legend for the fieldset.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;The Div attribute wraps the fields Address, city, pincode in a div.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Button takes name and value resulting a beautiful button.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;With HTML attribute we can render HTML content and the context can be accessed from where the form is rendered&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;</description><guid>http://agiliq.com/blog/2014/04/writing-styled-forms-with-absolutely-minimal-html2/</guid></item><item><title>Django backward relationship lookup</title><link>http://agiliq.com/blog/2014/04/django-backward-relationship-lookup/</link><description>&lt;p&gt;I often limit the lookup to fields of the model and forget about backward relations. &lt;/p&gt;
&lt;p&gt;Consider the following relationship:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;class Group(models.Model):
    name = models.CharField(max_length=100)

class Student(models.Model):
    name = models.CharField(max_length=100)
    group = models.ForeignKey(Group)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;A group can have many students.&lt;/p&gt;
&lt;p&gt;We want to get the groups based on certain conditions on model &lt;code&gt;Student&lt;/code&gt;. An example is getting the groups which contain a student named 'stud1'. If you can get it using model &lt;code&gt;Group&lt;/code&gt; and without using &lt;code&gt;Student&lt;/code&gt;, you can skip this post.&lt;/p&gt;
&lt;p&gt;In such a scenario, we tend to use &lt;code&gt;Student&lt;/code&gt; model. It's more intuitive because the Foreign Key relationship exists from Student to Group.&lt;/p&gt;
&lt;p&gt;Let's load the following data to test our queries:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;group1 = Group.objects.create(name='Group 1')
group1 = Group.objects.create(name='Group 2')
Student.objects.create(name='stud1', group=group1)
Student.objects.create(name='stud2', group=group1)
Student.objects.create(name='stud3', group=group1)
Student.objects.create(name='stud1', group=group2)
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Get the groups which contain student named &lt;code&gt;stud1&lt;/code&gt;.&lt;/h3&gt;
&lt;h4&gt;Intuitive way:&lt;/h4&gt;
&lt;p&gt;We first try to get all the students which satisfy the criteria. Query for that would be:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Student.objects.filter(name='stud1')
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And then we try to get the groups of those students. If we use the &lt;code&gt;Student&lt;/code&gt; model, we can't get a queryset of &lt;code&gt;Group&lt;/code&gt;. So our approach would be to first get the ids of desired groups and then get a queryset of Group using those ids.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;group_ids = Student.objects.filter(name='stud1').values_list('group', flat=True)
groups = Group.objects.filter(id__in=group_ids)
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;Less obvious way:&lt;/h4&gt;
&lt;p&gt;What if we could use the &lt;code&gt;Group&lt;/code&gt; model directly?&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Group.objects.filter(student__name='stud1')
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This gives the exact same result as given by the &lt;em&gt;Intuitive way&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;So, even though there is no field called &lt;code&gt;student&lt;/code&gt; on &lt;code&gt;Group&lt;/code&gt; and we didn't specify any relationship to Student from Group, Django is smart enough to figure out the relationship for us.&lt;/p&gt;
&lt;h3&gt;Get the groups with name &lt;code&gt;Group1&lt;/code&gt; which contain students named &lt;code&gt;stud1&lt;/code&gt;&lt;/h3&gt;
&lt;h4&gt;Intuitive way:&lt;/h4&gt;
&lt;pre&gt;&lt;code&gt;group_ids = Student.objects.filter(name='stud1', group__name='Group1').values_list('group', flat=True)
groups = Group.objects.filter(id__in=group_ids)
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;Less obvious way:&lt;/h4&gt;
&lt;pre&gt;&lt;code&gt;groups = Group.objects.filter(name='Group1', student__name='stud1')
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Gives the exact same result as given by preceding two queries.&lt;/p&gt;
&lt;p&gt;I always missed the backward relationship while following Django tutorial or whenever I read the docs. I tried finding it while writing this post to see if the docs missed mentioning it. I was wrong yet again, there is a section which mentions it.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;https://docs.djangoproject.com/en/dev/topics/db/queries/#lookups-that-span-relationships
&lt;/code&gt;&lt;/pre&gt;</description><guid>http://agiliq.com/blog/2014/04/django-backward-relationship-lookup/</guid></item><item><title>Writing styled forms with absolutely minimal HTML (Part-1)</title><link>http://agiliq.com/blog/2014/04/writing-styled-forms-with-absolutely-minimal-html-/</link><description>&lt;p&gt;When controlling the form rendering, we all know that we can use the three pre-baked output format
of the forms namely: as_u, as_p and as_table.&lt;/p&gt;
&lt;p&gt;For example: if we use: {{ registration_form.as_ul}}
The output template would be:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;li&amp;gt;
    &amp;lt;label for="id_uname"&amp;gt;Userame:&amp;lt;/label&amp;gt;
    &amp;lt;input type="text" name="username" id="id_uname"&amp;gt;
&amp;lt;li&amp;gt;

&amp;lt;li&amp;gt;
    &amp;lt;label for="id_email"&amp;gt;Email:&amp;lt;/lable&amp;gt;
    &amp;lt;input type="text" name="email" id="id_email"&amp;gt;
&amp;lt;li&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And so on...&lt;/p&gt;
&lt;h2&gt;Here are some questions that come into the picture:&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;What if we to want deal with divs?&lt;/li&gt;
&lt;li&gt;What if we want to reorder the fields? and what if I have 100 such fields?&lt;/li&gt;
&lt;li&gt;And what if I want to deal with model forms? How about field.errors and form.non_field_errors?&lt;/li&gt;
&lt;/ol&gt;
&lt;hr /&gt;
&lt;p&gt;To answer all those significant questions Django-crispy-forms steps into the arena.&lt;/p&gt;
&lt;h2&gt;What are Django-crispy-forms?&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;It's an app that brings up the best way to get the DRY Django forms,
providing the tag and filter that lets us quickly render forms in a div format.
This also provides an enormous amount of capability to configure and control the rendered HTML.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;As an added asset Django-crispy-forms support several frontend frameworks like Twitter Bootstrap(versions- 2 and 3),
Uniform and Foundation.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Using Django-crispy-forms is very simple and effortless.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Let's dive in to learn to use the Django-crispy-forms with Twitter Bootstrap in straightforward 5 steps:&lt;/p&gt;
&lt;p&gt;(We assume that you have set up the minimal Django configuration before following the below steps)&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Step1: Installing using pip.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;pip install django-crispy-forms&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Step-2: Add crispy_forms to the INSTALLED_APPS in settings.py.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;INSTALLED_APPS = (
    ....
    'crispy_forms',
    )&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Step-3: Set up a default template pack in the settings.py for the project (I assume Bootstrap3 here)&lt;/p&gt;
&lt;p&gt;&lt;code&gt;CRISPY_TEMPLATE_PACK = 'bootstrap3'&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Step-4: Create your desired custom form and view.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Eg: forms.py&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;class SimpleForm(forms.Form):
    user_name = forms.CharField(label='Username', required=True)
    ..........
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Eg: views.py&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;class Index1View(FormView):
    template_name = 'crispy_example/index.html'
    form_class = SimpleForm
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;Step-5: Loading crispy forms tag in the template&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In the template, add the below template tags:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;1. {% load crispy_forms_tags %}
2. {% crispy form %}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Add the first tag in the initial part to the template and the second tag in the place where you want to render the form.&lt;/p&gt;
&lt;p&gt;That's all, the above steps results you an impressive bootstrap form.&lt;/p&gt;
&lt;p&gt;You can have a look at the complete example that I have created in github over here: &lt;a href="https://github.com/krvc/crispy_example"&gt;Link&lt;/a&gt;&lt;/p&gt;</description><guid>http://agiliq.com/blog/2014/04/writing-styled-forms-with-absolutely-minimal-html-/</guid></item><item><title>Minimal Nginx and Gunicorn configuration for Django projects</title><link>http://agiliq.com/blog/2013/08/minimal-nginx-and-gunicorn-configuration-for-djang/</link><description>&lt;p&gt;We will see how to deploy a Django project with nginx and gunicorn.&lt;/p&gt;
&lt;p&gt;It was easier for me to understand nginx and gunicorn on development machine and then move to a publicly accessible server. So, we will cover this post in a similar sequence:&lt;/p&gt;
&lt;h4&gt;On development machine&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;Use django's &lt;code&gt;runserver&lt;/code&gt; to serve the site.&lt;/li&gt;
&lt;li&gt;Stop &lt;code&gt;runserver&lt;/code&gt; and start using gunicorn instead.&lt;/li&gt;
&lt;li&gt;Add nginx to this configuration.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;On server&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;Deploy the project on a publicly accessible server using same stack.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;br/&gt;&lt;/p&gt;
&lt;h3&gt;Use runserver&lt;/h3&gt;
&lt;p&gt;We will use a minimal project with two apps and few static files. You can view this project at &lt;a href="https://github.com/akshar-raaj/static-files-in-django" target="_blank"&gt;github&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Project structure:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="o"&gt;|--&lt;/span&gt; &lt;span class="n"&gt;manage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;py&lt;/span&gt;
&lt;span class="o"&gt;|--&lt;/span&gt; &lt;span class="n"&gt;other_app&lt;/span&gt;
&lt;span class="o"&gt;|&lt;/span&gt;   &lt;span class="o"&gt;|--&lt;/span&gt; &lt;span class="n"&gt;__init__&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;py&lt;/span&gt;
&lt;span class="o"&gt;|&lt;/span&gt;   &lt;span class="o"&gt;|--&lt;/span&gt; &lt;span class="n"&gt;models&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;py&lt;/span&gt;
&lt;span class="o"&gt;|&lt;/span&gt;   &lt;span class="o"&gt;|--&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt;
&lt;span class="o"&gt;|&lt;/span&gt;   &lt;span class="o"&gt;|&lt;/span&gt;   &lt;span class="err"&gt;`&lt;/span&gt;&lt;span class="o"&gt;--&lt;/span&gt; &lt;span class="n"&gt;other_app&lt;/span&gt;
&lt;span class="o"&gt;|&lt;/span&gt;   &lt;span class="o"&gt;|&lt;/span&gt;       &lt;span class="err"&gt;`&lt;/span&gt;&lt;span class="o"&gt;--&lt;/span&gt; &lt;span class="n"&gt;styles&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;css&lt;/span&gt;
&lt;span class="o"&gt;|&lt;/span&gt;   &lt;span class="o"&gt;|--&lt;/span&gt; &lt;span class="n"&gt;tests&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;py&lt;/span&gt;
&lt;span class="o"&gt;|&lt;/span&gt;   &lt;span class="o"&gt;|--&lt;/span&gt; &lt;span class="n"&gt;urls&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;py&lt;/span&gt;
&lt;span class="o"&gt;|&lt;/span&gt;   &lt;span class="err"&gt;`&lt;/span&gt;&lt;span class="o"&gt;--&lt;/span&gt; &lt;span class="n"&gt;views&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;py&lt;/span&gt;
&lt;span class="o"&gt;|--&lt;/span&gt; &lt;span class="n"&gt;project_static&lt;/span&gt;
&lt;span class="o"&gt;|&lt;/span&gt;   &lt;span class="err"&gt;`&lt;/span&gt;&lt;span class="o"&gt;--&lt;/span&gt; &lt;span class="n"&gt;base&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;css&lt;/span&gt;
&lt;span class="o"&gt;|--&lt;/span&gt; &lt;span class="n"&gt;requirements&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;txt&lt;/span&gt;
&lt;span class="o"&gt;|--&lt;/span&gt; &lt;span class="n"&gt;some_app&lt;/span&gt;
&lt;span class="o"&gt;|&lt;/span&gt;   &lt;span class="o"&gt;|--&lt;/span&gt; &lt;span class="n"&gt;__init__&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;py&lt;/span&gt;
&lt;span class="o"&gt;|&lt;/span&gt;   &lt;span class="o"&gt;|--&lt;/span&gt; &lt;span class="n"&gt;models&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;py&lt;/span&gt;
&lt;span class="o"&gt;|&lt;/span&gt;   &lt;span class="o"&gt;|--&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt;
&lt;span class="o"&gt;|&lt;/span&gt;   &lt;span class="o"&gt;|&lt;/span&gt;   &lt;span class="err"&gt;`&lt;/span&gt;&lt;span class="o"&gt;--&lt;/span&gt; &lt;span class="n"&gt;some_app&lt;/span&gt;
&lt;span class="o"&gt;|&lt;/span&gt;   &lt;span class="o"&gt;|&lt;/span&gt;       &lt;span class="err"&gt;`&lt;/span&gt;&lt;span class="o"&gt;--&lt;/span&gt; &lt;span class="n"&gt;styles&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;css&lt;/span&gt;
&lt;span class="o"&gt;|&lt;/span&gt;   &lt;span class="o"&gt;|--&lt;/span&gt; &lt;span class="n"&gt;tests&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;py&lt;/span&gt;
&lt;span class="o"&gt;|&lt;/span&gt;   &lt;span class="o"&gt;|--&lt;/span&gt; &lt;span class="n"&gt;urls&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;py&lt;/span&gt;
&lt;span class="o"&gt;|&lt;/span&gt;   &lt;span class="err"&gt;`&lt;/span&gt;&lt;span class="o"&gt;--&lt;/span&gt; &lt;span class="n"&gt;views&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;py&lt;/span&gt;
&lt;span class="o"&gt;|--&lt;/span&gt; &lt;span class="n"&gt;templates&lt;/span&gt;
&lt;span class="o"&gt;|&lt;/span&gt;   &lt;span class="o"&gt;|--&lt;/span&gt; &lt;span class="n"&gt;other_app&lt;/span&gt;
&lt;span class="o"&gt;|&lt;/span&gt;   &lt;span class="o"&gt;|&lt;/span&gt;   &lt;span class="err"&gt;`&lt;/span&gt;&lt;span class="o"&gt;--&lt;/span&gt; &lt;span class="n"&gt;home&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;html&lt;/span&gt;
&lt;span class="o"&gt;|&lt;/span&gt;   &lt;span class="err"&gt;`&lt;/span&gt;&lt;span class="o"&gt;--&lt;/span&gt; &lt;span class="n"&gt;some_app&lt;/span&gt;
&lt;span class="o"&gt;|&lt;/span&gt;       &lt;span class="err"&gt;`&lt;/span&gt;&lt;span class="o"&gt;--&lt;/span&gt; &lt;span class="n"&gt;home&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;html&lt;/span&gt;
&lt;span class="o"&gt;|--&lt;/span&gt; &lt;span class="n"&gt;test&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;db&lt;/span&gt;
&lt;span class="err"&gt;`&lt;/span&gt;&lt;span class="o"&gt;--&lt;/span&gt; &lt;span class="n"&gt;test_project&lt;/span&gt;
    &lt;span class="o"&gt;|--&lt;/span&gt; &lt;span class="n"&gt;__init__&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;py&lt;/span&gt;
    &lt;span class="o"&gt;|--&lt;/span&gt; &lt;span class="n"&gt;settings&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;py&lt;/span&gt;
    &lt;span class="o"&gt;|--&lt;/span&gt; &lt;span class="n"&gt;test_settings&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;py&lt;/span&gt;
    &lt;span class="o"&gt;|--&lt;/span&gt; &lt;span class="n"&gt;urls&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;py&lt;/span&gt;
    &lt;span class="err"&gt;`&lt;/span&gt;&lt;span class="o"&gt;--&lt;/span&gt; &lt;span class="n"&gt;wsgi&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;py&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;This project was started using &lt;strong&gt;django-admin.py startproject test_project&lt;/strong&gt;, so this structure is inside folder &lt;code&gt;test_project&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Cloning and trying it out would help you follow along, &lt;a href="https://github.com/akshar-raaj/static-files-in-django" target="_blank"&gt;so go ahead and clone this project&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Our assumption is that we are working from the same level as &lt;code&gt;manage.py&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Runserver and verify that you can access&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="nl"&gt;http:&lt;/span&gt;&lt;span class="c1"&gt;//localhost:8000/some_app/home&lt;/span&gt;
&lt;span class="nl"&gt;http:&lt;/span&gt;&lt;span class="c1"&gt;//localhost:8000/other_app/home&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;First url should have a red background and the second one should have a blue background. &lt;/p&gt;
&lt;p&gt;This project uses some static resources, you should check our post on &lt;a href="http://agiliq.com/blog/2013/03/serving-static-files-in-django/"&gt;serving static file&lt;/a&gt; if you are confused about serving static files during development.&lt;/p&gt;
&lt;h3&gt;Stop runserver and start using Gunicorn&lt;/h3&gt;
&lt;p&gt;Stop the Django development server.&lt;/p&gt;
&lt;p&gt;Make sure you have gunicorn installed, else install it with &lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;pip&lt;/span&gt; &lt;span class="n"&gt;install&lt;/span&gt; &lt;span class="n"&gt;gunicorn&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Gunicorn is a WSGI compliant server and you need to pass your &lt;strong&gt;application&lt;/strong&gt; object to it. You should read about &lt;a href="http://agiliq.com/blog/2013/07/basics-wsgi/"&gt;Basics of WSGI&lt;/a&gt; if you are not comfortable with wsgi.&lt;/p&gt;
&lt;p&gt;Django provides an &lt;strong&gt;application&lt;/strong&gt; object. The default structure provided by &lt;code&gt;django-admin startproject&lt;/code&gt; gives a &lt;code&gt;wsgi.py&lt;/code&gt; file which contains the &lt;code&gt;application&lt;/code&gt;. You need to pass this &lt;code&gt;application&lt;/code&gt; to gunicorn.&lt;/p&gt;
&lt;p&gt;Run gunicorn passing it the &lt;code&gt;application&lt;/code&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;gunicorn&lt;/span&gt; &lt;span class="n"&gt;test_project&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;wsgi&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;application&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Note: In the recent django versions the wsgi file extension has been changed it is a python module(ex: test_project_wsgi.py) and so you can serve it with just module name like below&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;gunicorn&lt;/span&gt; &lt;span class="n"&gt;test_project&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;application&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Refresh your page at &lt;strong&gt;http://localhost:8000/some_app/home&lt;/strong&gt;. Your page should be served, however the red background must have vanished.&lt;/p&gt;
&lt;p&gt;Red background vanished because the static files(stylesheets) are not being served anymore. They are not being served because we do not have any url pattern for &lt;code&gt;/static/&lt;/code&gt; in urls.py. Earlier they were served because we were using Django development server, i.e runserver, which does some magical things behind the scence to serve static files.&lt;/p&gt;
&lt;h3&gt;Add nginx to this configuration&lt;/h3&gt;
&lt;p&gt;Gunicorn is meant to serve dynamic content, it should not be used to serve static files. We will add nginx to serve static files.&lt;/p&gt;
&lt;p&gt;We want to serve static files from port 8000 and so it is required that gunicorn listens on some different port. Stop gunicorn and run it on port 8001.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;gunicorn&lt;/span&gt; &lt;span class="n"&gt;test_project&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;wsgi&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;application&lt;/span&gt; &lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="n"&gt;bind&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mf"&gt;127.0.0.1&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;8001&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Now you will not be able to see your page at &lt;strong&gt;http://localhost:8000/some_app/home/&lt;/strong&gt;. It will be available on port 8001 at &lt;strong&gt;http://localhost:8001/some_app/home&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Make sure you have nginx installed or install it with:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;sudo&lt;/span&gt; &lt;span class="n"&gt;apt&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt; &lt;span class="n"&gt;install&lt;/span&gt; &lt;span class="n"&gt;nginx&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Nginx acts as a reverse proxy here. All our request will initially come to nginx. It's for nginx to decide what requests it wants to serve and what requests it wants to pass to some other server.&lt;/p&gt;
&lt;p&gt;In our case, we want nginx to serve requests for static resources and to pass any other request to gunicorn.&lt;/p&gt;
&lt;p&gt;We need to tell nginx the location of our static resources and for that we need to make sure all our static resources are at a single location. Run &lt;code&gt;python manage.py collectstatic&lt;/code&gt; to collect all the static resources at location specified by STATIC_ROOT.&lt;/p&gt;
&lt;p&gt;Set STATIC_ROOT in settings.py:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;STATIC_ROOT&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;PROJECT_DIR&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;..&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;staticfiles&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Run collectstatic:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;python&lt;/span&gt; &lt;span class="n"&gt;manage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;py&lt;/span&gt; &lt;span class="n"&gt;collectstatic&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;You should see that a directory &lt;code&gt;staticfiles&lt;/code&gt; gets created at the same level as manage.py. All your static files must have got copied to this directory. Get the path of this directory, we need it in the &lt;code&gt;alias&lt;/code&gt; directive of nginx cofiguration.&lt;/p&gt;
&lt;p&gt;Create a file &lt;code&gt;/etc/nginx/sites-enabled/example&lt;/code&gt; and add following content to it.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;server&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;listen&lt;/span&gt; &lt;span class="n"&gt;localhost&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;8000&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="n"&gt;location&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;proxy_pass&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="c1"&gt;//127.0.0.1:8001;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="n"&gt;location&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="k"&gt;static&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;autoindex&lt;/span&gt; &lt;span class="n"&gt;on&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="n"&gt;alias&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;home&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;akshar&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;staticvirt&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;test_project&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;staticfiles&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Your &lt;code&gt;alias&lt;/code&gt; directive will differ from mine.&lt;/p&gt;
&lt;p&gt;Make sure nginx is running:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;sudo&lt;/span&gt; &lt;span class="n"&gt;service&lt;/span&gt; &lt;span class="n"&gt;nginx&lt;/span&gt; &lt;span class="n"&gt;restart&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Nginx is listening for requests now.&lt;/p&gt;
&lt;p&gt;Refresh page at &lt;code&gt;http://localhost:8000/some_app/home/&lt;/code&gt;, the page should be visible with red background which conforms that static files are being served properly.&lt;/p&gt;
&lt;h4&gt;Explanation:&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;listen&lt;/code&gt; directive tells that nginx is listening for any request that comes at &lt;code&gt;localhost:8000&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;There are two &lt;code&gt;location&lt;/code&gt; directives.&lt;/li&gt;
&lt;li&gt;Bottom &lt;code&gt;location&lt;/code&gt; can overide top &lt;code&gt;location&lt;/code&gt;. Bottom will have preference over top.&lt;/li&gt;
&lt;li&gt;When a request starting with &lt;code&gt;/&lt;/code&gt; comes, its being passed to port 8001.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;eg: If request comes for &lt;code&gt;http://localhost:8000/some_app/home&lt;/code&gt;, nginx tries to match it with one of the &lt;code&gt;location&lt;/code&gt; defined in the configuration file. In this case, it matches with first location. Nginx sees that a &lt;code&gt;proxy_pass&lt;/code&gt; is defined in this case so it passes this request to the proxy_pass which is http://127.0.0.1:8001. Gunicorn is listening at port 8001, so gunicorn will repond to this request.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;When a request starting with &lt;code&gt;/static/&lt;/code&gt; comes, bottom &lt;code&gt;location&lt;/code&gt; is used as it has preference over the top &lt;code&gt;location&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;When a request comes for &lt;code&gt;http://localhost:8000/static/some_app/styles.css&lt;/code&gt;, Nginx looks into the directory pointed to by &lt;code&gt;alias&lt;/code&gt; which is &lt;strong&gt;staticfiles&lt;/strong&gt;. It tries to find &lt;strong&gt;some_app/styles.css&lt;/strong&gt; inside this directory and if this file is available then serves the file.&lt;/p&gt;
&lt;p&gt;Now we are comfortable with serving django sites with nginx and gunicorn.&lt;/p&gt;
&lt;h3&gt;Deploy on a publicly accessible server.&lt;/h3&gt;
&lt;p&gt;I will use domain &lt;code&gt;pythoninternals.com&lt;/code&gt; for illustration. We need to do the following things on the server where A record of domain &lt;code&gt;pythoninternals.com&lt;/code&gt; points.&lt;/p&gt;
&lt;p&gt;We don't need any change for gunicorn and can run it in the same way:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;gunicorn&lt;/span&gt; &lt;span class="n"&gt;test_project&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;wsgi&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;application&lt;/span&gt; &lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="n"&gt;bind&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mf"&gt;127.0.0.1&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;8001&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Create file &lt;code&gt;/etc/nginx/sites-enabled/example&lt;/code&gt; on the server and add content:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;server&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;listen&lt;/span&gt; &lt;span class="mi"&gt;80&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; 
  &lt;span class="n"&gt;server_name&lt;/span&gt; &lt;span class="n"&gt;pythoninternals&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;com&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="n"&gt;location&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; 
    &lt;span class="n"&gt;proxy_pass&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="c1"&gt;//127.0.0.1:8001;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="n"&gt;location&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="k"&gt;static&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;alias&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;home&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;ubuntu&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;staticvirt&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;test_project&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;staticfiles&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;This file is almost similar to the nginx conf we had on development machine.&lt;/p&gt;
&lt;p&gt;Make sure that you have collected the static files in directory &lt;code&gt;staticfiles&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Some differences in this nginx conf and dev machine's nginx conf are:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;It's listening on port 80. When a request is made for domain &lt;code&gt;pythoninternal.com&lt;/code&gt;, it comes on the default port which is 80. So, nginx must be listening for any request on port 80.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;server_name&lt;/code&gt; makes sure that this configuration file will only be used for &lt;code&gt;pythoninternals.com&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;There might be another domain called &lt;code&gt;abcde.com&lt;/code&gt; being served from this same server, we don't want this configuration to be used for &lt;code&gt;abcde.com&lt;/code&gt;. That's why we specify the &lt;code&gt;server_name&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;After this a request for &lt;code&gt;pythoninternals.com/some_app/home&lt;/code&gt; would be served properly from this server.&lt;/p&gt;
&lt;p&gt;Running gunicorn the way we did, will keep it in the foreground and we will have to stop gunicorn to exit from the server. So, we need to run it as a daemon.&lt;/p&gt;
&lt;p&gt;Run gunicorn as daemon:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;gunicorn&lt;/span&gt; &lt;span class="n"&gt;test_project&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;wsgi&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;application&lt;/span&gt; &lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="n"&gt;bind&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mf"&gt;127.0.0.1&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;8001&lt;/span&gt; &lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="n"&gt;daemon&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;With this, gunicorn runs as a background process and we can quit from the server without affecting gunicorn.&lt;/p&gt;
&lt;p&gt;Till now, we have set various configurations for gunicorn, like --bind and --daemon, on the terminal. The suggested way to do it is using configuration file. You can read about it at &lt;a href="http://agiliq.com/blog/2014/06/minimal-gunicorn-configuration/" target="_blank"&gt;another post we wrote&lt;/a&gt; and should move these configurations to a separate file.&lt;/p&gt;</description><guid>http://agiliq.com/blog/2013/08/minimal-nginx-and-gunicorn-configuration-for-djang/</guid></item><item><title>Writing thread-safe django - get_or_create</title><link>http://agiliq.com/blog/2013/08/writing-thread-safe-django-code/</link><description>&lt;p&gt;In this blog post, we'll discuss thread-safety, why it's important and how to
write thread-safe django code, especially for bulk operations like management
commands. We'll take a simple example - get or create.&lt;/p&gt;
&lt;h2&gt;Thread-safety:&lt;/h2&gt;
&lt;p&gt;Thread-safety means that our code can be run in multiple threads and behave as
expected. The reason that code can be unsafe with regard to threads is because
we'll be manipulating shared memory (e.g. database) from the threads and there's
a chance of a race-condition which will produce unexpected results.&lt;/p&gt;
&lt;p&gt;To avoid this, we have the option of using read-write locks, transactions etc.&lt;/p&gt;
&lt;p&gt;We'll look at some simple examples and try to understand these options.&lt;/p&gt;
&lt;h2&gt;The usual way:&lt;/h2&gt;
&lt;p&gt;Let's consider a management command that syncs data from another source (e.g. API,
remote database etc.. The correct way to do this would be to use the built-in
django utility - &lt;code&gt;get_or_create&lt;/code&gt;:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Update&lt;/strong&gt;: Updated the command to run each arg in a thread&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;class MyThread(Thread):

    def __init__(self, my_id):
        super(MyThread, self).__init__(name=my_id)
        self.my_id = my_id

    def run(self):
        instance, created = MyModel.objects.get_or_create(my_id=my_id)
        print '%s %s' % (instance.id, created)
        instance.delete()
        return


class Command(BaseCommand):
    args = '&amp;lt;my_id my_id ...&amp;gt;'
    help = 'Get or create instace of mymodel with my_id'

    def handle(self, *args, **options):
        for my_id in args:
            thread = MyThread(my_id=my_id)
            thread.start()
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In this command, we'll be using the command line arg my_id get a MyModel
instance if it exists, else, we create one.&lt;/p&gt;
&lt;p&gt;Note: we'll be discarding the object for simplicity.&lt;/p&gt;
&lt;p&gt;Now, this management command (let's call it sync_myapp) is thread-safe because
we're just using the built-in &lt;code&gt;get_or_create&lt;/code&gt; to do our database call.&lt;/p&gt;
&lt;p&gt;To test this, run the command with same arg repeated multiple times:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$&amp;gt; python manage.py sync_myapp 1 1 1 1 1
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This will create five threads which will simultaneously try to get or create an instance
with my_id = 1&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$&amp;gt; 1 True
$&amp;gt; 1 False
$&amp;gt; 1 False
$&amp;gt; 1 False
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Note that all the threads are successful, even though they were working on the
same database at the same time.&lt;/p&gt;
&lt;p&gt;Now, even though get_or_create is the way to go, we might need to customize a
few things which are outside the scope of &lt;code&gt;get_or_create&lt;/code&gt;. For example, let's
say we need to do something special just before creating a new instance.&lt;/p&gt;
&lt;h2&gt;The problem:&lt;/h2&gt;
&lt;p&gt;Let's assume our code was:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;def run(self):
    created = False
    try:
        instance = MyModel.objects.get(my_id=my_id)
    except MyModel.DoesNotExist:
        something_special()
        instance = MyModel.objects.create(my_id=my_id)
        created = True
    instance.delete()
    return
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If we try to test it with the above command, you'll probably get:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Exception in thread 1:
Traceback (most recent call last):
....
IntegrityError: duplicate key value violates unique constraint "myapp_mymodel_my_id_key"
DETAIL:  Key (my_id)=(1) already exists.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This indicates that the try except block isn't thread-safe.&lt;/p&gt;
&lt;p&gt;Let's try to fix this problem.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Update&lt;/strong&gt;: I've removed the section dealing with locks since it's only useful when
dealing with shared memory in python processes, it's not applicable to
databases.&lt;/p&gt;
&lt;h2&gt;Using database transactions:&lt;/h2&gt;
&lt;p&gt;We use django's built-in &lt;code&gt;transactions&lt;/code&gt; module as follows:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Update&lt;/strong&gt;: We only need to wrap the create command in a transaction&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;def run(self):
    created = False
    try:
        instance = MyModel.objects.get(my_id=self.my_id)
    except MyModel.DoesNotExist:
            try:
                something_special()
                with transaction.commit_on_success():
                    instance = MyModel.objects.create(my_id=self.my_id)
                created = True
            except IntegrityError:
                instance = MyModel.objects.get(my_id=self.my_id)
    print '%s %s' % (instance.id, created)
    instance.delete()
    return
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now, the transaction will be committed only if there's no error within the
context block, so we can be sure that only one thread gets the go-ahead for
&lt;code&gt;create&lt;/code&gt; call.&lt;/p&gt;
&lt;p&gt;In addition to the context manager, django also has options for using savepoints,
manually commits, rollbacks etc.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://docs.djangoproject.com/en/1.5/topics/db/transactions"&gt;https://docs.djangoproject.com/en/1.5/topics/db/transactions&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;Caveats:&lt;/h2&gt;
&lt;p&gt;If you're using MySQL, refer to this open issue on problem with &lt;code&gt;get_or_create&lt;/code&gt;:&lt;/p&gt;
&lt;p&gt;&lt;a href="https://code.djangoproject.com/ticket/13906"&gt;https://code.djangoproject.com/ticket/13906&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;Conclusion:&lt;/h2&gt;
&lt;p&gt;Using database transactions, we can avoid data integrity issues and write
thread-safe code which can be run in parallel without any
issues.&lt;/p&gt;</description><guid>http://agiliq.com/blog/2013/08/writing-thread-safe-django-code/</guid></item><item><title>Deploying django using docker</title><link>http://agiliq.com/blog/2013/06/deploying-django-using-docker/</link><description>&lt;p&gt;In this blog post we'll take a look at &lt;a href="http://docker.io"&gt;Docker&lt;/a&gt; and
discuss ways to deploy django using docker.&lt;/p&gt;
&lt;h2&gt;About Docker:&lt;/h2&gt;
&lt;p&gt;Docker is a tool that helps you manage lxc containers and images. You can
create an image, launch container from the existing image, attach to a running
container, and generally play around with the containers.&lt;/p&gt;
&lt;p&gt;The most important benefit of using docker and containers in general is that
you have a clean, hygeinic and portable runtime enivorment for your app. This
means you don't have to worry about missing dependecies, packages and other
pain points during subsequent deployments. You can take a snapshot of a running
container and restore it again when required. Plus, each app runs in it's own
isolated container so you can have various versions of libraries and other
dependecies for each app without worrying about it's effect on other apps.
Coming from the python world where virtualenv is ubiqitous, it's a huge relief
to me that there's such a better and cleaner solution.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Note: Docker is still under heavy development. It should not yet be used in
 production. Check the repo for recent progress.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;To know more about docker and install it, go to the &lt;a href="http://www.docker.io/gettingstarted/"&gt;"Getting Started"&lt;/a&gt; guide.&lt;/p&gt;
&lt;p&gt;Here I'll discuss two ways of deploying django using docker:&lt;/p&gt;
&lt;h2&gt;Vanilla deployment:&lt;/h2&gt;
&lt;p&gt;Nothing fancy here, we just instantiate a container image and open up an ssh
port and a web port, then we can use our usual fabfile script to deploy it to
the container. Here I'll use the container image "dhrp/sshd" which I found by
searching &lt;a href="https://index.docker.io/search?q=ssh"&gt;the container index&lt;/a&gt;.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;docker&lt;/span&gt; &lt;span class="n"&gt;pull&lt;/span&gt; &lt;span class="n"&gt;dhrp&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;sshd&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;This will fetch the container image dhrp/sshd&lt;/p&gt;
&lt;p&gt;Now let's run the container &lt;code&gt;-d&lt;/code&gt; for daemonize, &lt;code&gt;-p 22 -p 8000&lt;/code&gt; for telling docker
to open port 22 and 8000, dhrp/sshd is the image we want to use, and &lt;code&gt;/usr/sbin/sshd -D&lt;/code&gt;
is the command we want to run inside the container - here we want to run the sshd daemon&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;docker&lt;/span&gt; &lt;span class="n"&gt;run&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;d&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt; &lt;span class="mi"&gt;22&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt; &lt;span class="mi"&gt;8000&lt;/span&gt; &lt;span class="n"&gt;dhrp&lt;/span&gt;&lt;span class="sr"&gt;/sshd /&lt;/span&gt;&lt;span class="n"&gt;usr&lt;/span&gt;&lt;span class="sr"&gt;/sbin/ss&lt;/span&gt;&lt;span class="n"&gt;hd&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;D&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;c4cee8e86fa0&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;The above command will give an hash by which you can refer to the running
container instance in the future.&lt;/p&gt;
&lt;p&gt;Now you can query for the NATed ports associated with our newly launched
container using:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;docker&lt;/span&gt; &lt;span class="n"&gt;port&lt;/span&gt; &lt;span class="n"&gt;c4cee8e86fa0&lt;/span&gt; &lt;span class="mi"&gt;22&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;49185&lt;/span&gt;

&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;docker&lt;/span&gt; &lt;span class="n"&gt;port&lt;/span&gt; &lt;span class="n"&gt;c4cee8e86fa0&lt;/span&gt; &lt;span class="mi"&gt;8000&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;49186&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;or you can also use the generic &lt;code&gt;docker ps&lt;/code&gt; command for a human readable and
prettier output:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;docker&lt;/span&gt; &lt;span class="n"&gt;ps&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Now, we can ssh into our container through the NATed port - the password for
this container is &lt;code&gt;screencast&lt;/code&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;ssh&lt;/span&gt; &lt;span class="n"&gt;root&lt;/span&gt;&lt;span class="nv"&gt;@localhost&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt; &lt;span class="mi"&gt;49185&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;root&lt;/span&gt;&lt;span class="nv"&gt;@c4cee8e86fa0:&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="c1"&gt;#&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Note that the password - &lt;code&gt;screencast&lt;/code&gt; was set by the container image author.
For better security, you should login, change the password and commit your
changes immediately:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;docker&lt;/span&gt; &lt;span class="n"&gt;commit&lt;/span&gt; &lt;span class="n"&gt;c4cee8e86fa0&lt;/span&gt; &lt;span class="n"&gt;dhrp&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;sshd&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Now, you can use this container just like any other server. You'll just need to
make sure to proxy the NATed web port through nginx. You can update your
fabfile to point to the container by updating the ssh port number and deploy as
usual.&lt;/p&gt;
&lt;h2&gt;Heroku-like deployment:&lt;/h2&gt;
&lt;p&gt;A few days back I came across &lt;a href="https://github.com/progrium/dokku"&gt;dokku&lt;/a&gt; and
decided to give it a try by deploying a small django app. You'll need to clone
the dokku repository and use a buildpack like
&lt;a href="https://github.com/jiaaro/heroku-buildpack-django"&gt;heroku-buildpack-django&lt;/a&gt; as described
in the &lt;a href="https://github.com/progrium/buildstep#adding-buildpacks"&gt;dokku docs&lt;/a&gt;. The
django buildpack I found worked quite well, except that it requires python-dev to be installed.
Luckily, it's quite easy to modify the buildstep script to handle this. Once I had this set-up,
I just had to create a tarball of my code and build it:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;cat&lt;/span&gt; &lt;span class="n"&gt;django&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;pastebin&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;tar&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="o"&gt;./&lt;/span&gt;&lt;span class="n"&gt;buildstep&lt;/span&gt; &lt;span class="n"&gt;django&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;pastebin&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;This will build a container from scratch and install all dependecies required
for the buildpack and prepare the container for deployment.&lt;/p&gt;
&lt;p&gt;Here are the repos I've used for this example:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/tuxcanfly/buildstep"&gt;https://github.com/tuxcanfly/buildstep&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/tuxcanfly/heroku-buildpack-django"&gt;https://github.com/tuxcanfly/heroku-buildpack-django&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/agiliq/django-pastebin"&gt;https://github.com/agiliq/django-pastebin&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Verify that it works:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;docker&lt;/span&gt; &lt;span class="n"&gt;run&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt; &lt;span class="mi"&gt;8000&lt;/span&gt; &lt;span class="n"&gt;django&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;pastebin&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;start&lt;/span&gt; &lt;span class="n"&gt;web&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;2013&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mo"&gt;06&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;14&lt;/span&gt; &lt;span class="mi"&gt;13&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;31&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;22&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;9&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;INFO&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="n"&gt;Starting&lt;/span&gt; &lt;span class="n"&gt;gunicorn&lt;/span&gt; &lt;span class="mf"&gt;0.17.4&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;2013&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mo"&gt;06&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;14&lt;/span&gt; &lt;span class="mi"&gt;13&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;31&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;22&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;9&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;INFO&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="n"&gt;Listening&lt;/span&gt; &lt;span class="n"&gt;at:&lt;/span&gt; &lt;span class="n"&gt;http:&lt;/span&gt;&lt;span class="sr"&gt;//&lt;/span&gt;&lt;span class="mf"&gt;127.0.0.1&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;8000&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;9&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;2013&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mo"&gt;06&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;14&lt;/span&gt; &lt;span class="mi"&gt;13&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;31&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;22&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;9&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;INFO&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="n"&gt;Using&lt;/span&gt; &lt;span class="n"&gt;worker:&lt;/span&gt; &lt;span class="n"&gt;sync&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;2013&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mo"&gt;06&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;14&lt;/span&gt; &lt;span class="mi"&gt;13&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;31&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;22&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;14&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;INFO&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="n"&gt;Booting&lt;/span&gt; &lt;span class="n"&gt;worker&lt;/span&gt; &lt;span class="n"&gt;with&lt;/span&gt; &lt;span class="n"&gt;pid:&lt;/span&gt; &lt;span class="mi"&gt;14&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Now, you can daemonize it and let it run in the background:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;docker&lt;/span&gt; &lt;span class="n"&gt;run&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;d&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt; &lt;span class="mi"&gt;8000&lt;/span&gt; &lt;span class="n"&gt;django&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;pastebin&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;start&lt;/span&gt; &lt;span class="n"&gt;web&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="n"&gt;dc243483b56&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;h2&gt;Conclusion:&lt;/h2&gt;
&lt;p&gt;I've found docker and containers very useful in managing multiple apps on a
single server even if it's a little rough around the edges. Tools like
&lt;a href="https://index.docker.io/"&gt;container index&lt;/a&gt; are a great way of sharing
development enviroments and avoid getting bogged down by installation
processes. I'm eagerly looking forward to future versions and upcoming features
in docker.&lt;/p&gt;</description><guid>http://agiliq.com/blog/2013/06/deploying-django-using-docker/</guid></item><item><title>Common testing scenarios for Django app.</title><link>http://agiliq.com/blog/2013/04/common-testing-scenarios-for-django-app/</link><description>&lt;p&gt;People are often confused regarding what tests to write. Let's look into some scenarios for which tests can be written.&lt;/p&gt;
&lt;h2&gt;Setting up the project&lt;/h2&gt;
&lt;p&gt;We start a Django project inside a virtual environment. In this post we would be using django 1.4.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;dj&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;~&lt;/span&gt;&lt;span class="sr"&gt;/play/&lt;/span&gt;&lt;span class="n"&gt;dj&lt;/span&gt;&lt;span class="nv"&gt;$&lt;/span&gt; &lt;span class="nv"&gt;django&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;admin&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;py&lt;/span&gt; &lt;span class="n"&gt;startproject&lt;/span&gt; &lt;span class="n"&gt;testcases&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Let's start an app named &lt;code&gt;blog&lt;/code&gt;.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;dj&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;~&lt;/span&gt;&lt;span class="sr"&gt;/play/&lt;/span&gt;&lt;span class="n"&gt;dj&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;testcases&lt;/span&gt;&lt;span class="nv"&gt;$&lt;/span&gt; &lt;span class="nv"&gt;python&lt;/span&gt; &lt;span class="n"&gt;manage&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;py&lt;/span&gt; &lt;span class="n"&gt;startapp&lt;/span&gt; &lt;span class="n"&gt;blog&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;We will have the following model in &lt;code&gt;blog/models.py&lt;/code&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;class&lt;/span&gt; &lt;span class="n"&gt;BlogEntry&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;models&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Model&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;title&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;models&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CharField&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;max_length&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;text&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;models&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;TextField&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;is_published&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;models&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;BooleanField&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;default&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;models&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ForeignKey&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;User&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;We will do test driven development which requires:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Thinking about our assumption.&lt;/li&gt;
&lt;li&gt;Writing the test to satisfy that assumption.&lt;/li&gt;
&lt;li&gt;Run the test and it will fail since we won't have view written till this point.&lt;/li&gt;
&lt;li&gt;Adding the view.&lt;/li&gt;
&lt;li&gt;Run the test and fixing the view or anything else till our test passes.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If I could not explain the project structure properly, you can find the complete project &lt;a href="https://github.com/akshar-raaj/Testing-in-Django"&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;First test&lt;/h2&gt;
&lt;p&gt;We want a page which shows all blog entries at url &lt;code&gt;/blog/entries/&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;We need following line in urls i.e &lt;code&gt;testcases/urls.py&lt;/code&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;^blog/&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;include&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;blog.urls&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;&lt;code&gt;blog/urls.py&lt;/code&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;^entries/$&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;#39;blog.views.entries&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;entries&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Let's add a test which satisfies our assumption.&lt;/p&gt;
&lt;p&gt;Every app we create gets a &lt;code&gt;tests.py&lt;/code&gt; where we can put our tests. You can remove the simple addition test generated by default by Django.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;blog/tests.py&lt;/code&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;from&lt;/span&gt; &lt;span class="n"&gt;django&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;test&lt;/span&gt; &lt;span class="nb"&gt;import&lt;/span&gt; &lt;span class="n"&gt;TestCase&lt;/span&gt;
&lt;span class="n"&gt;from&lt;/span&gt; &lt;span class="n"&gt;django&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;test&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;client&lt;/span&gt; &lt;span class="nb"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Client&lt;/span&gt;

&lt;span class="n"&gt;class&lt;/span&gt; &lt;span class="n"&gt;BlogEntriesTest&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;TestCase&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;

    &lt;span class="n"&gt;def&lt;/span&gt; &lt;span class="n"&gt;setUp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Client&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="n"&gt;def&lt;/span&gt; &lt;span class="n"&gt;test_entries_access&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;/blog/entries/&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;assertEqual&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;status_code&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;h3&gt;Explanation&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;We need a test class which is &lt;code&gt;BlogEntriesTest&lt;/code&gt;. Any test class we write must subclass &lt;strong&gt;TestCase&lt;/strong&gt; which is defined in &lt;code&gt;django.test&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Actual tests go in methods defined on the test class. So, our test goes in &lt;code&gt;test_entries_access&lt;/code&gt;. Every test method name must start with &lt;strong&gt;test&lt;/strong&gt; for it to be found by the django test runner.&lt;/li&gt;
&lt;li&gt;Before every test, &lt;code&gt;setUp&lt;/code&gt; method is run. So anything which is common on all the test methods can go in &lt;code&gt;setUp&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;We created a &lt;code&gt;Client&lt;/code&gt; object in setUp. This object is needed to make &lt;code&gt;GET&lt;/code&gt; or &lt;code&gt;POST&lt;/code&gt; request. &lt;code&gt;Client&lt;/code&gt; object simulates request to a url similar to a browser can. Since it is created in setUp, it will be available in all the test methods.&lt;/li&gt;
&lt;li&gt;From &lt;code&gt;test_entries_access&lt;/code&gt;, we make a GET request to the url which we have defined. We capture the response in variable &lt;strong&gt;response&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;We are asserting that &lt;code&gt;status_code&lt;/code&gt; of response must be 200 since we assumed this url to return a 200.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Running the test&lt;/h3&gt;
&lt;p&gt;Tests use a database. Since sqlite is faster than mysql or postgresql, we would use sqlite as the test database. You can continue using your any other database for development or production. We are only interested in running the tests using sqlite.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;testcases/test_settings.py&lt;/code&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;from&lt;/span&gt; &lt;span class="n"&gt;settings&lt;/span&gt; &lt;span class="nb"&gt;import&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;
&lt;span class="n"&gt;DATABASES&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="s"&gt;&amp;#39;default&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="s"&gt;&amp;#39;ENGINE&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;#39;django.db.backends.sqlite3&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="s"&gt;&amp;#39;NAME&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;#39;abc&amp;#39;&lt;/span&gt;
     &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Running the test. &lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;python&lt;/span&gt; &lt;span class="n"&gt;manage&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;py&lt;/span&gt; &lt;span class="n"&gt;test&lt;/span&gt; &lt;span class="n"&gt;blog&lt;/span&gt; &lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="n"&gt;settings&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;testcases&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;test_settings&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;&lt;code&gt;blog&lt;/code&gt; says that only run the tests for app &lt;code&gt;blog&lt;/code&gt;. Not providing this would run the tests for all the apps defined in INSTALLED_APPS which would take quite some time. Make sure that you have added &lt;code&gt;blog&lt;/code&gt; to INSTALLED_APPS.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;--settings&lt;/code&gt; flag tells django test runner to use the specified settings file.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;And our test fails.&lt;/strong&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="err"&gt;ERROR:&lt;/span&gt; &lt;span class="err"&gt;test_entries_access&lt;/span&gt; &lt;span class="err"&gt;(blog.tests.BlogEntriesTest)&lt;/span&gt;
&lt;span class="err"&gt;----------------------------------------------------------------------&lt;/span&gt;
&lt;span class="err"&gt;Traceback&lt;/span&gt; &lt;span class="err"&gt;(most&lt;/span&gt; &lt;span class="err"&gt;recent&lt;/span&gt; &lt;span class="err"&gt;call&lt;/span&gt; &lt;span class="err"&gt;last):&lt;/span&gt;
&lt;span class="err"&gt;......&lt;/span&gt;
&lt;span class="err"&gt;......&lt;/span&gt;
&lt;span class="err"&gt;ViewDoesNotExist:&lt;/span&gt; &lt;span class="err"&gt;Could&lt;/span&gt; &lt;span class="err"&gt;not&lt;/span&gt; &lt;span class="err"&gt;import&lt;/span&gt; &lt;span class="err"&gt;blog.views.entries.&lt;/span&gt; &lt;span class="err"&gt;View&lt;/span&gt; &lt;span class="err"&gt;does&lt;/span&gt; &lt;span class="err"&gt;not&lt;/span&gt; &lt;span class="err"&gt;exist&lt;/span&gt; &lt;span class="err"&gt;in&lt;/span&gt; &lt;span class="err"&gt;module&lt;/span&gt; &lt;span class="err"&gt;blog.views.&lt;/span&gt;

&lt;span class="err"&gt;----------------------------------------------------------------------&lt;/span&gt;
&lt;span class="err"&gt;Ran&lt;/span&gt; &lt;span class="err"&gt;1&lt;/span&gt; &lt;span class="err"&gt;test&lt;/span&gt; &lt;span class="err"&gt;in&lt;/span&gt; &lt;span class="err"&gt;0.019s&lt;/span&gt;

&lt;span class="err"&gt;FAILED&lt;/span&gt; &lt;span class="err"&gt;(errors=1)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Because we have not written the view yet. We didn't have to go to browser to check if this url works, our test does it for us. &lt;/p&gt;
&lt;p&gt;We should test every url we want available in our project. So, that if some url breaks our test would tell that to us immediately.&lt;/p&gt;
&lt;h3&gt;Adding the view&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;from&lt;/span&gt; &lt;span class="n"&gt;blog&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;models&lt;/span&gt; &lt;span class="nb"&gt;import&lt;/span&gt; &lt;span class="n"&gt;BlogEntry&lt;/span&gt;
&lt;span class="n"&gt;from&lt;/span&gt; &lt;span class="n"&gt;django&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;shortcuts&lt;/span&gt; &lt;span class="nb"&gt;import&lt;/span&gt; &lt;span class="n"&gt;render&lt;/span&gt;

&lt;span class="n"&gt;def&lt;/span&gt; &lt;span class="n"&gt;entries&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;entries&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;BlogEntry&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;objects&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;all&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;render&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;blog/entries.html&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;entries&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;entries&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Make sure to add the template &lt;code&gt;blog/entries.html&lt;/code&gt; in your template directory.&lt;/p&gt;
&lt;p&gt;Run the test again.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;python&lt;/span&gt; &lt;span class="n"&gt;manage&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;py&lt;/span&gt; &lt;span class="n"&gt;test&lt;/span&gt; &lt;span class="n"&gt;blog&lt;/span&gt; &lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="n"&gt;settings&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;testcases&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;test_settings&lt;/span&gt;

&lt;span class="n"&gt;Ran&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="n"&gt;test&lt;/span&gt; &lt;span class="n"&gt;in&lt;/span&gt; &lt;span class="mf"&gt;0.019&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;

&lt;span class="n"&gt;OK&lt;/span&gt;
&lt;span class="n"&gt;Destroying&lt;/span&gt; &lt;span class="n"&gt;test&lt;/span&gt; &lt;span class="n"&gt;database&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;alias&lt;/span&gt; &lt;span class="s"&gt;&amp;#39;default&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;...&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;h3&gt;Minor modification to test&lt;/h3&gt;
&lt;p&gt;Since we should not hardcode the urls, we will use &lt;code&gt;reverse&lt;/code&gt;.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;def&lt;/span&gt; &lt;span class="n"&gt;test_entries_access&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;reverse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;entries&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;assertEqual&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;status_code&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Run the test again to make sure our change has not broken anything.&lt;/p&gt;
&lt;h2&gt;Test that context is populated in template&lt;/h2&gt;
&lt;p&gt;We want to make sure that our expectation regarding number of visible blog entries on the page matches the result. Say we have two entries in the database then both of them should be shown on the page as per our view definition.&lt;/p&gt;
&lt;p&gt;A blog must be associated with a user. So, we will create an instance of user in &lt;code&gt;setUp&lt;/code&gt; because we would need this user in other tests as well.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;def&lt;/span&gt; &lt;span class="n"&gt;setUp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Client&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;User&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;objects&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;create_user&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;username&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;test&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;test@test.com&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;password&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;test&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;h3&gt;Testing the context&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;def&lt;/span&gt; &lt;span class="n"&gt;test_entries_template_context&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="c1"&gt;#create few blog entries&lt;/span&gt;
    &lt;span class="n"&gt;BlogEntry&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;objects&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;title&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;Test&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;Test&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;BlogEntry&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;objects&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;title&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;Test&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;Test&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;reverse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;entries&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="c1"&gt;#assert that context contains as many entries as you expect&lt;/span&gt;
    &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;assertEqual&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;entries&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;]),&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;&lt;code&gt;response&lt;/code&gt; contains an attribute &lt;strong&gt;context&lt;/strong&gt; which is a dictionary containing the context sent to template.&lt;/p&gt;
&lt;h3&gt;Assertion&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;We created two blogs and asserted that context contains both of them.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This test is not much useful now. We will see how &lt;code&gt;response.context&lt;/code&gt; becomes useful when we write a custom manager.&lt;/p&gt;
&lt;h2&gt;Only logged in user must access create entry page.&lt;/h2&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;def&lt;/span&gt; &lt;span class="n"&gt;test_entry_create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;reverse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;entry_create&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;assertEqual&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;status_code&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;302&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;login&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;username&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;test&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;password&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;test&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;reverse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;entry_create&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;assertEqual&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;status_code&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Run the test. We know it will fail because we have not written the view or the url yet. &lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;python&lt;/span&gt; &lt;span class="n"&gt;manage&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;py&lt;/span&gt; &lt;span class="n"&gt;test&lt;/span&gt; &lt;span class="n"&gt;blog&lt;/span&gt; &lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="n"&gt;settings&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;testcases&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;test_settings&lt;/span&gt;

&lt;span class="o"&gt;.....&lt;/span&gt;
&lt;span class="n"&gt;ERROR:&lt;/span&gt; &lt;span class="n"&gt;test_entry_create&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;blog&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;tests&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;BlogEntriesTest&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;----------------------------------------------------------------------&lt;/span&gt;
&lt;span class="n"&gt;Traceback&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;most&lt;/span&gt; &lt;span class="n"&gt;recent&lt;/span&gt; &lt;span class="n"&gt;call&lt;/span&gt; &lt;span class="k"&gt;last&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;span class="o"&gt;....&lt;/span&gt;
&lt;span class="n"&gt;NoReverseMatch:&lt;/span&gt; &lt;span class="n"&gt;Reverse&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="s"&gt;&amp;#39;entry_create&amp;#39;&lt;/span&gt; &lt;span class="n"&gt;with&lt;/span&gt; &lt;span class="n"&gt;arguments&lt;/span&gt; &lt;span class="s"&gt;&amp;#39;()&amp;#39;&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="n"&gt;keyword&lt;/span&gt; &lt;span class="n"&gt;arguments&lt;/span&gt; &lt;span class="s"&gt;&amp;#39;{}&amp;#39;&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;found&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;
&lt;span class="o"&gt;----------------------------------------------------------------------&lt;/span&gt;
&lt;span class="n"&gt;Ran&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt; &lt;span class="n"&gt;tests&lt;/span&gt; &lt;span class="n"&gt;in&lt;/span&gt; &lt;span class="mf"&gt;0.051&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;

&lt;span class="n"&gt;FAILED&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;errors&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;h3&gt;Explanation:&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;We expect a url with name &lt;code&gt;entry_create&lt;/code&gt; to be available.&lt;/li&gt;
&lt;li&gt;A non-logged user should not be able to access this url and should be redirected to login urll. So, we assert that status code be 302.&lt;/li&gt;
&lt;li&gt;There is a &lt;code&gt;login&lt;/code&gt; method defined on &lt;code&gt;Client&lt;/code&gt;. So, we can call &lt;code&gt;self.c.login()&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;login()&lt;/code&gt; takes a username and password. You should provide credentials of some user already present in db. Remember we created an user in &lt;code&gt;setUp&lt;/code&gt;. We pass the same credentials here.&lt;/li&gt;
&lt;li&gt;After this client i.e &lt;code&gt;self.c&lt;/code&gt; starts behaving like a logged in user.&lt;/li&gt;
&lt;li&gt;Now client should be able to access create page and so we assert the status code as 200.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Let's start fixing this test.&lt;/p&gt;
&lt;p&gt;Need to add following in &lt;code&gt;blog/urls.py&lt;/code&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;^entry/create/$&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;#39;blog.views.entry_create&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;entry_create&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Adding a modelform. This will be used in create view.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;class&lt;/span&gt; &lt;span class="n"&gt;BlogEntryForm&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ModelForm&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;                                                                          
    &lt;span class="n"&gt;class&lt;/span&gt; &lt;span class="n"&gt;Meta:&lt;/span&gt;
        &lt;span class="n"&gt;model&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;BlogEntry&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Adding the view&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;def&lt;/span&gt; &lt;span class="n"&gt;entry_create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;form&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;BlogEntryForm&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;method&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;POST&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;form&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;BlogEntryForm&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;POST&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;form&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;is_valid&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;HttpResponseRedirect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;reverse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;entries&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
            &lt;span class="n"&gt;form&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;save&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;render&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;blog/entry_create.html&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;form&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;form&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Make sure to create the template. And then run the test. &lt;/p&gt;
&lt;p&gt;You will still see an error.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;File&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;/home/akshar/play/dj/testcases/blog/tests.py&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;line&lt;/span&gt; &lt;span class="mi"&gt;30&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;in&lt;/span&gt; &lt;span class="n"&gt;test_entry_create&lt;/span&gt;
    &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;assertEqual&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;status_code&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;302&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;AssertionError:&lt;/span&gt; &lt;span class="mi"&gt;200&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="mi"&gt;302&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Because we missed adding &lt;code&gt;login_required&lt;/code&gt; to the view and even anonymous users are able to access this url. And hence they are getting a 200 instead of 302.&lt;/p&gt;
&lt;p&gt;Let's fix it by adding &lt;code&gt;login_required&lt;/code&gt; decorator to &lt;code&gt;entry_create&lt;/code&gt; view.&lt;/p&gt;
&lt;p&gt;Run the test again and it should pass now.&lt;/p&gt;
&lt;h2&gt;Test invalid form&lt;/h2&gt;
&lt;p&gt;So, we wrote &lt;code&gt;entry_create&lt;/code&gt; with assumption that it will handle POST requests.&lt;/p&gt;
&lt;p&gt;We want to make sure that this view doesn't allow invalid POST and raises an exception in that case.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;def&lt;/span&gt; &lt;span class="n"&gt;test_invalid_entry_create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;login&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;username&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;test&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;password&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;test&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;text&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;#39;Test text&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;reverse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;entry_create&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;assertEqual&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;status_code&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;assertFormError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;form&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;title&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;This field is required.&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;h3&gt;Assertions:&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Since we posted an invalid form, we expect to remain on the same page. So asserted for status code of 200.&lt;/li&gt;
&lt;li&gt;We expect an error to be present on the &lt;code&gt;title&lt;/code&gt; field.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Test valid form&lt;/h2&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;def&lt;/span&gt; &lt;span class="n"&gt;test_valid_entry_create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;login&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;username&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;test&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;password&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;test&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;text&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;#39;Test text&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;#39;title&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;#39;Test title&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;user&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;
    &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;assertEqual&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;BlogEntry&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;objects&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;count&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;reverse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;entry_create&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;assertEqual&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;status_code&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;302&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;assertEqual&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;BlogEntry&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;objects&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;count&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;h3&gt;Assertions:&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Before posting we assert that there is no &lt;code&gt;BlogEntry&lt;/code&gt; in the db.&lt;/li&gt;
&lt;li&gt;After posting we check that the user is redirected and so asserted for status code of 302&lt;/li&gt;
&lt;li&gt;We make sure that a &lt;code&gt;BlogEntry&lt;/code&gt; is created in the database on post by checking that count of &lt;code&gt;BlogEntry&lt;/code&gt; has been increased to 1.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Test custom manager methods&lt;/h2&gt;
&lt;p&gt;Suppose you find yourself writing the same filter multiple times for getting the blog entries which have is_published as True. In that case you would write a custom manager.&lt;/p&gt;
&lt;p&gt;We will add the custom manager in models.py&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;class&lt;/span&gt; &lt;span class="n"&gt;PublishedBlogManager&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;models&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Manager&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;def&lt;/span&gt; &lt;span class="n"&gt;get_query_set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;kwargs&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;super&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;PublishedBlogManager&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get_query_set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;kwargs&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;is_published&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Also we need to add this manager on &lt;code&gt;BlogEntry&lt;/code&gt;. So, don't forget to add next two lines to &lt;code&gt;BlogEntry&lt;/code&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;objects&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;models&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Manager&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;published&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;PublishedBlogManager&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Let's write a test now:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;def&lt;/span&gt; &lt;span class="n"&gt;test_entry_custom_managers&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;BlogEntry&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;objects&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;title&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;Test&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;Test&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;is_published&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;False&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;BlogEntry&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;objects&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;title&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;Test&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;Test&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;assertEqual&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;BlogEntry&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;objects&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;count&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;assertEqual&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;BlogEntry&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;published&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;count&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;h3&gt;Assertions:&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;We created two entries. One with is_published as False, and another with True.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;objects&lt;/code&gt; i.e default manager returns all the entries.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;published&lt;/code&gt; i.e custom manager returns only entries which have &lt;code&gt;is_published=True&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Using custom manager in &lt;strong&gt;test_entries_template_context&lt;/strong&gt;:&lt;/h3&gt;
&lt;p&gt;Say now we decide that all entries should not be shown on list entries page. Only published entries should be shown.&lt;/p&gt;
&lt;p&gt;Remember &lt;code&gt;test_entries_template_context&lt;/code&gt;. We only created two blog entries in that test. Edit that test and create one more entry with &lt;code&gt;is_published=False&lt;/code&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;def&lt;/span&gt; &lt;span class="n"&gt;test_entries_template_context&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="c1"&gt;#create few blog entries&lt;/span&gt;
    &lt;span class="n"&gt;BlogEntry&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;objects&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;title&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;Test&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;Test&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;BlogEntry&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;objects&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;title&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;Test&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;Test&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;BlogEntry&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;objects&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;title&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;Test&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;Test&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;is_published&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;False&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;reverse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;entries&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="c1"&gt;#assert that context contains only published entries&lt;/span&gt;
    &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;assertEqual&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;entries&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;]),&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;We created three entries. Only two of them are published.&lt;/p&gt;
&lt;h3&gt;Assertion:&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Entries page should only show 2 entries.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Run the test and it will fail.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="o"&gt;======================================================================&lt;/span&gt;
&lt;span class="n"&gt;FAIL:&lt;/span&gt; &lt;span class="n"&gt;test_entries_template_context&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;blog&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;tests&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;BlogEntriesTest&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;----------------------------------------------------------------------&lt;/span&gt;
&lt;span class="n"&gt;Traceback&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;most&lt;/span&gt; &lt;span class="n"&gt;recent&lt;/span&gt; &lt;span class="n"&gt;call&lt;/span&gt; &lt;span class="k"&gt;last&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
  &lt;span class="n"&gt;File&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;/home/akshar/play/dj/testcases/blog/tests.py&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;line&lt;/span&gt; &lt;span class="mi"&gt;29&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;in&lt;/span&gt; &lt;span class="n"&gt;test_entries_template_context&lt;/span&gt;
    &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;assertEqual&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;entries&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;]),&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;AssertionError:&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;

&lt;span class="o"&gt;----------------------------------------------------------------------&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Happened because we forgot to change our view. Our view still says &lt;code&gt;BlogEntry.objects.all()&lt;/code&gt;. We should change it to &lt;code&gt;BlogEntry.published.all()&lt;/code&gt;. Make this change and the test will pass.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;def&lt;/span&gt; &lt;span class="n"&gt;entries&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;entries&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;BlogEntry&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;published&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;all&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;render_to_response&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;blog/entries.html&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;entries&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;entries&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;So, &lt;strong&gt;response.context&lt;/strong&gt; helped us find that we do not show more entries than we should.&lt;/p&gt;
&lt;h2&gt;Test for pagination&lt;/h2&gt;
&lt;p&gt;Suppose we expect maximum ten entries to be available on each page. There are 15 entries in the db, so first page should show 10 entries and the second page should show 5. If user tries to access the third page a 404 page should be shown.&lt;/p&gt;
&lt;p&gt;Our decided url pattern for getting entries on a particular page:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;^entries/(?P&amp;lt;page&amp;gt;\d+)/$&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;#39;blog.views.entries_page&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;entries_page&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Writing the test:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;def&lt;/span&gt; &lt;span class="n"&gt;test_entries_page&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="n"&gt;in&lt;/span&gt; &lt;span class="n"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;15&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;BlogEntry&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;objects&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;title&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;title&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;text&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;is_published&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;#access first page&lt;/span&gt;
    &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;reverse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;entries_page&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,]))&lt;/span&gt;
    &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;assertEqual&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;status_code&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;assertEqual&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;entries&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;]),&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;#access second page&lt;/span&gt;
    &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;reverse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;entries_page&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,]))&lt;/span&gt;
    &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;assertEqual&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;status_code&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;assertEqual&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;entries&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;]),&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Run the test and it will fail. Let's add view to make it pass.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;def&lt;/span&gt; &lt;span class="n"&gt;entries_page&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;page&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;page&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;page&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;entries&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;BlogEntry&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;published&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;all&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;paginator&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Paginator&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;entries&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;#10 entries per page&lt;/span&gt;
    &lt;span class="n"&gt;page_&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;paginator&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;page&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;page&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;object_list&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;page_&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;object_list&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;render&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;blog/entries_page.html&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;entries&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;object_list&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Test should pass now provided you have added the template.&lt;/p&gt;
&lt;p&gt;Let's try to access third page in the test. We need to add following in &lt;code&gt;test_entries_page&lt;/code&gt; for that.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;    &lt;span class="c1"&gt;#access third page&lt;/span&gt;
    &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;reverse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;entries_page&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,]))&lt;/span&gt;
    &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;assertEqual&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;status_code&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;404&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Running the test raises an error.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="o"&gt;....&lt;/span&gt;
&lt;span class="n"&gt;raise&lt;/span&gt; &lt;span class="n"&gt;EmptyPage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;That page contains no results&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;EmptyPage:&lt;/span&gt; &lt;span class="n"&gt;That&lt;/span&gt; &lt;span class="n"&gt;page&lt;/span&gt; &lt;span class="n"&gt;contains&lt;/span&gt; &lt;span class="nb"&gt;no&lt;/span&gt; &lt;span class="n"&gt;results&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;We find that there is a bug in our view and any page which doesn't contain entries is not being handled as we want. Let's change our view:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;def&lt;/span&gt; &lt;span class="n"&gt;entries_page&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;page&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;page&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;page&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;entries&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;BlogEntry&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;published&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;all&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;paginator&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Paginator&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;entries&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;#10 entries per page&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;page&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;paginator&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;num_pages:&lt;/span&gt;
        &lt;span class="n"&gt;raise&lt;/span&gt; &lt;span class="n"&gt;Http404&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;page_&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;paginator&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;page&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;page&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;object_list&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;page_&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;object_list&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;render&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;blog/entries_page.html&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;entries&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;object_list&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Run the test again.&lt;/p&gt;
&lt;p&gt;If you have a 404 template defined then your test will pass. In this project we do not have a 404 template and so we get another exception&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="err"&gt;ERROR:&lt;/span&gt; &lt;span class="err"&gt;test_entries_page&lt;/span&gt; &lt;span class="err"&gt;(blog.tests.BlogEntriesTest)&lt;/span&gt;
&lt;span class="err"&gt;----------------------------------------------------------------------&lt;/span&gt;
&lt;span class="err"&gt;Traceback&lt;/span&gt; &lt;span class="err"&gt;(most&lt;/span&gt; &lt;span class="err"&gt;recent&lt;/span&gt; &lt;span class="err"&gt;call&lt;/span&gt; &lt;span class="err"&gt;last):&lt;/span&gt;
&lt;span class="err"&gt;....&lt;/span&gt;
    &lt;span class="err"&gt;raise&lt;/span&gt; &lt;span class="err"&gt;TemplateDoesNotExist(name)&lt;/span&gt;
&lt;span class="err"&gt;TemplateDoesNotExist:&lt;/span&gt; &lt;span class="err"&gt;404.html&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;So, let's add a 404 template. Test passes once we do it.&lt;/p&gt;
&lt;p&gt;So, this test also helped us find a missing 404 template.&lt;/p&gt;
&lt;h2&gt;Test for static files&lt;/h2&gt;
&lt;p&gt;You can look at &lt;a href="http://agiliq.com/blog/2013/03/serving-static-files-in-django/"&gt;our blog on static file&lt;/a&gt; if you have some confusion regarding how static files are served in Django.&lt;/p&gt;
&lt;p&gt;We will create a &lt;code&gt;static&lt;/code&gt; directory in our app &lt;code&gt;blog&lt;/code&gt; and will put an image in this directory. Let's say this image is &lt;code&gt;default.jpg&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;Let's add a test to make sure this image is found by django static file handlers. This test makes us confident that we can expect this image to be served at &lt;code&gt;{{STATIC_URL}}default.jpg&lt;/code&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;from&lt;/span&gt; &lt;span class="n"&gt;django&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;contrib&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;staticfiles&lt;/span&gt; &lt;span class="nb"&gt;import&lt;/span&gt; &lt;span class="n"&gt;finders&lt;/span&gt;
&lt;span class="n"&gt;from&lt;/span&gt; &lt;span class="n"&gt;django&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;contrib&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;staticfiles&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;storage&lt;/span&gt; &lt;span class="nb"&gt;import&lt;/span&gt; &lt;span class="n"&gt;staticfiles_storage&lt;/span&gt;

&lt;span class="n"&gt;def&lt;/span&gt; &lt;span class="n"&gt;test_images&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;abs_path&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;finders&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;find&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;default.jpg&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;assertTrue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;staticfiles_storage&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;exists&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;abs_path&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Run the test and it should pass.&lt;/p&gt;
&lt;p&gt;You can view the complete project &lt;a href="https://github.com/akshar-raaj/Testing-in-Django"&gt;here&lt;/a&gt;.&lt;/p&gt;</description><guid>http://agiliq.com/blog/2013/04/common-testing-scenarios-for-django-app/</guid></item><item><title>Logging in Django</title><link>http://agiliq.com/blog/2013/03/logging-in-django/</link><description>This is a talk I gave at Agiliq on 21-March-2013 as a part of the &lt;a href="http://www.meetup.com/Hyderabad-Python-Meetup-Group/events/109204312/" target="_blank"&gt;Hyderabad Python Meetup Group&lt;/a&gt;

&lt;script async class="speakerdeck-embed" data-id="b33f5e2074ec0130286a22000a1f8aa6" data-ratio="1.33333333333333" src="//speakerdeck.com/assets/embed.js"&gt;&lt;/script&gt;</description><guid>http://agiliq.com/blog/2013/03/logging-in-django/</guid></item><item><title>Serving static files in Django</title><link>http://agiliq.com/blog/2013/03/serving-static-files-in-django/</link><description>&lt;p&gt;Serving static files, especially during development, is frequently a pain point. In this post, we will discuss the various settings and directory structure and how they interact with each other. Let's start with development when you have DEBUG = True.&lt;/p&gt;
&lt;p&gt;We will create a Django project from scratch so that we are fully aware about what file in what directory we are talking about. So, this blog post will be a little longer than it should be. We will try these things with Django 1.4, but these will work on Django 1.3 as well. I have not tested it with Django 1.2, so not sure about 1.2.&lt;/p&gt;
&lt;h3&gt;Setting up the project.&lt;/h3&gt;
&lt;p&gt;If you think you don't need this section, then skip to the next section titled &lt;a href="#servee"&gt;Serving static files&lt;/a&gt;. Just make sure to see the directory structure at the end of this section to get an idea of it, so that you will be comfortable in the next section.&lt;/p&gt;
&lt;p&gt;We will try everything inside a virtual environment. We name our virtual environment as staticvirt. So the command we need is &lt;strong&gt;virtualenv staticvirt&lt;/strong&gt;.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="o"&gt;~&lt;/span&gt;&lt;span class="nv"&gt;$&lt;/span&gt; &lt;span class="nv"&gt;virtualenv&lt;/span&gt; &lt;span class="n"&gt;staticvirt&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Next we need to start a Django project inside this virtualenv. Make sure you are inside the virtualenv and have activated it. Also make sure that you install Django inside your virtual environment as we don't want to pollute your system wide site packages.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="o"&gt;~&lt;/span&gt;&lt;span class="nv"&gt;$&lt;/span&gt; &lt;span class="nv"&gt;cd&lt;/span&gt; &lt;span class="n"&gt;staticvirt&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;
&lt;span class="o"&gt;~&lt;/span&gt;&lt;span class="sr"&gt;/staticvirt$ source bin/&lt;/span&gt;&lt;span class="n"&gt;activate&lt;/span&gt;
&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;staticvirt&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;~/&lt;/span&gt;&lt;span class="n"&gt;staticvirt&lt;/span&gt;&lt;span class="nv"&gt;$&lt;/span&gt; &lt;span class="nv"&gt;pip&lt;/span&gt; &lt;span class="n"&gt;install&lt;/span&gt; &lt;span class="n"&gt;django&lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="mf"&gt;1.4&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Start a Django project.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;django&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;admin&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;py&lt;/span&gt; &lt;span class="n"&gt;startproject&lt;/span&gt; &lt;span class="n"&gt;test_project&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Change to directory containing the project.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;cd&lt;/span&gt; &lt;span class="n"&gt;test_project&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Let's see the directory structure at this point.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;staticvirt&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;~&lt;/span&gt;&lt;span class="sr"&gt;/staticvirt/&lt;/span&gt;&lt;span class="n"&gt;test_project&lt;/span&gt;&lt;span class="nv"&gt;$&lt;/span&gt; &lt;span class="nv"&gt;tree&lt;/span&gt;
&lt;span class="o"&gt;.&lt;/span&gt;
&lt;span class="o"&gt;|--&lt;/span&gt; &lt;span class="n"&gt;manage&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;py&lt;/span&gt;
&lt;span class="sb"&gt;`-- test_project&lt;/span&gt;
&lt;span class="sb"&gt;    |-- __init__.py&lt;/span&gt;
&lt;span class="sb"&gt;    |-- settings.py&lt;/span&gt;
&lt;span class="sb"&gt;    |-- urls.py&lt;/span&gt;
&lt;span class="sb"&gt;    `&lt;/span&gt;&lt;span class="o"&gt;--&lt;/span&gt; &lt;span class="n"&gt;wsgi&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;py&lt;/span&gt;

&lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="n"&gt;directory&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt; &lt;span class="n"&gt;files&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Check the contents of test_project/settings.py. Search for all the lines which contain the substring &lt;strong&gt;static&lt;/strong&gt;. I will list all those lines below.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;STATIC_ROOT&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;&amp;#39;&amp;#39;&lt;/span&gt;

&lt;span class="n"&gt;STATIC_URL&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;&amp;#39;/static/&amp;#39;&lt;/span&gt;

&lt;span class="n"&gt;STATICFILES_DIRS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;STATICFILES_FINDERS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; 
    &lt;span class="s"&gt;&amp;#39;django.contrib.staticfiles.finders.FileSystemFinder&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s"&gt;&amp;#39;django.contrib.staticfiles.finders.AppDirectoriesFinder&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="c1"&gt;#    &amp;#39;django.contrib.staticfiles.finders.DefaultStorageFinder&amp;#39;,&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;INSTALLED_APPS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; 
    &lt;span class="o"&gt;....&lt;/span&gt;
    &lt;span class="o"&gt;....&lt;/span&gt;
    &lt;span class="s"&gt;&amp;#39;django.contrib.staticfiles&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="o"&gt;....&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Whatever we saw till here is the default setting provided to us by Django. We have not made any modifications.&lt;/p&gt;
&lt;p&gt;Let's create an app in which we will have a template and then we will write a static file, which will be a stylesheet, and will use that stylesheet in this template.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;python&lt;/span&gt; &lt;span class="n"&gt;manage&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;py&lt;/span&gt; &lt;span class="n"&gt;startapp&lt;/span&gt; &lt;span class="n"&gt;some_app&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Add &lt;strong&gt;some_app&lt;/strong&gt; to INSTALLED_APPS in test_project/settings.py.&lt;/p&gt;
&lt;p&gt;We need a urls.py file for some_app where we will define the urls available on some_app. Project's urls.py should include the urls.py of some_app. So, we add the following line to test_project/urls.py.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;^some_app/&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;include&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;some_app.urls&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;We have following line in urls.py of some_app i.e in some_app/urls.py.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;^home$&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;direct_to_template&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;template&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;some_app/home.html&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Create a directory called &lt;strong&gt;templates&lt;/strong&gt; and add it to TEMPLATE_DIRS. I created this &lt;strong&gt;templates&lt;/strong&gt; directory on the same level as manage.py.&lt;/p&gt;
&lt;p&gt;Adding &lt;strong&gt;templates&lt;/strong&gt; directory to TEMPLATE_DIRS require following changes for me. It will be same if you use the same directory structure as I am using.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;PROJECT_DIR&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dirname&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;__file__&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;TEMPLATE_DIRS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; 
    &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;PROJECT_DIR&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;#39;../templates&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;We need to create home.html for app some_app and it needs to go into templates. So, we create a template file &lt;strong&gt;templates/some_app/home.html&lt;/strong&gt;. We have the following content in the html file.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="nt"&gt;&amp;lt;html&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;body&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;h1&amp;gt;&lt;/span&gt;This is home for some_app&lt;span class="nt"&gt;&amp;lt;/h1&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/body&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/html&amp;gt;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Let's check our project directory structure, so as to remove any confusion.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="o"&gt;~&lt;/span&gt;&lt;span class="sr"&gt;/staticvirt/&lt;/span&gt;&lt;span class="n"&gt;test_project&lt;/span&gt;&lt;span class="nv"&gt;$&lt;/span&gt; &lt;span class="nv"&gt;tree&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;I&lt;/span&gt; &lt;span class="o"&gt;*.&lt;/span&gt;&lt;span class="n"&gt;pyc&lt;/span&gt;
&lt;span class="o"&gt;.&lt;/span&gt;
&lt;span class="o"&gt;|--&lt;/span&gt; &lt;span class="n"&gt;manage&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;py&lt;/span&gt;
&lt;span class="o"&gt;|--&lt;/span&gt; &lt;span class="n"&gt;some_app&lt;/span&gt;
&lt;span class="o"&gt;|&lt;/span&gt;   &lt;span class="o"&gt;|--&lt;/span&gt; &lt;span class="n"&gt;__init__&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;py&lt;/span&gt;
&lt;span class="o"&gt;|&lt;/span&gt;   &lt;span class="o"&gt;|--&lt;/span&gt; &lt;span class="n"&gt;models&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;py&lt;/span&gt;
&lt;span class="o"&gt;|&lt;/span&gt;   &lt;span class="o"&gt;|--&lt;/span&gt; &lt;span class="n"&gt;tests&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;py&lt;/span&gt;
&lt;span class="o"&gt;|&lt;/span&gt;   &lt;span class="o"&gt;|--&lt;/span&gt; &lt;span class="n"&gt;urls&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;py&lt;/span&gt;
&lt;span class="o"&gt;|&lt;/span&gt;   &lt;span class="sb"&gt;`-- views.py&lt;/span&gt;
&lt;span class="sb"&gt;|-- templates&lt;/span&gt;
&lt;span class="sb"&gt;|   `&lt;/span&gt;&lt;span class="o"&gt;--&lt;/span&gt; &lt;span class="n"&gt;some_app&lt;/span&gt;
&lt;span class="o"&gt;|&lt;/span&gt;       &lt;span class="sb"&gt;`-- home.html&lt;/span&gt;
&lt;span class="sb"&gt;`&lt;/span&gt;&lt;span class="o"&gt;--&lt;/span&gt; &lt;span class="n"&gt;test_project&lt;/span&gt;
    &lt;span class="o"&gt;|--&lt;/span&gt; &lt;span class="n"&gt;__init__&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;py&lt;/span&gt;
    &lt;span class="o"&gt;|--&lt;/span&gt; &lt;span class="n"&gt;settings&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;py&lt;/span&gt;
    &lt;span class="o"&gt;|--&lt;/span&gt; &lt;span class="n"&gt;urls&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;py&lt;/span&gt;
    &lt;span class="err"&gt;`&lt;/span&gt;&lt;span class="o"&gt;--&lt;/span&gt; &lt;span class="n"&gt;wsgi&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;py&lt;/span&gt;

&lt;span class="mi"&gt;4&lt;/span&gt; &lt;span class="n"&gt;directories&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;11&lt;/span&gt; &lt;span class="n"&gt;files&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;We did not want .pyc files to be shown and so used a switch with &lt;em&gt;tree&lt;/em&gt; to ignore .pyc files.&lt;/p&gt;
&lt;p&gt;Start the server. Make sure you have added your database settings.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;staticvirt&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;~&lt;/span&gt;&lt;span class="sr"&gt;/staticvirt/&lt;/span&gt;&lt;span class="n"&gt;test_project&lt;/span&gt;&lt;span class="nv"&gt;$&lt;/span&gt; &lt;span class="nv"&gt;python&lt;/span&gt; &lt;span class="n"&gt;manage&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;py&lt;/span&gt; &lt;span class="n"&gt;runserver&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Navigate to &lt;strong&gt;http://127.0.0.1:8000/some_app/home&lt;/strong&gt;. Hereafter, we will call this page as home page of some_app. You should see the html we just wrote.&lt;/p&gt;
&lt;p&gt;&lt;a name="servee"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;Serving static files.&lt;/h3&gt;
&lt;p&gt;Let's edit home.html of some_app and add a stylesheet to it. There doesn't exist any stylesheet yet, we will create it after editing html.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="nt"&gt;&amp;lt;html&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;head&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;link&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;{{STATIC_URL}}styles.css&amp;quot;&lt;/span&gt; &lt;span class="na"&gt;rel=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;stylesheet&amp;quot;&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;text/css&amp;quot;&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/head&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;body&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;h1&amp;gt;&lt;/span&gt;This is home for some_app&lt;span class="nt"&gt;&amp;lt;/h1&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/body&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/html&amp;gt;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Refresh home page of some_app. You will not see any changes yet because we have not created the stylesheet file.&lt;/p&gt;
&lt;p&gt;Also navigate to &lt;strong&gt;http://127.0.0.1:8000/static/styles.css&lt;/strong&gt;, you will see a 404 page.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Static files should be created inside the static/ subdirectory of apps&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Let's create the stylesheet file. Since we want to use this stylesheet in the template of some_app, we will create it inside the &lt;strong&gt;static/&lt;/strong&gt; subdirectory of some_app.
So, let's create a file some_app/static/styles.css. Add following contents to this file.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;body&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;background&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;color:&lt;/span&gt; &lt;span class="n"&gt;red&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Refresh home page of some_app. You should see that the background of this page becomes red. Also, refresh page at &lt;strong&gt;http://127.0.0.1:8000/static/styles.css&lt;/strong&gt;. You will see that it's no more a 404 page and you will see the contents of your stylesheet at this url. If you can't see these changes, make sure that &lt;strong&gt;some_app&lt;/strong&gt; is added to INSTALLED_APPS and restart the server.&lt;/p&gt;
&lt;h4&gt;Points to be noted&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;We did not make any changes to any of the static settings provided by Django to us. We left the static settings as they were in default settings.py provided by Django.&lt;/li&gt;
&lt;li&gt;You don't need any change in your urls.py for serving your static files in development. You don't need to add staticfiles_urlpatterns(). Many a times, I got confused with this.&lt;/li&gt;
&lt;li&gt;You do not need &lt;strong&gt;python manage.py collectstatic&lt;/strong&gt; for serving static files in development.
&lt;br/&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;How it works internally&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;First, check all the static settings we have in settings.py&lt;/li&gt;
&lt;li&gt;They are STATIC_URL, STATIC_ROOT, STATICFILES_FINDERS, STATICFILES_DIRS.&lt;/li&gt;
&lt;li&gt;Also, we have 'django.contrib.staticfiles' in INSTALLED_APPS.&lt;/li&gt;
&lt;li&gt;For now, forget about STATIC_ROOT and STATICFILES_DIRS. Even if you comment it or delete it from settings, your project will continue to work as it is working currently.&lt;/li&gt;
&lt;li&gt;We need 'django.contrib.staticfiles' in our INSTALLED_APPS if we want Django's default server to serve static files.&lt;/li&gt;
&lt;li&gt;By Django's default server, we mean &lt;strong&gt;python manage.py runserver&lt;/strong&gt;, that's provided with Django.&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Django's default server will serve the static files at STATIC_URL. Notice that STATIC_URL is set to '/static/'. &lt;/p&gt;
&lt;p&gt;That's why we have our static file, ie stylesheet, getting served at &lt;code&gt;http://127.0.0.1:8000/static/styles.css&lt;/code&gt;. If you try to get it at &lt;code&gt;http://127.0.0.1:8000/static_changed/styles.css&lt;/code&gt;, you will not be able to, you will get a 404 instead.&lt;/p&gt;
&lt;p&gt;If you want to get the stylesheet at &lt;code&gt;http://127.0.0.1:8000/static_changed/styles.css&lt;/code&gt;, make STATIC_URL='/static_changed/'. Go ahead make this change and check. With this change, static files will get served at /static_changed/.&lt;/p&gt;
&lt;p&gt;This change was only to illustrate what is the purpose of STATIC_URL. Change it back to its default, i.e STATIC_URL='/static/'. &lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Next question is how does Django know from where to read the static files or where to find the static files. That's where STATICFILES_FINDERS comes into picture.&lt;/p&gt;
&lt;p&gt;Check that we have two entries in STATICFILES_FINDERS, i.e 'django.contrib.staticfiles.finders.FileSystemFinder' and 'django.contrib.staticfiles.finders.AppDirectoriesFinder'. You can ignore FileSystemFinder for now, if you wish you can go ahead and comment the FileSystemFinder line.&lt;/p&gt;
&lt;p&gt;Appdirectoriesfinder tells Django to look into static/ subdirectory of each app in INSTALLED_APPS while looking for static files. Remember, we have styles.css under static/ subdirectory of some_app. That's why Django was able to find it and it got served properly by Django server. &lt;/p&gt;
&lt;p&gt;If you change the name of this subdirectory from 'static/' to something else, your static resources will not be served. Go ahead, try it.&lt;/p&gt;
&lt;p&gt;Try commenting Appdirectoriesfinder line and your css file at http://127.0.0.1:8000/static/styles.css will not be served anymore. Ok, uncomment it back after trying this out.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Now, we are fine with what STATIC_URL and STATICFILES_FINDERS does. We still do not need STATIC_ROOT and STATICFILES_DIRS.&lt;/p&gt;
&lt;p&gt;To understand few other things about serving static files, we need one more app.&lt;/p&gt;
&lt;p&gt;Let's create it.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;python&lt;/span&gt; &lt;span class="n"&gt;manage&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;py&lt;/span&gt; &lt;span class="n"&gt;startapp&lt;/span&gt; &lt;span class="n"&gt;other_app&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Edit project urls.py to include the url for other_app. Now project's urls.py i.e test_project/urls.py contains two lines.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;^some_app/&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;include&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;some_app.urls&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt;
&lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;^other_app/&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;include&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;other_app.urls&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;We need following line in other_app's urls.py i.e in other_app/urls.py&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;^home$&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;direct_to_template&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;template&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;other_app/home.html&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Let's create other_app/home.html inside templates/ directory.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="nt"&gt;&amp;lt;html&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;body&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;h1&amp;gt;&lt;/span&gt;This is home for other_app&lt;span class="nt"&gt;&amp;lt;/h1&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/body&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/html&amp;gt;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Check the directory structure at this point.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="o"&gt;~&lt;/span&gt;&lt;span class="sr"&gt;/staticvirt/&lt;/span&gt;&lt;span class="n"&gt;test_project&lt;/span&gt;&lt;span class="nv"&gt;$&lt;/span&gt; &lt;span class="nv"&gt;tree&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;I&lt;/span&gt; &lt;span class="o"&gt;*.&lt;/span&gt;&lt;span class="n"&gt;pyc&lt;/span&gt;
&lt;span class="o"&gt;.&lt;/span&gt;
&lt;span class="o"&gt;|--&lt;/span&gt; &lt;span class="n"&gt;manage&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;py&lt;/span&gt;
&lt;span class="o"&gt;|--&lt;/span&gt; &lt;span class="n"&gt;other_app&lt;/span&gt;
&lt;span class="o"&gt;|&lt;/span&gt;   &lt;span class="o"&gt;|--&lt;/span&gt; &lt;span class="n"&gt;__init__&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;py&lt;/span&gt;
&lt;span class="o"&gt;|&lt;/span&gt;   &lt;span class="o"&gt;|--&lt;/span&gt; &lt;span class="n"&gt;models&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;py&lt;/span&gt;
&lt;span class="o"&gt;|&lt;/span&gt;   &lt;span class="o"&gt;|--&lt;/span&gt; &lt;span class="n"&gt;tests&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;py&lt;/span&gt;
&lt;span class="o"&gt;|&lt;/span&gt;   &lt;span class="o"&gt;|--&lt;/span&gt; &lt;span class="n"&gt;urls&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;py&lt;/span&gt;
&lt;span class="o"&gt;|&lt;/span&gt;   &lt;span class="sb"&gt;`-- views.py&lt;/span&gt;
&lt;span class="sb"&gt;|-- some_app&lt;/span&gt;
&lt;span class="sb"&gt;|   |-- __init__.py&lt;/span&gt;
&lt;span class="sb"&gt;|   |-- models.py&lt;/span&gt;
&lt;span class="sb"&gt;|   |-- static&lt;/span&gt;
&lt;span class="sb"&gt;|   |   `&lt;/span&gt;&lt;span class="o"&gt;--&lt;/span&gt; &lt;span class="n"&gt;styles&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;css&lt;/span&gt;
&lt;span class="o"&gt;|&lt;/span&gt;   &lt;span class="o"&gt;|--&lt;/span&gt; &lt;span class="n"&gt;tests&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;py&lt;/span&gt;
&lt;span class="o"&gt;|&lt;/span&gt;   &lt;span class="o"&gt;|--&lt;/span&gt; &lt;span class="n"&gt;urls&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;py&lt;/span&gt;
&lt;span class="o"&gt;|&lt;/span&gt;   &lt;span class="sb"&gt;`-- views.py&lt;/span&gt;
&lt;span class="sb"&gt;|-- templates&lt;/span&gt;
&lt;span class="sb"&gt;|   |-- other_app&lt;/span&gt;
&lt;span class="sb"&gt;|   |   `&lt;/span&gt;&lt;span class="o"&gt;--&lt;/span&gt; &lt;span class="n"&gt;home&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;html&lt;/span&gt;
&lt;span class="o"&gt;|&lt;/span&gt;   &lt;span class="sb"&gt;`-- some_app&lt;/span&gt;
&lt;span class="sb"&gt;|       `&lt;/span&gt;&lt;span class="o"&gt;--&lt;/span&gt; &lt;span class="n"&gt;home&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;html&lt;/span&gt;
&lt;span class="sb"&gt;`-- test_project&lt;/span&gt;
&lt;span class="sb"&gt;    |-- __init__.py&lt;/span&gt;
&lt;span class="sb"&gt;    |-- settings.py&lt;/span&gt;
&lt;span class="sb"&gt;    |-- urls.py&lt;/span&gt;
&lt;span class="sb"&gt;    `&lt;/span&gt;&lt;span class="o"&gt;--&lt;/span&gt; &lt;span class="n"&gt;wsgi&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;py&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Add other_app to INSTALLED_APPS.&lt;/p&gt;
&lt;p&gt;Now check the url &lt;strong&gt;http://127.0.0.1:8000/other_app/home&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Let's add a stylesheet to home of other_app. Let's assume we want to make background color of other_app's home as blue. For this we create the stylesheet other_app/static/other_style.css&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;body&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;background&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;color:&lt;/span&gt; &lt;span class="n"&gt;blue&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Now add this stylesheet to other_app's home template. So, we edit templates/other_app/home.html and change its content to&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="nt"&gt;&amp;lt;html&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;head&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;link&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;{{STATIC_URL}}other_style.css&amp;quot;&lt;/span&gt; &lt;span class="na"&gt;rel=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;stylesheet&amp;quot;&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;text/css&amp;quot;&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/head&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;body&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;h1&amp;gt;&lt;/span&gt;This is home for other_app&lt;span class="nt"&gt;&amp;lt;/h1&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/body&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/html&amp;gt;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Refresh your page at &lt;code&gt;http://127.0.0.1:8000/other_app/home&lt;/code&gt;. You will see a blue background on this page. You might have to restart your server to see this change. Also, you will be able to see the stylesheet for this page at &lt;code&gt;http://127.0.0.1:8000/static/other_style.css&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Also, verify that home of some_app still has a red background at &lt;code&gt;http://127.0.0.1:8000/some_app/home&lt;/code&gt;.&lt;/p&gt;
&lt;h4&gt;What happened here.&lt;/h4&gt;
&lt;p&gt;When we made a request for /static/other_style.css, Django knows that STATIC_URL is set to '/static/' which matches the first fragment of the url we provide and hence infers that we want it to serve a static file. So, it starts looking into static/ subdirectory of all the apps. It looks into 'static/' subdirectory of all apps because STATICFILES_FINDERS contains 'django.contrib.staticfiles.finders.AppDirectoriesFinder'. Since it finds a file called other_style.css in the static/ subdirectory of other_app, it serves it.&lt;/p&gt;
&lt;p&gt;However, there is one problem with this approach. You must have noticed that we named the stylesheet of other_app as other_style.css. What if we wanted to name this stylesheet as styles.css. Let's try doing it.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;mv&lt;/span&gt; &lt;span class="n"&gt;other_app&lt;/span&gt;&lt;span class="sr"&gt;/static/o&lt;/span&gt;&lt;span class="n"&gt;ther_style&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;css&lt;/span&gt; &lt;span class="n"&gt;other_app&lt;/span&gt;&lt;span class="sr"&gt;/static/s&lt;/span&gt;&lt;span class="n"&gt;tyles&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;css&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Once we make this change, we will also have to change the html of homepage of other_app to include this file. So, edit templates/other_app/home.html and make this change. We have to do this because we renamed other_style.css to styles.css. Html of other_app changes to:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="nt"&gt;&amp;lt;html&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;head&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;link&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;{{STATIC_URL}}styles.css&amp;quot;&lt;/span&gt; &lt;span class="na"&gt;rel=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;stylesheet&amp;quot;&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;text/css&amp;quot;&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/head&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;body&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;h1&amp;gt;&lt;/span&gt;This is home for other_app&lt;span class="nt"&gt;&amp;lt;/h1&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/body&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/html&amp;gt;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Now see both the html pages, we have created.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;http://127.0.0.1:8000/some_app/home&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;http://127.0.0.1:8000/other_app/home&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;You will find that the background of both pages is shown as red now. It depends on what order you have the apps listed in INSTALLED_APPS. If some_app appears before other_app in INSTALLED_APPS, both the pages will have red background. If other_app appears before some_app, both the pages will have blue background. In my INSTALLED_APPS, some_app appears before other_app, so both pages have red background for me.&lt;/p&gt;
&lt;h4&gt;Why this happened:&lt;/h4&gt;
&lt;p&gt;Both these pages try to access a static file named styles.css. Django tries to find this file in the static/ subdirectory of each app listed in INSTALLED_APPS. Once it finds it in static/ subdirectory of some_app, it serves it and does not try to find it in static/ subdirectory of other_app. Since, static/styles.css for some_app says that the background should be red, so the background is shown red for both of these pages. &lt;/p&gt;
&lt;h4&gt;How do we prevent it:&lt;/h4&gt;
&lt;p&gt;So, we want to name stylesheet in both apps as styles.css. For this, we need one extra level of directory inside static/ subdirectory of each app. Let's do the following&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="nb"&gt;mkdir&lt;/span&gt; &lt;span class="n"&gt;some_app&lt;/span&gt;&lt;span class="sr"&gt;/static/som&lt;/span&gt;&lt;span class="n"&gt;e_app&lt;/span&gt;
&lt;span class="n"&gt;mv&lt;/span&gt; &lt;span class="n"&gt;some_app&lt;/span&gt;&lt;span class="sr"&gt;/static/s&lt;/span&gt;&lt;span class="n"&gt;tyles&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;css&lt;/span&gt; &lt;span class="n"&gt;some_app&lt;/span&gt;&lt;span class="sr"&gt;/static/som&lt;/span&gt;&lt;span class="n"&gt;e_app&lt;/span&gt;

&lt;span class="nb"&gt;mkdir&lt;/span&gt; &lt;span class="n"&gt;other_app&lt;/span&gt;&lt;span class="sr"&gt;/static/o&lt;/span&gt;&lt;span class="n"&gt;ther_app&lt;/span&gt;
&lt;span class="n"&gt;mv&lt;/span&gt; &lt;span class="n"&gt;other_app&lt;/span&gt;&lt;span class="sr"&gt;/static/s&lt;/span&gt;&lt;span class="n"&gt;tyles&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;css&lt;/span&gt;  &lt;span class="n"&gt;other_app&lt;/span&gt;&lt;span class="sr"&gt;/static/o&lt;/span&gt;&lt;span class="n"&gt;ther_app&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;So, we created a directory inside static/ subdirectory of each app. The name of this directory is the same as the app name. Then we moved the static resource i.e stylesheet inside the new directory.&lt;/p&gt;
&lt;p&gt;We will also have to change the path to stylesheet in the templates.&lt;/p&gt;
&lt;p&gt;Edit templates/some_app/home.html and change the path of stylesheet. So, the new content becomes:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="nt"&gt;&amp;lt;html&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;head&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;link&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;{{STATIC_URL}}some_app/styles.css&amp;quot;&lt;/span&gt; &lt;span class="na"&gt;rel=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;stylesheet&amp;quot;&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;text/css&amp;quot;&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/head&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;body&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;h1&amp;gt;&lt;/span&gt;This is home for some_app&lt;span class="nt"&gt;&amp;lt;/h1&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/body&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/html&amp;gt;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Make similar change to templates/other_app/home.html, so that new content becomes:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="nt"&gt;&amp;lt;html&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;head&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;link&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;{{STATIC_URL}}other_app/styles.css&amp;quot;&lt;/span&gt; &lt;span class="na"&gt;rel=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;stylesheet&amp;quot;&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;text/css&amp;quot;&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/head&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;body&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;h1&amp;gt;&lt;/span&gt;This is home for other_app&lt;span class="nt"&gt;&amp;lt;/h1&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/body&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/html&amp;gt;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Now see both the html pages again&lt;/p&gt;
&lt;p&gt;&lt;code&gt;http://127.0.0.1:8000/some_app/home&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;http://127.0.0.1:8000/other_app/home&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;You should find red background for some_app and blue background for other_app. &lt;/p&gt;
&lt;h4&gt;What happened here&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;Template of some_app references &lt;code&gt;http://127.0.0.1:8000/static/some_app/styles.css&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Django sees that this url starts with /static/, which is the STATIC_URL and infers that it needs to serve the static file some_app/styles.css&lt;/li&gt;
&lt;li&gt;It starts looking for file some_app/styles.css in static/ subdirectory of apps.&lt;/li&gt;
&lt;li&gt;It finds this file in static/ of some_app and serves it.&lt;/li&gt;
&lt;li&gt;Template of other_app references &lt;code&gt;http://127.0.0.1:8000/static/other_app/styles.css&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Django starts looking for file other_app/styles.css in static/ subdirectory of apps.&lt;/li&gt;
&lt;li&gt;It finds it in static/ of other_app and serves it.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Hope STATIC_URL, STATICFILES_FINDERS and how static files are served makes more sense now.&lt;/p&gt;
&lt;h3&gt;About STATICFILES_DIRS&lt;/h3&gt;
&lt;p&gt;Till now our assumption was that we need separate styling on templates of some_app and other_app. So, we wrote different stylesheet for them.&lt;/p&gt;
&lt;p&gt;Assume we want some style which should be common on all the pages across the project and they are not specific to a particular app. In that case, we do not keep such stylesheet in the static/ subdirectory of any particular app. Instead we create a directory at the same level as manage.py and put project wide static resources in that directory.&lt;/p&gt;
&lt;p&gt;Let's see it in action.&lt;/p&gt;
&lt;p&gt;Create a directory called &lt;strong&gt;project_static&lt;/strong&gt; at the same level as manage.py.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="nb"&gt;mkdir&lt;/span&gt; &lt;span class="n"&gt;project_static&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Let's create a file named base.css inside it.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;touch&lt;/span&gt; &lt;span class="n"&gt;project_static&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;base&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;css&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Edit this file project_static/base.css and add the following content to it.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;h1&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;font&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;style:&lt;/span&gt; &lt;span class="n"&gt;italic&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;So, we want to make h1 as italic across entire project.&lt;/p&gt;
&lt;p&gt;Django is still not aware about this file and will not serve it. For making Django aware about this file we need to add the directory containing this file to STATICFILES_DIRS. So edit test_project/settings.py and add the required directory to STATICFILES_DIRS.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;STATICFILES_DIRS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; 
    &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;PROJECT_DIR&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;#39;../project_static&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Try to access url &lt;code&gt;127.0.0.1:8000/static/base.css&lt;/code&gt;. You should see the contents of the stylesheet you just wrote. Make sure that you have 'django.contrib.staticfiles.finders.FileSystemFinder' in STATICFILES_FINDERS, otherwise this url will give you a 404 page.&lt;/p&gt;
&lt;h4&gt;What happened here:&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;Django server sees that a request comes for a static resource, since it is for a url that starts with '/static/'.&lt;/li&gt;
&lt;li&gt;It tries to find the static file i.e base.css in any of the directory defined in STATICFILES_DIRS.&lt;/li&gt;
&lt;li&gt;Since we have only one directory defined in STATICFILES_DIRS, which is project_static, Django server tries to find this file inside this directory. It finds the file it is searching for in this directory and serves it.&lt;/li&gt;
&lt;li&gt;Had it not found this file in any of the directory defined in STATICFILES_DIRS, it would have tried to find the file in static/ subdirectory of each of the apps defined in INSTALLED_APPS.&lt;/li&gt;
&lt;li&gt;Notice that we still didn't need to add staticfiles_urlpatterns().&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;For using this file in templates, we need to reference this stylesheet. Add the following line to both of the templates we defined.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nb"&gt;link&lt;/span&gt; &lt;span class="n"&gt;href&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;{{STATIC_URL}}base.css&amp;quot;&lt;/span&gt; &lt;span class="n"&gt;rel&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;stylesheet&amp;quot;&lt;/span&gt; &lt;span class="n"&gt;type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;text/css&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Refresh the urls for both the pages. You will see that h1 appears in italic on these pages.&lt;/p&gt;
&lt;p&gt;Let's check the final directory structure which will help in case you have some issues.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;staticvirt&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;~&lt;/span&gt;&lt;span class="sr"&gt;/staticvirt/&lt;/span&gt;&lt;span class="n"&gt;test_project&lt;/span&gt;&lt;span class="nv"&gt;$&lt;/span&gt; &lt;span class="nv"&gt;tree&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;I&lt;/span&gt; &lt;span class="o"&gt;*.&lt;/span&gt;&lt;span class="n"&gt;pyc&lt;/span&gt;
&lt;span class="o"&gt;.&lt;/span&gt;
&lt;span class="o"&gt;|--&lt;/span&gt; &lt;span class="n"&gt;manage&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;py&lt;/span&gt;
&lt;span class="o"&gt;|--&lt;/span&gt; &lt;span class="n"&gt;other_app&lt;/span&gt;
&lt;span class="o"&gt;|&lt;/span&gt;   &lt;span class="o"&gt;|--&lt;/span&gt; &lt;span class="n"&gt;__init__&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;py&lt;/span&gt;
&lt;span class="o"&gt;|&lt;/span&gt;   &lt;span class="o"&gt;|--&lt;/span&gt; &lt;span class="n"&gt;models&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;py&lt;/span&gt;
&lt;span class="o"&gt;|&lt;/span&gt;   &lt;span class="o"&gt;|--&lt;/span&gt; &lt;span class="n"&gt;static&lt;/span&gt;
&lt;span class="o"&gt;|&lt;/span&gt;   &lt;span class="o"&gt;|&lt;/span&gt;   &lt;span class="sb"&gt;`-- other_app&lt;/span&gt;
&lt;span class="sb"&gt;|   |       `&lt;/span&gt;&lt;span class="o"&gt;--&lt;/span&gt; &lt;span class="n"&gt;styles&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;css&lt;/span&gt;
&lt;span class="o"&gt;|&lt;/span&gt;   &lt;span class="o"&gt;|--&lt;/span&gt; &lt;span class="n"&gt;tests&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;py&lt;/span&gt;
&lt;span class="o"&gt;|&lt;/span&gt;   &lt;span class="o"&gt;|--&lt;/span&gt; &lt;span class="n"&gt;urls&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;py&lt;/span&gt;
&lt;span class="o"&gt;|&lt;/span&gt;   &lt;span class="sb"&gt;`-- views.py&lt;/span&gt;
&lt;span class="sb"&gt;|-- project_static&lt;/span&gt;
&lt;span class="sb"&gt;|   `&lt;/span&gt;&lt;span class="o"&gt;--&lt;/span&gt; &lt;span class="n"&gt;base&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;css&lt;/span&gt;
&lt;span class="o"&gt;|--&lt;/span&gt; &lt;span class="n"&gt;some_app&lt;/span&gt;
&lt;span class="o"&gt;|&lt;/span&gt;   &lt;span class="o"&gt;|--&lt;/span&gt; &lt;span class="n"&gt;__init__&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;py&lt;/span&gt;
&lt;span class="o"&gt;|&lt;/span&gt;   &lt;span class="o"&gt;|--&lt;/span&gt; &lt;span class="n"&gt;models&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;py&lt;/span&gt;
&lt;span class="o"&gt;|&lt;/span&gt;   &lt;span class="o"&gt;|--&lt;/span&gt; &lt;span class="n"&gt;static&lt;/span&gt;
&lt;span class="o"&gt;|&lt;/span&gt;   &lt;span class="o"&gt;|&lt;/span&gt;   &lt;span class="sb"&gt;`-- some_app&lt;/span&gt;
&lt;span class="sb"&gt;|   |       `&lt;/span&gt;&lt;span class="o"&gt;--&lt;/span&gt; &lt;span class="n"&gt;styles&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;css&lt;/span&gt;
&lt;span class="o"&gt;|&lt;/span&gt;   &lt;span class="o"&gt;|--&lt;/span&gt; &lt;span class="n"&gt;tests&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;py&lt;/span&gt;
&lt;span class="o"&gt;|&lt;/span&gt;   &lt;span class="o"&gt;|--&lt;/span&gt; &lt;span class="n"&gt;urls&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;py&lt;/span&gt;
&lt;span class="o"&gt;|&lt;/span&gt;   &lt;span class="sb"&gt;`-- views.py&lt;/span&gt;
&lt;span class="sb"&gt;|-- templates&lt;/span&gt;
&lt;span class="sb"&gt;|   |-- other_app&lt;/span&gt;
&lt;span class="sb"&gt;|   |   `&lt;/span&gt;&lt;span class="o"&gt;--&lt;/span&gt; &lt;span class="n"&gt;home&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;html&lt;/span&gt;
&lt;span class="o"&gt;|&lt;/span&gt;   &lt;span class="sb"&gt;`-- some_app&lt;/span&gt;
&lt;span class="sb"&gt;|       `&lt;/span&gt;&lt;span class="o"&gt;--&lt;/span&gt; &lt;span class="n"&gt;home&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;html&lt;/span&gt;
&lt;span class="sb"&gt;`-- test_project&lt;/span&gt;
&lt;span class="sb"&gt;    |-- __init__.py&lt;/span&gt;
&lt;span class="sb"&gt;    |-- settings.py&lt;/span&gt;
&lt;span class="sb"&gt;    |-- urls.py&lt;/span&gt;
&lt;span class="sb"&gt;    `&lt;/span&gt;&lt;span class="o"&gt;--&lt;/span&gt; &lt;span class="n"&gt;wsgi&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;py&lt;/span&gt;

&lt;span class="mi"&gt;11&lt;/span&gt; &lt;span class="n"&gt;directories&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;20&lt;/span&gt; &lt;span class="n"&gt;files&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;h3&gt;About STATIC_ROOT&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;You should never require STATIC_ROOT in development if you are using Django's runserver.&lt;/li&gt;
&lt;li&gt;Once you go to production, you can use it on the server. Django provides a management command called &lt;strong&gt;collectstatic&lt;/strong&gt;, which will collect all the static resources, i.e the resources found in STATICFILES_DIRS and the resources found in static/ subdirectory of apps, into a single location defined by STATIC_ROOT.&lt;/li&gt;
&lt;li&gt;STATIC_ROOT only comes into picture if you want to use &lt;strong&gt;collectstatic&lt;/strong&gt; management command provided by Django.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Let's try it out.
Create a directory named static_resources.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="nb"&gt;mkdir&lt;/span&gt; &lt;span class="n"&gt;static_resources&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Edit test_project/settings.py and add the following line:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;STATIC_ROOT&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;PROJECT_DIR&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;#39;../static_resources&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Now run the following command:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;python&lt;/span&gt; &lt;span class="n"&gt;manage&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;py&lt;/span&gt; &lt;span class="n"&gt;collectstatic&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;You will be asked for confirmation. Type 'yes', and you will see all your static resources are collected into the directory defined by STATIC_ROOT.&lt;/p&gt;
&lt;p&gt;And on your production server you can configure your server to serve all the request for static files from the directory defined by STATIC_ROOT.&lt;/p&gt;
&lt;p&gt;Again, this STATIC_ROOT part was only for illustration purpose. You should not need it during development.&lt;/p&gt;</description><guid>http://agiliq.com/blog/2013/03/serving-static-files-in-django/</guid></item><item><title>Two Scoops of Django: Review</title><link>http://agiliq.com/blog/2013/02/two-scoops-of-django-review/</link><description>&lt;p&gt;&lt;img alt="Django best practices" src="https://s3.amazonaws.com/twoscoops/img/tsd-cover.png" /&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://django.2scoops.org/"&gt;Two scoops of Django&lt;/a&gt; is the new book on Django best practices by Daniel Greenfeld and Audrey Roy. I just finished reading it and found it extremely useful.&lt;/p&gt;
&lt;p&gt;The book is a collection of tips, their justification and code organized in logical areas. I have been using Django since 2008, but I still found a few tips which were new to me and many which served as good reminder. At about 200 pages, its comprehensive but not overwhelming. If you are an advanced Djangonaut, you can read it in a weekend (And you probably are using all its recommendations anyway). If you are just getting started, putting all the tips to use will keep you busy for month.&lt;/p&gt;
&lt;p&gt;A random sampling of tips (The book has more than 50 of them.)&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Use pip, virtualenv and virtualenvwrapper&lt;/li&gt;
&lt;li&gt;Don't keep your virtualenv inside the project folder&lt;/li&gt;
&lt;li&gt;Apps should be small and do one thing well&lt;/li&gt;
&lt;li&gt;Use relative modules, prefer &lt;code&gt;from .models import foo&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;All settings file should be versioned - local_settings.py is an anti-pattern&lt;/li&gt;
&lt;li&gt;Every settings module should have a corresponding requirements.txt&lt;/li&gt;
&lt;li&gt;Don't hardcode your paths&lt;/li&gt;
&lt;li&gt;SingleTable model inheritance is good, multi table model inheritance is bad.&lt;/li&gt;
&lt;li&gt;Create custom managers, but don't reset  default manager.&lt;/li&gt;
&lt;li&gt;If you use CBV, ensure logic doesn't go to urls&lt;/li&gt;
&lt;li&gt;Use Meta.fields and Never Use Meta.excludes&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I especially like that the book mentions alternate ways of doing things. Eg. it recommends CBV as the new and shiny, but advises that FBV are just as reasonable choice.&lt;/p&gt;
&lt;p&gt;If you use Django, I highly recommend this book. At just $12, it would be hard to go wrong.&lt;/p&gt;</description><guid>http://agiliq.com/blog/2013/02/two-scoops-of-django-review/</guid></item><item><title>Easy client side form validations for Django: Django Parsley</title><link>http://agiliq.com/blog/2013/02/easy-client-side-form-validations-for-django-djang/</link><description>&lt;p&gt;&lt;a href="http://parsleyjs.org/"&gt;Parsleyjs&lt;/a&gt; is a JavaScript library to do client side data validations.
It does this in a non-intrusive way via adding a &lt;code&gt;data-*&lt;/code&gt; attributes to form fields. Check it out, it's really slick.&lt;/p&gt;
&lt;p&gt;Django forms do a great job of server side data validations. By integrating Parsley with Django form, you get good client side data validations as well. Get the &lt;a href="https://github.com/agiliq/django-parsley"&gt;app here&lt;/a&gt;.&lt;/p&gt;
&lt;h3&gt;Some design considerations&lt;/h3&gt;
&lt;p&gt;When I started writing this app I wanted to make it really easy to use. My first thought was to make this a filter or a template tag which would have allowed you to do:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="p"&gt;{{&lt;/span&gt; &lt;span class="n"&gt;form&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;parsleyfy&lt;/span&gt; &lt;span class="p"&gt;}}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;However, I use Django-crispy-forms in all my projects. If parsley was a filter, it would have made piping to &lt;code&gt;|crispy&lt;/code&gt; impossible as the render step would already have been completed. Hence &lt;code&gt;parsleyfy&lt;/code&gt; is class decorator. Django-crispy-forms and family will play well with &lt;code&gt;parsleyfy&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Here is the readme.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://travis-ci.org/agiliq/Django-parsley"&gt;&lt;img alt="Build Status" src="https://travis-ci.org/agiliq/Django-parsley.png?branch=master" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;What is it?&lt;/h3&gt;
&lt;p&gt;&lt;a href="http://parsleyjs.org/"&gt;Parsleyjs&lt;/a&gt; is a JavaScript library to do client side data validations.
It does this in a non-intrusive way via adding a &lt;code&gt;data-*&lt;/code&gt; attributes to form fields.&lt;/p&gt;
&lt;p&gt;When you define a Django form, you get server side validations for free using
the form field attributes. Django-parsley adds these validations to client side, by tagging your form with &lt;code&gt;data-*&lt;/code&gt; attributes.&lt;/p&gt;
&lt;h3&gt;Installation&lt;/h3&gt;
&lt;p&gt;Add &lt;code&gt;parsley&lt;/code&gt; to your &lt;code&gt;INSTALLED_APPS&lt;/code&gt;.&lt;/p&gt;
&lt;h3&gt;Usage&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;parsley&lt;/code&gt; provides a single class decorator called &lt;code&gt;parsleyfy&lt;/code&gt;. Decorate your &lt;code&gt;Form&lt;/code&gt; with &lt;code&gt;parsleyfy&lt;/code&gt; to get the validations.&lt;/p&gt;
&lt;p&gt;Eg.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;from&lt;/span&gt; &lt;span class="n"&gt;parsley&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;decorators&lt;/span&gt; &lt;span class="nb"&gt;import&lt;/span&gt; &lt;span class="n"&gt;parsleyfy&lt;/span&gt;

&lt;span class="nv"&gt;@parsleyfy&lt;/span&gt;
&lt;span class="n"&gt;class&lt;/span&gt; &lt;span class="n"&gt;FieldTypeForm&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;forms&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Form&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;forms&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CharField&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;min_length&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;max_length&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;30&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;forms&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;URLField&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;url2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;forms&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;URLField&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;required&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;False&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;email&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;forms&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;EmailField&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;email2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;forms&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;EmailField&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;required&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;False&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;age&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;forms&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;IntegerField&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;income&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;forms&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DecimalField&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Your rendered form's HTML will look like this&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="nt"&gt;&amp;lt;p&amp;gt;&amp;lt;label&lt;/span&gt; &lt;span class="na"&gt;for=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;id_name&amp;quot;&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Name:&lt;span class="nt"&gt;&amp;lt;/label&amp;gt;&lt;/span&gt; &lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="na"&gt;data-required=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;true&amp;quot;&lt;/span&gt; &lt;span class="na"&gt;data-minlength=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;3&amp;quot;&lt;/span&gt; &lt;span class="na"&gt;maxlength=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;30&amp;quot;&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;text&amp;quot;&lt;/span&gt; &lt;span class="na"&gt;data-maxlength=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;30&amp;quot;&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;id_name&amp;quot;&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;name&amp;quot;&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;p&amp;gt;&amp;lt;label&lt;/span&gt; &lt;span class="na"&gt;for=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;id_url&amp;quot;&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Url:&lt;span class="nt"&gt;&amp;lt;/label&amp;gt;&lt;/span&gt; &lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;text&amp;quot;&lt;/span&gt; &lt;span class="na"&gt;data-required=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;true&amp;quot;&lt;/span&gt; &lt;span class="na"&gt;data-type=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;url&amp;quot;&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;url&amp;quot;&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;id_url&amp;quot;&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;p&amp;gt;&amp;lt;label&lt;/span&gt; &lt;span class="na"&gt;for=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;id_url2&amp;quot;&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Url2:&lt;span class="nt"&gt;&amp;lt;/label&amp;gt;&lt;/span&gt; &lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;text&amp;quot;&lt;/span&gt; &lt;span class="na"&gt;data-type=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;url&amp;quot;&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;url2&amp;quot;&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;id_url2&amp;quot;&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;p&amp;gt;&amp;lt;label&lt;/span&gt; &lt;span class="na"&gt;for=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;id_email&amp;quot;&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Email:&lt;span class="nt"&gt;&amp;lt;/label&amp;gt;&lt;/span&gt; &lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;text&amp;quot;&lt;/span&gt; &lt;span class="na"&gt;data-required=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;true&amp;quot;&lt;/span&gt; &lt;span class="na"&gt;data-type=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;email&amp;quot;&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;email&amp;quot;&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;id_email&amp;quot;&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;p&amp;gt;&amp;lt;label&lt;/span&gt; &lt;span class="na"&gt;for=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;id_email2&amp;quot;&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Email2:&lt;span class="nt"&gt;&amp;lt;/label&amp;gt;&lt;/span&gt; &lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;text&amp;quot;&lt;/span&gt; &lt;span class="na"&gt;data-type=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;email&amp;quot;&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;email2&amp;quot;&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;id_email2&amp;quot;&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;p&amp;gt;&amp;lt;label&lt;/span&gt; &lt;span class="na"&gt;for=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;id_age&amp;quot;&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Age:&lt;span class="nt"&gt;&amp;lt;/label&amp;gt;&lt;/span&gt; &lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;text&amp;quot;&lt;/span&gt; &lt;span class="na"&gt;data-required=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;true&amp;quot;&lt;/span&gt; &lt;span class="na"&gt;data-type=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;digits&amp;quot;&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;age&amp;quot;&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;id_age&amp;quot;&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;p&amp;gt;&amp;lt;label&lt;/span&gt; &lt;span class="na"&gt;for=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;id_income&amp;quot;&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Income:&lt;span class="nt"&gt;&amp;lt;/label&amp;gt;&lt;/span&gt; &lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;text&amp;quot;&lt;/span&gt; &lt;span class="na"&gt;data-required=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;true&amp;quot;&lt;/span&gt; &lt;span class="na"&gt;data-type=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;number&amp;quot;&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;income&amp;quot;&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;id_income&amp;quot;&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Note the &lt;code&gt;data-*&lt;/code&gt; attributes.&lt;/p&gt;
&lt;p&gt;You could also do&lt;/p&gt;
&lt;p&gt;FieldTypeForm = parsleyfy(FieldTypeForm)&lt;/p&gt;
&lt;p&gt;Which is the same thing.&lt;/p&gt;
&lt;p&gt;Put this form inside a&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="nt"&gt;&amp;lt;form&lt;/span&gt; &lt;span class="na"&gt;data-validate=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;parsley&amp;quot;&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    {{ form.as_p }}
&lt;span class="nt"&gt;&amp;lt;/form&amp;gt;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Include the parsleyjs and you are good to go.&lt;/p&gt;
&lt;h3&gt;License&lt;/h3&gt;
&lt;p&gt;3 Clause BSD.&lt;/p&gt;
&lt;h3&gt;Bug report and Help&lt;/h3&gt;
&lt;p&gt;For bug reports open a github ticket. Patches gratefully accepted. Need help? &lt;a href="http://agiliq.com/contactus"&gt;Contact us here&lt;/a&gt;&lt;/p&gt;</description><guid>http://agiliq.com/blog/2013/02/easy-client-side-form-validations-for-django-djang/</guid></item><item><title>Not exactly, not exactly tim the enchanter</title><link>http://agiliq.com/blog/2012/11/not-exactly-not-exactly-tim-the-enchanter/</link><description>&lt;p&gt;I've been putting off writing about my experience with django form wizard
for some time now. I came across &lt;a href="http://brack3t.com/not-exactly-tim-the-enchanter.html"&gt;this blog post by Kenneth Love&lt;/a&gt;
which finally compelled me to write this down.&lt;/p&gt;
&lt;h2&gt;About Django Form Wizard:&lt;/h2&gt;
&lt;p&gt;Form Wizard can be handy when you have a huge form, and you want to make it less
intimidating to the user by splitting it into multiple steps.&lt;/p&gt;
&lt;p&gt;If you have glued multiple forms together with &lt;code&gt;sessions&lt;/code&gt; or whatnot and it
turned out to be a mess, you now what I'm talking about :)&lt;/p&gt;
&lt;p&gt;Think surveys, checkouts, lengthy registrations etc.&lt;/p&gt;
&lt;p&gt;The class &lt;code&gt;WizardView&lt;/code&gt; implements most of functionality while subclasses
&lt;code&gt;SessionWizardView&lt;/code&gt;, &lt;code&gt;CookieWizardView&lt;/code&gt; etc. specify which backend to use.&lt;/p&gt;
&lt;p&gt;Typically, the view takes a list of forms and presents them one by one.
After each step, the form is validated and the raw form data is saved in the backend
(session or cookie for POST data and &lt;code&gt;file_storage&lt;/code&gt; for files). After the last step,
each form is filled with raw data from the backend and validated again.&lt;/p&gt;
&lt;p&gt;The list of fully-filled up form instances is then passed to the &lt;code&gt;done&lt;/code&gt; handler
where the forms can be processed.&lt;/p&gt;
&lt;p&gt;I guess the key bit of info here is: Nothing is written to the database until all
the steps are completed and the forms are saved manually.&lt;/p&gt;
&lt;h2&gt;I know that feel:&lt;/h2&gt;
&lt;p&gt;I'm not a fan of putting more stuff than necessary in &lt;code&gt;urls&lt;/code&gt; either, and I think
this can be easily remedied the way Kenneth wants it.&lt;/p&gt;
&lt;p&gt;For example, to specify &lt;code&gt;forms_list&lt;/code&gt; and &lt;code&gt;url_name&lt;/code&gt; in the &lt;code&gt;views&lt;/code&gt; instead of &lt;code&gt;urls&lt;/code&gt; one could do:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;from&lt;/span&gt; &lt;span class="n"&gt;holygrail&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;forms&lt;/span&gt; &lt;span class="nb"&gt;import&lt;/span&gt; &lt;span class="n"&gt;NameForm&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;QuestForm&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ColorForm&lt;/span&gt;

&lt;span class="n"&gt;class&lt;/span&gt; &lt;span class="n"&gt;MerlinWizard&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;NamedUrlSessionWizardView&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;

    &lt;span class="o"&gt;...&lt;/span&gt;
    &lt;span class="o"&gt;...&lt;/span&gt;

    &lt;span class="nv"&gt;@classonlymethod&lt;/span&gt;
    &lt;span class="n"&gt;def&lt;/span&gt; &lt;span class="n"&gt;as_view&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cls&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;kwargs&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;kwargs&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;update&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
            &lt;span class="s"&gt;&amp;#39;form_list&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
                &lt;span class="n"&gt;NameForm&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="n"&gt;QuestForm&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="n"&gt;ColorForm&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="p"&gt;],&lt;/span&gt;
            &lt;span class="s"&gt;&amp;#39;url_name&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;#39;merlin_wizard&amp;#39;&lt;/span&gt;
        &lt;span class="p"&gt;})&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;super&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;MerlinWizard&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;cls&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;as_view&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;kwargs&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="o"&gt;...&lt;/span&gt;
    &lt;span class="o"&gt;...&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;and voilà, you no longer need to pass any args to &lt;code&gt;MerlinWizard&lt;/code&gt;&lt;/p&gt;
&lt;h2&gt;ModelForms/Formsets:&lt;/h2&gt;
&lt;p&gt;I think modelforms/formsets are perfectly fine for usage in the form wizard,
although, you'll need to dive into a few details:&lt;/p&gt;
&lt;p&gt;Save a modelform:&lt;/p&gt;
&lt;p&gt;We can use the &lt;code&gt;process_step&lt;/code&gt; method here. This methods takes the form instance
and returns the data to be saved in the storage for the current step. By default,
it returns the raw form data.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;def&lt;/span&gt; &lt;span class="n"&gt;process_step&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;form&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="s"&gt;&amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;
&lt;span class="s"&gt;    you can save the form here,&lt;/span&gt;
&lt;span class="s"&gt;    since it&amp;#39;s guaranteed to be valid&lt;/span&gt;
&lt;span class="s"&gt;    &amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;steps&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;current&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s"&gt;&amp;#39;2&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;instance&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;form&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;save&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;super&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;MerlinWizard&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;process_step&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;form&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;If you need to pass around the instance to another step, you can add it to the step's storage data e.g:&lt;/p&gt;
&lt;p&gt;Let's say we need to save a model in step 2 and create a formset based on its instance
in step 3:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;def&lt;/span&gt; &lt;span class="n"&gt;process_step&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;form&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="s"&gt;&amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;
&lt;span class="s"&gt;    you can save the current form here,&lt;/span&gt;
&lt;span class="s"&gt;    since it&amp;#39;s guaranteed to be valid&lt;/span&gt;
&lt;span class="s"&gt;    &amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;
    &lt;span class="n"&gt;step_data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;super&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;MerlinWizard&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;process_step&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;form&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;copy&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;steps&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;current&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s"&gt;&amp;#39;2&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;instance&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;form&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;save&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="n"&gt;step_data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;instance_pk&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;instance&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;pk&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;step_data&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;then you can retrieve the &lt;code&gt;instance_pk&lt;/code&gt; like this:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;def&lt;/span&gt; &lt;span class="n"&gt;get_form_kwargs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;step&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;None&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="s"&gt;&amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;
&lt;span class="s"&gt;    in step 3, use the instance from step 2&lt;/span&gt;
&lt;span class="s"&gt;    as a kwarg to the formset&lt;/span&gt;
&lt;span class="s"&gt;    &amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;
    &lt;span class="n"&gt;kwargs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;super&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;MerlinWizard&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get_form_kwargs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;step&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;step&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;step&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s"&gt;&amp;#39;3&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;step_data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;storage&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get_step_data&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;2&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;instance_pk&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;step_data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;instance_pk&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
        &lt;span class="n"&gt;instance&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;MyModel&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;objects&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pk&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;instance_pk&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;kwargs&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;update&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
            &lt;span class="s"&gt;&amp;#39;instance&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;instance&lt;/span&gt;
        &lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;kwargs&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;h2&gt;Defaults:&lt;/h2&gt;
&lt;p&gt;I agree with Kenneth that storages should just work™ like they work with forms/modelforms.&lt;/p&gt;
&lt;p&gt;But, it's handy when you want to keep the wizard media away for the rest of the user media.&lt;/p&gt;
&lt;p&gt;One workaround is to just set the file storage to the default storage engine:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;from&lt;/span&gt; &lt;span class="n"&gt;django&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;core&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;files&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;storage&lt;/span&gt; &lt;span class="nb"&gt;import&lt;/span&gt; &lt;span class="n"&gt;default_storage&lt;/span&gt;

&lt;span class="o"&gt;...&lt;/span&gt;
&lt;span class="o"&gt;...&lt;/span&gt;

&lt;span class="n"&gt;class&lt;/span&gt; &lt;span class="n"&gt;MerlinWizard&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;NamedUrlSessionWizardView&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;

    &lt;span class="n"&gt;file_storage&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;default_storage&lt;/span&gt;
    &lt;span class="o"&gt;...&lt;/span&gt;
    &lt;span class="o"&gt;...&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;h2&gt;Are we &lt;code&gt;done&lt;/code&gt;, yet?:&lt;/h2&gt;
&lt;p&gt;You can handle all the forms you want to save to the database in &lt;code&gt;done&lt;/code&gt; method.&lt;/p&gt;
&lt;p&gt;AFAIK, there's no need to do:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;del&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;session&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;wizard_key_here&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;The wizard cleans up both when it's started and when it's &lt;code&gt;done&lt;/code&gt;.
Also, relying on &lt;code&gt;request.session&lt;/code&gt; breaks the storage abstraction,
so you're better off using &lt;code&gt;self.storage&lt;/code&gt; if your &lt;em&gt;really&lt;/em&gt; want to mess with the storage.
This way, you can switch to a different wizard backend without worrying too much.&lt;/p&gt;
&lt;h2&gt;Conclusion:&lt;/h2&gt;
&lt;p&gt;Having spent a good deal of time with the form wizard over the past few weeks, I feel that
form wizard does a very good job at handling the use case it was designed for.&lt;/p&gt;
&lt;p&gt;Even though the documentation is not perfect, the implementation is clear, concise and flexible
enough to handle a variety of scenarios.&lt;/p&gt;</description><guid>http://agiliq.com/blog/2012/11/not-exactly-not-exactly-tim-the-enchanter/</guid></item><item><title>The missing documentation for django.utils.datastructures</title><link>http://agiliq.com/blog/2012/11/the-missing-documentation-for-djangoutilsdatastruc/</link><description>&lt;div class="note"&gt;
&lt;p class="first admonition-title"&gt;Note&lt;/p&gt;
&lt;p class="last"&gt;&lt;tt class="docutils literal"&gt;django.utils.datastructures&lt;/tt&gt; is intentionally not documented by the django
core devs because it is an internal API and is liable to change without any
notice. This file is not governed by django's lenient backwards-compatible
policy. You have been sufficiently warned!&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;With the note out of the way, let's look at the interesting &lt;a class="reference external" href="https://en.wikipedia.org/wiki/Data_structure"&gt;datastructures&lt;/a&gt; in
this file. You may ask why we should learn about those when we shouldn't be
using them? Reading code is the best way of learning and this file has some
beautiful code.&lt;/p&gt;
&lt;p&gt;&lt;tt class="docutils literal"&gt;MergeDict&lt;/tt&gt; is the first of the datastructures in the file. It provides a
dictionary like interface but can look up from multiple dictionaries provided
during the initialization.&lt;/p&gt;
&lt;p&gt;Here's an example:&lt;/p&gt;
&lt;pre class="literal-block"&gt;
&amp;gt;&amp;gt;&amp;gt; md = MergeDict({&amp;quot;foo&amp;quot;: &amp;quot;bar&amp;quot;, &amp;quot;moo&amp;quot;: &amp;quot;cow&amp;quot;}, {&amp;quot;abc&amp;quot;: &amp;quot;def&amp;quot;})
&amp;gt;&amp;gt;&amp;gt; md[&amp;quot;foo&amp;quot;]
'bar'
&amp;gt;&amp;gt;&amp;gt; md[&amp;quot;abc&amp;quot;]
'def'
&amp;gt;&amp;gt;&amp;gt; md.get(&amp;quot;abc&amp;quot;)
'def'
&amp;gt;&amp;gt;&amp;gt; md[&amp;quot;xyz&amp;quot;]
KeyError:
&amp;gt;&amp;gt;&amp;gt; md.items()
[('foo', 'bar'), ('moo', 'cow'), ('abc', 'def')]
&amp;gt;&amp;gt;&amp;gt; md.keys()
['foo', 'moo', 'abc']
&amp;gt;&amp;gt;&amp;gt; md.values()
['bar', 'cow', 'def']
&lt;/pre&gt;
&lt;p&gt;The MergeDict is used within django in attaching values with a form widget and in
&lt;tt class="docutils literal"&gt;request.REQUEST&lt;/tt&gt;.&lt;/p&gt;
&lt;p&gt;The built-in dictionary does not maintain the order of the items but the
&lt;tt class="docutils literal"&gt;SortedDict&lt;/tt&gt; is a subclass of the built-in dictionary that maintains the keys
in exactly the same order they were inserted.&lt;/p&gt;
&lt;p&gt;Here's an example:&lt;/p&gt;
&lt;pre class="literal-block"&gt;
&amp;gt;&amp;gt;&amp;gt; dd = {&amp;quot;foo&amp;quot;: &amp;quot;bar&amp;quot;, &amp;quot;moo&amp;quot;: &amp;quot;cow&amp;quot;, &amp;quot;abc&amp;quot;: &amp;quot;def&amp;quot;}
{&amp;quot;abc&amp;quot;: &amp;quot;def&amp;quot;, &amp;quot;foo&amp;quot;: &amp;quot;bar&amp;quot;, &amp;quot;moo&amp;quot;: &amp;quot;cow&amp;quot;}
&amp;gt;&amp;gt;&amp;gt; sd = SortedDict(((&amp;quot;foo&amp;quot;, &amp;quot;bar&amp;quot;), (&amp;quot;moo&amp;quot;, &amp;quot;cow&amp;quot;), (&amp;quot;abc&amp;quot;, &amp;quot;def&amp;quot;)))
{&amp;quot;foo&amp;quot;: &amp;quot;bar&amp;quot;, &amp;quot;moo&amp;quot;: &amp;quot;cow&amp;quot;, &amp;quot;abc&amp;quot;: &amp;quot;def&amp;quot;}
&amp;gt;&amp;gt;&amp;gt; dd[&amp;quot;xyz&amp;quot;] = &amp;quot;pqr&amp;quot;
&amp;gt;&amp;gt;&amp;gt; dd
{'abc': 'def', 'foo': 'bar', 'moo': 'cow', 'xyz': 'pqr'}
&amp;gt;&amp;gt;&amp;gt; dd[&amp;quot;lmn&amp;quot;] = &amp;quot;ghi&amp;quot;
&amp;gt;&amp;gt;&amp;gt; dd
{'abc': 'def', 'foo': 'bar', 'lmn': 'ghi', 'moo': 'cow', 'xyz': 'pqr'}
&amp;gt;&amp;gt;&amp;gt; sd[&amp;quot;xyz&amp;quot;] = &amp;quot;pqr&amp;quot;
&amp;gt;&amp;gt;&amp;gt; sd
{'foo': 'bar', 'moo': 'cow', 'abc': 'def', 'xyz': 'pqr'}
&amp;gt;&amp;gt;&amp;gt; sd[&amp;quot;lmn&amp;quot;] = &amp;quot;ghi&amp;quot;
{'foo': 'bar', 'moo': 'cow', 'abc': 'def', 'xyz': 'pqr', 'lmn': 'ghi'}
&lt;/pre&gt;
&lt;p&gt;The &lt;tt class="docutils literal"&gt;SortedDict&lt;/tt&gt; is fairly widely used inside of django generally to build a
hierarchy (like models and it's parents), maintaining the order of the form fields
while iterating etc.&lt;/p&gt;
&lt;p&gt;In python 2.7, a new datastructure was introduced that mimics the SortedDict in
the &lt;a class="reference external" href="http://docs.python.org/2/library/collections.html"&gt;collections&lt;/a&gt; module and is called &lt;a class="reference external" href="http://docs.python.org/2/library/collections.html#collections.OrderedDict"&gt;OrderedDict&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;tt class="docutils literal"&gt;MultiValueDict&lt;/tt&gt; is a dictionary subclass that can handle multiple values
assigned to a key.&lt;/p&gt;
&lt;p&gt;Here's an example:&lt;/p&gt;
&lt;pre class="literal-block"&gt;
&amp;gt;&amp;gt;&amp;gt; dd = {&amp;quot;abc&amp;quot;: &amp;quot;def&amp;quot;, &amp;quot;foo&amp;quot;: [&amp;quot;bar1&amp;quot;, &amp;quot;bar2&amp;quot;]}
&amp;gt;&amp;gt;&amp;gt; dd[&amp;quot;foo&amp;quot;]
['bar1', 'bar2']
&amp;gt;&amp;gt;&amp;gt; mvd = MultiValueDict({&amp;quot;abc&amp;quot;: &amp;quot;def&amp;quot;, &amp;quot;foo&amp;quot;: [&amp;quot;bar1&amp;quot;, &amp;quot;bar2&amp;quot;]})
&amp;gt;&amp;gt;&amp;gt; mvd[&amp;quot;foo&amp;quot;]
'bar2'
&amp;gt;&amp;gt;&amp;gt; mvd.getlist(&amp;quot;foo&amp;quot;)
['bar1', 'bar2']
&amp;gt;&amp;gt;&amp;gt; mvd.getlist('blah')
[]
&amp;gt;&amp;gt;&amp;gt; mvd.getlist('abc')
'def'
&amp;gt;&amp;gt;&amp;gt; mvd.setlist('xyz', ['pqr', 'ghi'])
&amp;gt;&amp;gt;&amp;gt; mvd
&amp;lt;MultiValueDict: {'xyz': ['pqr', 'ghi'], 'abc': 'def', 'foo': ['foo1', 'foo2']}&amp;gt;
&amp;gt;&amp;gt;&amp;gt; mvd.appendlist('xyz', 'ijk')
&amp;gt;&amp;gt;&amp;gt; mvd
&amp;lt;MultiValueDict: {'xyz': ['pqr', 'ghi', 'ijk'], 'abc': 'def', 'foo': ['foo1', 'foo2']}&amp;gt;
&amp;gt;&amp;gt;&amp;gt; mvd.update({'xyz': 'lmn'})
&amp;gt;&amp;gt;&amp;gt; mvd
&amp;lt;MultiValueDict: {'xyz': ['pqr', 'ghi', 'ijk', 'lmn'], 'abc': 'def', 'foo': ['foo1', 'foo2']}&amp;gt;
&lt;/pre&gt;
&lt;p&gt;The &lt;tt class="docutils literal"&gt;MultiValueDict&lt;/tt&gt; is used in binding data to &lt;tt class="docutils literal"&gt;request.POST&lt;/tt&gt;, the files to &lt;tt class="docutils literal"&gt;request.FILES&lt;/tt&gt;
and in the get parameter parsing.&lt;/p&gt;
&lt;p&gt;The &lt;tt class="docutils literal"&gt;ImmutableList&lt;/tt&gt; is an immutable datastructure that raises errors when it is
attempted to be mutated.&lt;/p&gt;
&lt;p&gt;Here's an example:&lt;/p&gt;
&lt;pre class="literal-block"&gt;
&amp;gt;&amp;gt;&amp;gt; il = ImmutableList(['foo', 'bar', 'abc'])
&amp;gt;&amp;gt;&amp;gt; il += 'lmn'
AttributeError: ImmutableList object is immutable.
&amp;gt;&amp;gt;&amp;gt; il = ImmutableList(['foo', 'bar', 'abc'], warning='Custom warning')
&amp;gt;&amp;gt;&amp;gt; il[1] = 123
AttributeError: Custom warning
&lt;/pre&gt;
&lt;p&gt;The &lt;tt class="docutils literal"&gt;ImmutableList&lt;/tt&gt; is used in &lt;tt class="docutils literal"&gt;request.upload_handlers&lt;/tt&gt; to prevent
modification after the &lt;tt class="docutils literal"&gt;request.POST&lt;/tt&gt; or &lt;tt class="docutils literal"&gt;request.FILES&lt;/tt&gt; have been accessed.&lt;/p&gt;
&lt;p&gt;The &lt;tt class="docutils literal"&gt;DictWrapper&lt;/tt&gt; is a subclass of the built-in dictionary that prefixes the keys.
It takes a dictionary, a function and a prefix as arguments. If a specific key lookup
begins with the prefix then the value is passed through the function before it is
returned.&lt;/p&gt;
&lt;p&gt;Here's an example:&lt;/p&gt;
&lt;pre class="literal-block"&gt;
&amp;gt;&amp;gt;&amp;gt; dw = DictWrapper({'foo': 'bar', 'moo': 'cow'}, lambda x: x, 'abc_')
&amp;gt;&amp;gt;&amp;gt; dw['foo']
'bar'
&amp;gt;&amp;gt;&amp;gt; dw['abc_foo']
'bar'
&amp;gt;&amp;gt;&amp;gt; dw['xyz_foo']
KeyError: 'xyz_foo'
&amp;gt;&amp;gt;&amp;gt; def post_process_value(value):
...     return &amp;quot;The value is &amp;quot; + value
&amp;gt;&amp;gt;&amp;gt; dw = DictWrapper({'foo': 'bar', 'moo': 'cow'}, post_process_value, 'abc_')
&amp;gt;&amp;gt;&amp;gt; dw['foo']
'bar'
&amp;gt;&amp;gt;&amp;gt; dw['abc_foo']
'The value is bar'
&lt;/pre&gt;
&lt;p&gt;The &lt;tt class="docutils literal"&gt;DictWrapper&lt;/tt&gt; is used in quoting names for SQL queries with the key prefix.&lt;/p&gt;
&lt;p&gt;Hope you enjoyed learning about these hidden gems and how django works under the hood but
take the note on the top into consideration.&lt;/p&gt;
</description><guid>http://agiliq.com/blog/2012/11/the-missing-documentation-for-djangoutilsdatastruc/</guid></item><item><title>Rails for Django developers</title><link>http://agiliq.com/blog/2012/10/rails-for-django-developers/</link><description>&lt;h3&gt;My presentation at Pycon India 2012&lt;/h3&gt; &lt;br /&gt;&lt;br /&gt;


&lt;iframe src="https://docs.google.com/presentation/embed?id=1986PqvjT9J2xNrOGF1Vt28WgesGn8V52fcEKsQzNYY4&amp;start=false&amp;loop=false&amp;delayms=3000" frameborder="0" width="480" height="389" allowfullscreen="true" mozallowfullscreen="true" webkitallowfullscreen="true"&gt;&lt;/iframe&gt;

&lt;a href="https://docs.google.com/presentation/pub?id=1986PqvjT9J2xNrOGF1Vt28WgesGn8V52fcEKsQzNYY4&amp;start=false&amp;loop=false&amp;delayms=3000"&gt;Download it from here&lt;/a&gt;</description><guid>http://agiliq.com/blog/2012/10/rails-for-django-developers/</guid></item><item><title>Dropbox file upload handler for django</title><link>http://agiliq.com/blog/2012/07/dropbox-file-upload-handler-for-django/</link><description>&lt;p&gt;Dropbox &lt;a class="reference external" href="http://blog.dropbox.com/index.php/new-dropbox-pro-plans/"&gt;announced&lt;/a&gt; new pro plans last week and some accounts have had their
storage size doubled. Wouldn't it be wonderful if we could upload all our
files to dropbox from our django webapp?&lt;/p&gt;
&lt;p&gt;In this post, I write a custom file upload handler that will upload files
from our application to dropbox.&lt;/p&gt;
&lt;p&gt;Let us see how to use the custom file upload handler.&lt;/p&gt;
&lt;p&gt;Install the &lt;a class="reference external" href="https://www.dropbox.com/developers/reference/sdk"&gt;Dropbox Python SDK&lt;/a&gt; before you setup your django app to handle
the file uploads.&lt;/p&gt;
&lt;p&gt;In your &lt;cite&gt;settings.py&lt;/cite&gt;, add the following attributes (with the values filled):&lt;/p&gt;
&lt;pre class="literal-block"&gt;
DROPBOX_APP_KEY = &amp;quot;&amp;quot;
DROPBOX_APP_SECRET_KEY = &amp;quot;&amp;quot;
DROPBOX_APP_ACCESS_TOKEN = &amp;quot;&amp;quot;
DROPBOX_APP_ACCESS_TOKEN_SECRET = &amp;quot;&amp;quot;

# Optional values below

# The folder where you want the files uploaded.
# Example: /Public or /
DROPBOX_FILE_UPLOAD_FOLDER = &amp;quot;&amp;quot;
# The value below may be either 'app_folder' or 'dropbox'
DROPBOX_ACCESS_TYPE = &amp;quot;&amp;quot;
&lt;/pre&gt;
&lt;p&gt;The &lt;cite&gt;DROPBOX_APP_KEY&lt;/cite&gt; and &lt;cite&gt;DROPBOX_APP_SECRET_KEY&lt;/cite&gt; are provided to you when you
&lt;a class="reference external" href="https://www.dropbox.com/developers/apps"&gt;create a new dropbox app&lt;/a&gt;. Fetching the access token and access token secret
is outside the scope of this blog post but you can follow the &lt;a class="reference external" href="https://www.dropbox.com/developers/start/authentication#python"&gt;Getting Started
Guide&lt;/a&gt; until the &lt;cite&gt;Get an access token section&lt;/cite&gt; and then paste the access token
key and secret in the &lt;cite&gt;DROPBOX_APP_ACCESS_TOKEN&lt;/cite&gt; and &lt;cite&gt;DROPBOX_APP_ACCESS_TOKEN_SECRET&lt;/cite&gt;
attributes respectively.&lt;/p&gt;
&lt;p&gt;Add the &lt;a class="reference external" href="https://gist.github.com/3128835"&gt;DropboxFileUploadHandler&lt;/a&gt; to any app (in my case &lt;cite&gt;testapp&lt;/cite&gt;) and reference
it in the &lt;cite&gt;FILE_UPLOAD_HANDLERS&lt;/cite&gt; in &lt;cite&gt;settings.py&lt;/cite&gt;:&lt;/p&gt;
&lt;pre class="literal-block"&gt;
FILE_UPLOAD_HANDLERS = (
    &amp;quot;testapp.dropbox_upload_handler.DropboxFileUploadHandler&amp;quot;,
)
&lt;/pre&gt;
&lt;p&gt;That's it and you are done!&lt;/p&gt;
&lt;div class="note"&gt;
&lt;p class="first admonition-title"&gt;Note&lt;/p&gt;
&lt;p class="last"&gt;Since dropbox doesn't support chunked uploads, the file is first uploaded
to the temporary file upload directory on the server and then onto dropbox.&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;Here's how you would handle the file post upload in your view:&lt;/p&gt;
&lt;pre class="literal-block"&gt;
def file_upload_handler_view(request):
    if request.method == &amp;quot;POST&amp;quot;:
        file_uploaded = request.FILES[&amp;quot;name_of_file_input&amp;quot;]
        print file_uploaded.read()
        # Helpful attribute to get dropbox file metadata
        # like path on the server, size, thumbnail etc
        file_uploaded.dropbox_metadata
&lt;/pre&gt;
&lt;p&gt;The &lt;cite&gt;DropboxFile&lt;/cite&gt; returned is an instance of &lt;a class="reference external" href="http://docs.python.org/library/httplib.html?highlight=httplib#httplib.HTTPResponse"&gt;httplib.HTTPResponse&lt;/a&gt; and so all
file like methods are not defined but some basic methods like read are supported.
There is an attribute called &lt;cite&gt;dropbox_metadata&lt;/cite&gt; on the uploaded file that holds
the &lt;a class="reference external" href="https://www.dropbox.com/developers/reference/api#metadata-details"&gt;dropbox metadata&lt;/a&gt;.&lt;/p&gt;
</description><guid>http://agiliq.com/blog/2012/07/dropbox-file-upload-handler-for-django/</guid></item><item><title>Deploying Django apps on Heroku</title><link>http://agiliq.com/blog/2012/04/deploying-django-apps-on-heroku/</link><description>&lt;p&gt;Deploying Django apps on Heroku:&lt;/p&gt;
&lt;p&gt;Read this first: http://devcenter.heroku.com/articles/django.&lt;/p&gt;
&lt;p&gt;This is a great article by the Heroku. I am just filling in some more details and making this step-by-step.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Get your Django project code.&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Create a virtualenv with a no-site-packages command ::&lt;/p&gt;
&lt;p&gt;virtualenv vent --no-site-packages&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Install Django, psycopg2 (postgres connector), gunicorn and any other required Django libraries.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;Confirm that you have all the required libraries and you can run your code locally using &lt;code&gt;manage.py runserver&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Create a requirement.txt by using 
    ::&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;pip&lt;/span&gt; &lt;span class="n"&gt;freeze&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;requirements&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;txt&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Make sure you have a requirements.txt at the root of your repo. Heroku uses this to identify that the app is a Python app.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Create a Procfile. Put this entry: ::&lt;/p&gt;
&lt;p&gt;web: python mysite/manage.py run_gunicorn -b "0.0.0.0:$PORT" -w 3shabda&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;This is what your directory structure will look like&lt;/p&gt;
&lt;p&gt;::&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="k"&gt;[root-of-heroku-folder]&lt;/span&gt;
    &lt;span class="err"&gt;requirements.txt&lt;/span&gt;
    &lt;span class="err"&gt;Procfile&lt;/span&gt;
    &lt;span class="k"&gt;[Django-project-folder]&lt;/span&gt;
        &lt;span class="err"&gt;__init__.py&lt;/span&gt;
        &lt;span class="err"&gt;manage.py&lt;/span&gt;
        &lt;span class="err"&gt;settings.py&lt;/span&gt;
        &lt;span class="k"&gt;[app1]&lt;/span&gt;
        &lt;span class="k"&gt;[app2]&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;(If you aren't tracking your files with git yet.) Track your files with git. ::&lt;/p&gt;
&lt;p&gt;git init
git add .
git commit -am "First commit"&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Make sure you have the heroku toolbelt installed. If not go to http://toolbelt.herokuapp.com/ and install.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;11.You should have these commands available now: ::&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;heroku&lt;/span&gt;
&lt;span class="n"&gt;foreman&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Authenticate to heroku with &lt;/p&gt;
&lt;p&gt;::&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;heroku&lt;/span&gt; &lt;span class="n"&gt;auth:login&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Run this command. 
    ::&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;heroku&lt;/span&gt; &lt;span class="n"&gt;create&lt;/span&gt; &lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="n"&gt;stack&lt;/span&gt; &lt;span class="n"&gt;cedar&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;This will create a new Heroku app and create a new remote in your git repo.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Push your code to heroku. 
    ::&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;git&lt;/span&gt; &lt;span class="nb"&gt;push&lt;/span&gt; &lt;span class="n"&gt;heroku&lt;/span&gt; &lt;span class="n"&gt;master&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Your app should be working on Heroku now. &lt;code&gt;heroku open&lt;/code&gt; will show your site.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;</description><guid>http://agiliq.com/blog/2012/04/deploying-django-apps-on-heroku/</guid></item><item><title>Deploy Django App in 5 Easy Steps</title><link>http://agiliq.com/blog/2012/02/deploy-django-app-5-easy-steps/</link><description>&lt;p&gt;So you just bought a new VPS, have installed &lt;a href="http://www.ubuntu.com/"&gt;Ubuntu&lt;/a&gt; and want to deploy
your &lt;a href="www.djangoproject.com"&gt;django&lt;/a&gt; app, GREAT!! We shall get your app, up and running in 5 easy steps, using best(arguably) of tools available. The post is targeted to audience who are new to deployment arena, but assumes you are comfortable with developing basic django apps. We shall be using &lt;a href="http://gunicorn.org/"&gt;gunicorn&lt;/a&gt; as our server and &lt;a href="http://nginx.org/en/"&gt;nginx&lt;/a&gt; nginx as our reverse proxy and static hanlder. Here we go:&lt;/p&gt;
&lt;h3&gt;1. Login and OS Updation:&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="nv"&gt;$&lt;/span&gt; &lt;span class="nv"&gt;ssh&lt;/span&gt; &lt;span class="n"&gt;root&lt;/span&gt;&lt;span class="nv"&gt;@&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;your_ip&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;# apt-get update&lt;/span&gt;

&lt;span class="c1"&gt;# apt-get upgrade&lt;/span&gt;

&lt;span class="c1"&gt;# apt-get dist-upgrade&lt;/span&gt;

&lt;span class="c1"&gt;# dpkg-reconfigure tzdata #choose your time zone&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;h3&gt;2. Setup Users and Permissions:&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="c1"&gt;# useradd agiliq&lt;/span&gt;

&lt;span class="c1"&gt;# mkdir /home/agiliq&lt;/span&gt;

&lt;span class="c1"&gt;# chown agiliq:agiliq /home/agiliq&lt;/span&gt;

&lt;span class="c1"&gt;# passwd agiliq  #choose a password&lt;/span&gt;

&lt;span class="c1"&gt;# chsh agiliq -s /bin/bash  #choose a shell&lt;/span&gt;

&lt;span class="c1"&gt;# visudo #lets give sudo access to the user agiliq&lt;/span&gt;

    &lt;span class="n"&gt;root&lt;/span&gt;     &lt;span class="n"&gt;ALL&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ALL&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;ALL&lt;/span&gt; 
    &lt;span class="n"&gt;agiliq&lt;/span&gt;   &lt;span class="n"&gt;ALL&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ALL&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;ALL&lt;/span&gt;

&lt;span class="c1"&gt;# su agiliq # switch from root to agiliq&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;h3&gt;3. Install necessary stuff and create a dev environment:&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="nv"&gt;$&lt;/span&gt; &lt;span class="nv"&gt;sudo&lt;/span&gt; &lt;span class="n"&gt;apt&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt; &lt;span class="n"&gt;install&lt;/span&gt; &lt;span class="n"&gt;python&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;pip&lt;/span&gt; &lt;span class="n"&gt;git&lt;/span&gt; &lt;span class="n"&gt;mysql&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;client&lt;/span&gt; &lt;span class="n"&gt;mysql&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;server&lt;/span&gt;

&lt;span class="nv"&gt;$&lt;/span&gt; &lt;span class="nv"&gt;python&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;mysqldb&lt;/span&gt; &lt;span class="n"&gt;nginx&lt;/span&gt; &lt;span class="n"&gt;emacs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;you&lt;/span&gt; &lt;span class="n"&gt;might&lt;/span&gt; &lt;span class="n"&gt;choose&lt;/span&gt; &lt;span class="n"&gt;vim&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="n"&gt;stick&lt;/span&gt; &lt;span class="n"&gt;to&lt;/span&gt; &lt;span class="n"&gt;default&lt;/span&gt; &lt;span class="n"&gt;vi&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;nano&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nv"&gt;$&lt;/span&gt; &lt;span class="nv"&gt;pip&lt;/span&gt; &lt;span class="n"&gt;install&lt;/span&gt; &lt;span class="n"&gt;virtualenv&lt;/span&gt; &lt;span class="c1"&gt;#please refer to documentation of virtualenv&lt;/span&gt;

&lt;span class="nv"&gt;$&lt;/span&gt; &lt;span class="nv"&gt;virtualenv&lt;/span&gt; &lt;span class="n"&gt;projhq&lt;/span&gt; &lt;span class="c1"&gt;# creates a project directory,&lt;/span&gt;

&lt;span class="nv"&gt;$&lt;/span&gt; &lt;span class="nv"&gt;cd&lt;/span&gt; &lt;span class="n"&gt;projhq&lt;/span&gt;

&lt;span class="nv"&gt;$&lt;/span&gt; &lt;span class="nv"&gt;projhq&lt;/span&gt; &lt;span class="n"&gt;source&lt;/span&gt; &lt;span class="sr"&gt;/bin/&lt;/span&gt;&lt;span class="n"&gt;activate&lt;/span&gt;

&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;projhq&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="nv"&gt;$&lt;/span&gt; &lt;span class="nv"&gt;pip&lt;/span&gt; &lt;span class="n"&gt;install&lt;/span&gt; &lt;span class="n"&gt;django&lt;/span&gt; &lt;span class="n"&gt;gunicorn&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;h3&gt;4. Deploy some code for test&lt;/h3&gt;
&lt;p&gt;you may clone this polls application for the sake of testing&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;    &lt;span class="nv"&gt;$&lt;/span&gt; &lt;span class="nv"&gt;cd&lt;/span&gt; &lt;span class="o"&gt;~/&lt;/span&gt;&lt;span class="n"&gt;projhq&lt;/span&gt; &lt;span class="c1"&gt;#your project directory&lt;/span&gt;
    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;projhq&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="nv"&gt;$&lt;/span&gt; &lt;span class="nv"&gt;git&lt;/span&gt; &lt;span class="n"&gt;clone&lt;/span&gt; &lt;span class="n"&gt;git:&lt;/span&gt;&lt;span class="sr"&gt;//gi&lt;/span&gt;&lt;span class="n"&gt;thub&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;com&lt;/span&gt;&lt;span class="sr"&gt;/bitaVersion/&lt;/span&gt;&lt;span class="n"&gt;Hello&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;Django&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;git&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;h3&gt;5. Necessary Configurations&lt;/h3&gt;
&lt;h5&gt;i) nginx&lt;/h5&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;    &lt;span class="nv"&gt;$&lt;/span&gt; &lt;span class="nv"&gt;cd&lt;/span&gt; &lt;span class="sr"&gt;/etc/&lt;/span&gt;&lt;span class="n"&gt;nginx&lt;/span&gt;&lt;span class="sr"&gt;/sites-enabled/&lt;/span&gt;
    &lt;span class="nv"&gt;$&lt;/span&gt; &lt;span class="nv"&gt;touch&lt;/span&gt; &lt;span class="n"&gt;nginx&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;conf&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;and inside the file place the following snippet, make sure to change your 
servername, username and static files directory. &lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;server&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nb"&gt;listen&lt;/span&gt; &lt;span class="mi"&gt;80&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="n"&gt;server_name&lt;/span&gt; &lt;span class="err"&gt;“&lt;/span&gt;&lt;span class="n"&gt;your&lt;/span&gt; &lt;span class="n"&gt;server&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="err"&gt;”&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="n"&gt;access_log&lt;/span&gt; &lt;span class="sr"&gt;/home/&lt;/span&gt;&lt;span class="n"&gt;username&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;access&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;log&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="n"&gt;error_log&lt;/span&gt; &lt;span class="sr"&gt;/home/&lt;/span&gt;&lt;span class="n"&gt;username&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;error&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;log&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="n"&gt;location&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;static&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;root&lt;/span&gt; &lt;span class="sr"&gt;/home/&lt;/span&gt;&lt;span class="n"&gt;path_to_proj_directory_containing&lt;/span&gt; &lt;span class="n"&gt;static_files&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="n"&gt;location&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;proxy_pass&lt;/span&gt; &lt;span class="n"&gt;http:&lt;/span&gt;&lt;span class="sr"&gt;//&lt;/span&gt;&lt;span class="mf"&gt;127.0.0.1&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;8000&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;h5&gt;ii)gunicorn configuration&lt;/h5&gt;
&lt;p&gt;cd into project directory/app 
touch gunicorn_cfg.py 
place the following snippet:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="nb"&gt;bind&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;127.0.0.1:8000&amp;quot;&lt;/span&gt;
&lt;span class="n"&gt;logfile&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;/var/log/gunicorn.log&amp;quot;&lt;/span&gt;
&lt;span class="n"&gt;workers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;
&lt;span class="n"&gt;pid&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;projhq&lt;/span&gt;&lt;span class="sr"&gt;/pid/g&lt;/span&gt;&lt;span class="n"&gt;unicorn&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;pid&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;h5&gt;iii)server restart script&lt;/h5&gt;
&lt;p&gt;make a directory called scripts parallel to project root
and place the following snippet in some file(i name start.sh):&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;PROJDIR&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;/path/to/proj/&amp;quot;&lt;/span&gt; &lt;span class="c1"&gt;#directory which contains settings.py&lt;/span&gt;
&lt;span class="n"&gt;PIDFILE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;$PROJDIR/pid/gunicorn.pid&amp;quot;&lt;/span&gt; &lt;span class="c1"&gt;#create a directory called pid inside projdir&lt;/span&gt;
&lt;span class="n"&gt;cd&lt;/span&gt; &lt;span class="nv"&gt;$PROJDIR&lt;/span&gt;
&lt;span class="n"&gt;source&lt;/span&gt; &lt;span class="sr"&gt;/path/&lt;/span&gt;&lt;span class="n"&gt;to&lt;/span&gt;&lt;span class="sr"&gt;/bin/&lt;/span&gt;&lt;span class="n"&gt;activate&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt; &lt;span class="nv"&gt;$PIDFILE&lt;/span&gt; &lt;span class="p"&gt;];&lt;/span&gt; &lt;span class="k"&gt;then&lt;/span&gt;
    &lt;span class="nb"&gt;kill&lt;/span&gt; &lt;span class="sb"&gt;`cat -- $PIDFILE`&lt;/span&gt;
    &lt;span class="n"&gt;rm&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt; &lt;span class="o"&gt;--&lt;/span&gt; &lt;span class="nv"&gt;$PIDFILE&lt;/span&gt;
&lt;span class="n"&gt;fi&lt;/span&gt;
&lt;span class="n"&gt;gunicorn_django&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="n"&gt;path_to_gunicorn_file&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;gunicorn_cfg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;py&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Few checks if you have missed them:&lt;/p&gt;
&lt;h5&gt;create mysql db:&lt;/h5&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;   &lt;span class="n"&gt;create&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="n"&gt;database&lt;/span&gt; &lt;span class="n"&gt;with&lt;/span&gt; &lt;span class="n"&gt;the&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="n"&gt;matching&lt;/span&gt; &lt;span class="n"&gt;your&lt;/span&gt; &lt;span class="n"&gt;settings&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;py&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;h5&gt;Start nginx:&lt;/h5&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;  &lt;span class="n"&gt;sudo&lt;/span&gt; &lt;span class="n"&gt;service&lt;/span&gt; &lt;span class="n"&gt;nginx&lt;/span&gt; &lt;span class="n"&gt;restart&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;h5&gt;Start server:&lt;/h5&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;go&lt;/span&gt; &lt;span class="n"&gt;to&lt;/span&gt; &lt;span class="n"&gt;scripts&lt;/span&gt; &lt;span class="n"&gt;directory:&lt;/span&gt; 
&lt;span class="nb"&gt;chmod&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="n"&gt;start&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sh&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;only&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;the&lt;/span&gt; &lt;span class="n"&gt;first&lt;/span&gt; &lt;span class="nb"&gt;time&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;bash&lt;/span&gt; &lt;span class="n"&gt;start&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sh&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;The above post was a general introduction of how you can begin using lightweight yet scalable tools, in the next post we shall be talking about tools as &lt;a href="http://docs.fabfile.org/en/1.4.0/index.html"&gt;fabric&lt;/a&gt;, &lt;a href="http://pypi.python.org/pypi/supervisor"&gt;supervisor&lt;/a&gt; and &lt;a href="http://pypi.python.org/pypi/MonitManager"&gt;Monit&lt;/a&gt;, which makes things far easier and more secure. Experienced admins can point out flaws in the approach and suggest improvements.&lt;/p&gt;</description><guid>http://agiliq.com/blog/2012/02/deploy-django-app-5-easy-steps/</guid></item><item><title> Dynamically attaching SITE_ID to Django Caching</title><link>http://agiliq.com/blog/2012/02/dynamically-attaching-site_id-django-caching/</link><description>&lt;p&gt;It would be useful and convenient, if you have an automatic way to add the SITE_ID, especially, when you have multiple sites running on the same deployment. Django provides a cache prefix function KEY_FUNCTION in settings which can be used to achieve this.&lt;/p&gt;
&lt;p&gt;Just follow the following steps, and your cache, automatically prepends SITE_ID to the cache key, making it unique across multiple sites.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Put the following into the settings file.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;     &lt;span class="n"&gt;CACHES&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

     &lt;span class="s"&gt;&amp;#39;default&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

      &lt;span class="s"&gt;&amp;#39;BACKEND&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;#39;django.core.cache.backends.db.DatabaseCache&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;

       &lt;span class="s"&gt;&amp;#39;LOCATION&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;#39;cache_table&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;

       &lt;span class="n"&gt;KEY_FUNCTION&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="err"&gt;‘&lt;/span&gt;&lt;span class="n"&gt;projectname&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;appname&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;modulename&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;functionname&lt;/span&gt;&lt;span class="err"&gt;’&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;

                &lt;span class="p"&gt;}&lt;/span&gt;

         &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Write a function to get current site id, say, get_current_site(), which returns current SITE_ID.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Add a function like below, as functionname at the same path as specified in KEY_FUNCTION.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;from&lt;/span&gt; &lt;span class="n"&gt;django&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;utils&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;encoding&lt;/span&gt; &lt;span class="nb"&gt;import&lt;/span&gt; &lt;span class="n"&gt;smart_str&lt;/span&gt;

&lt;span class="n"&gt;def&lt;/span&gt; &lt;span class="n"&gt;prefix_site_id&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;key_prefix&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;version&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;

   &lt;span class="n"&gt;site_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;get_current_site&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

   &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s"&gt;&amp;#39;:&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;join&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="n"&gt;str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;site_id&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;version&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;smart_str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;)])&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;That’s it. You have successfully added an automatic, dynamic, function based cache prefix for django.&lt;/p&gt;</description><guid>http://agiliq.com/blog/2012/02/dynamically-attaching-site_id-django-caching/</guid></item><item><title>Deploying Django apps on Heroku</title><link>http://agiliq.com/blog/2012/02/deploying-django-apps-on-heroku-2/</link><description>&lt;p&gt;Read this first: &lt;a class="reference external" href="http://devcenter.heroku.com/articles/django"&gt;http://devcenter.heroku.com/articles/django&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;This is a great article by the Heroku. I am just filling in some more details and making this step-by-step.&lt;/p&gt;
&lt;ol class="arabic"&gt;
&lt;li&gt;&lt;p class="first"&gt;Get your Django project code.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p class="first"&gt;Create a virtualenv with a no-site-packages command&lt;/p&gt;
&lt;pre class="literal-block"&gt;
virtualenv vent --no-site-packages
&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p class="first"&gt;Install Django, psycopg2 (postgres connector), gunicorn and any other required Django libraries.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p class="first"&gt;Confirm that you have all the required libraries and you can run your code locally using &lt;tt class="docutils literal"&gt;manage.py runserver&lt;/tt&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;dl class="first docutils"&gt;
&lt;dt&gt;Create a requirement.txt by using&lt;/dt&gt;
&lt;dd&gt;&lt;pre class="first last literal-block"&gt;
pip freeze &amp;gt; requirements.txt
&lt;/pre&gt;
&lt;/dd&gt;
&lt;/dl&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p class="first"&gt;Make sure you have a requirements.txt at the root of your repo. Heroku uses this to identify that the app is a Python app.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p class="first"&gt;Create a Procfile. Put this entry:&lt;/p&gt;
&lt;pre class="literal-block"&gt;
web: python mysite/manage.py run_gunicorn -b &amp;quot;0.0.0.0:$PORT&amp;quot; -w 3shabda
&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p class="first"&gt;This is what your directory structure will look like&lt;/p&gt;
&lt;blockquote&gt;
&lt;pre class="literal-block"&gt;
[root-of-heroku-folder]
    requirements.txt
    Procfile
    [Django-project-folder]
        __init__.py
        manage.py
        settings.py
        [app1]
        [app2]
&lt;/pre&gt;
&lt;/blockquote&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p class="first"&gt;(If you aren't tracking your files with git yet.) Track your files with git.&lt;/p&gt;
&lt;pre class="literal-block"&gt;
git init
git add .
git commit -am &amp;quot;First commit&amp;quot;
&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p class="first"&gt;Make sure you have the heroku toolbelt installed. If not go to &lt;a class="reference external" href="http://toolbelt.herokuapp.com/"&gt;http://toolbelt.herokuapp.com/&lt;/a&gt; and install.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;11.You should have these commands available now:&lt;/p&gt;
&lt;pre class="literal-block"&gt;
heroku
foreman
&lt;/pre&gt;
&lt;ol class="arabic" start="12"&gt;
&lt;li&gt;&lt;p class="first"&gt;Authenticate to heroku with&lt;/p&gt;
&lt;pre class="literal-block"&gt;
heroku auth:login
&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p class="first"&gt;Run this command.&lt;/p&gt;
&lt;pre class="literal-block"&gt;
heroku create --stack cedar
&lt;/pre&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;This will create a new Heroku app and create a new remote in your git repo.&lt;/p&gt;
&lt;ol class="arabic" start="14"&gt;
&lt;li&gt;&lt;p class="first"&gt;Push your code to heroku.&lt;/p&gt;
&lt;pre class="literal-block"&gt;
git push heroku master
&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p class="first"&gt;Your app should be working on Heroku now. &lt;tt class="docutils literal"&gt;heroku open&lt;/tt&gt; will show your site.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
</description><guid>http://agiliq.com/blog/2012/02/deploying-django-apps-on-heroku-2/</guid></item><item><title>How to use pep8.py to write better Django code</title><link>http://agiliq.com/blog/2012/02/how-to-use-pep8py-to-write-better-django-code/</link><description>&lt;iframe width="420" height="315" src="http://www.youtube.com/embed/fYEJpq_PtDQ" frameborder="0" allowfullscreen&gt;&lt;/iframe&gt;

&lt;p&gt;Here is another or screencast I created for my "Getting Started with Django" series. Like this? Email us on what would you like to see.&lt;/p&gt;
&lt;p&gt;(Watch in fullscreen.)&lt;/p&gt;</description><guid>http://agiliq.com/blog/2012/02/how-to-use-pep8py-to-write-better-django-code/</guid></item><item><title>Screencast: Django Tutorial Part 1</title><link>http://agiliq.com/blog/2012/02/screencast-django-tutorial-part-1/</link><description>&lt;iframe src="http://player.vimeo.com/video/35836565?title=0&amp;amp;byline=0&amp;amp;portrait=0" width="400" height="300" frameborder="0" webkitAllowFullScreen mozallowfullscreen allowFullScreen&gt;&lt;/iframe&gt;&lt;p&gt;&lt;a href="http://vimeo.com/35836565"&gt;Django Screencast Tutorial 1&lt;/a&gt; from &lt;a href="http://vimeo.com/user10211601"&gt;Shabda Raaj&lt;/a&gt; on &lt;a href="http://vimeo.com"&gt;Vimeo&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;
I am creating screencasts for Django tutorial and other Django videos. Here is part 1. Liked this? Leave me a comment or email me and tell me what would you like me to create screencasts for.

&lt;/p&gt;
&lt;p&gt;
(Watch the screencast in full screen mode.)
&lt;/p&gt;</description><guid>http://agiliq.com/blog/2012/02/screencast-django-tutorial-part-1/</guid></item><item><title>How and why to use pyflakes to write better Python</title><link>http://agiliq.com/blog/2012/02/how-and-why-to-use-pyflakes-to-write-better-python/</link><description>&lt;iframe width="420" height="315" src="http://www.youtube.com/embed/N_Kz4Iu5E7U" frameborder="0" allowfullscreen&gt;&lt;/iframe&gt;

&lt;p&gt;Here is another of the screencasts I created for "Getting started with Python" series. Liked them? Let me know what else would you like me to create screencasts about?&lt;/p&gt;</description><guid>http://agiliq.com/blog/2012/02/how-and-why-to-use-pyflakes-to-write-better-python/</guid></item><item><title>Getting started with South for Django DB migrations</title><link>http://agiliq.com/blog/2012/01/south/</link><description>&lt;p&gt;South is a migration tool used with Django.There will be times when you would be adding fields to a model or changing the type of field (eg: Field was an IntegerField and you want to change it to FloatField). In such cases syncdb doesn't help and South comes to your rescue.&lt;/p&gt;
&lt;p&gt;There were times when i tried "python manage.py migrate southapp", got some error and then tried "python manage.py migrate southapp 0001 --fake". In some cases, that worked. When it did not work, i tried something else and so on. There were confusions regarding what --fake does and why it does so. In this post, i intend to remove(lessen) that confusion.&lt;/p&gt;
&lt;p&gt;We will be seeing some scenarios which will help us understand south better. At various points, we will intentionally make some mistakes and will rectify them later. Also, we keep looking at our database schema as we go. &lt;/p&gt;
&lt;p&gt;Scenario 1: Using south on a brand new app.&lt;/p&gt;
&lt;p&gt;Let's create an app named "farzi_app".&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;python&lt;/span&gt; &lt;span class="n"&gt;manage&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;py&lt;/span&gt; &lt;span class="n"&gt;startapp&lt;/span&gt; &lt;span class="n"&gt;farzi_app&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;In settings.py, add 'south' to INSTALLED_APPS and run syncdb.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;python&lt;/span&gt; &lt;span class="n"&gt;manage&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;py&lt;/span&gt; &lt;span class="n"&gt;syncdb&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Running syncdb creates a table named 'south_migrationhistory' in your database. 
This table 'south_migrationhistory' keeps a track of all the migrations which have been applied. So, this is the table used by south to determine which migrations have been applied and which need to be applied, when you run "python manage.py migrate app_name". More on this table later. You can see this table in your database. See it.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;python&lt;/span&gt; &lt;span class="n"&gt;manage&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;py&lt;/span&gt; &lt;span class="n"&gt;dbshell&lt;/span&gt;
&lt;span class="n"&gt;mysql&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;show&lt;/span&gt; &lt;span class="n"&gt;tables&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;See the entries in table south_migrationhistory.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="nb"&gt;select&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;from&lt;/span&gt; &lt;span class="n"&gt;south_migrationhistory&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;You would see an Empty set at this point.&lt;/p&gt;
&lt;p&gt;The command used to perform migrations is:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;python&lt;/span&gt; &lt;span class="n"&gt;manage&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;py&lt;/span&gt; &lt;span class="n"&gt;migrate&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Run this command.
Since at this point, none of our apps are being managed by south, so performing migration do not do anything.&lt;/p&gt;
&lt;p&gt;Let's make a model in our app 'farzi_app'. Let's name the model Employee. This model looks like:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;class&lt;/span&gt; &lt;span class="n"&gt;Employee&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;models&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Model&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;models&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CharField&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;max_length&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Let's set "farzi_app" to be managed by South(south works on an app level and not on a model level). Had you not wanted to manage this app(farzi_app) by South, you would have run syncdb and a table named "farzi_app_employee" would be created in your database.
But since we want to use south on a brand new app we won't be using syncdb, we need to write a migration which will create the corresponding table in database. 
Before writing the migration, add "farzi_app" to INSTALLED_APPS in settings.py .Writing our migration:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;python&lt;/span&gt; &lt;span class="n"&gt;manage&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;py&lt;/span&gt; &lt;span class="n"&gt;schemamigration&lt;/span&gt; &lt;span class="n"&gt;farzi_app&lt;/span&gt; &lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="n"&gt;initial&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;We used --initial because this is the first migration we wrote. Since, we don't have any migration written for "farzi_app", we need to use --initial. Other option which can be used is --auto. But, --auto needs a previous migration. In our next migration, we will use --auto and see what it does. So, the output for our previous command is :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;Added&lt;/span&gt; &lt;span class="n"&gt;model&lt;/span&gt; &lt;span class="n"&gt;farzi_app&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Employee&lt;/span&gt;
&lt;span class="n"&gt;Created&lt;/span&gt; &lt;span class="mo"&gt;0001&lt;/span&gt;&lt;span class="n"&gt;_initial&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;py&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt; &lt;span class="n"&gt;You&lt;/span&gt; &lt;span class="n"&gt;can&lt;/span&gt; &lt;span class="n"&gt;now&lt;/span&gt; &lt;span class="n"&gt;apply&lt;/span&gt; &lt;span class="n"&gt;this&lt;/span&gt; &lt;span class="n"&gt;migration&lt;/span&gt; &lt;span class="n"&gt;with:&lt;/span&gt; &lt;span class="o"&gt;./&lt;/span&gt;&lt;span class="n"&gt;manage&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;py&lt;/span&gt; &lt;span class="n"&gt;migrate&lt;/span&gt; &lt;span class="n"&gt;farzi_app&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Now, check your database. Still the table "farzi_app_employee" is not created in your database. Also, you can't find any row in table south_migrationhistory. Let's confirm this:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;python&lt;/span&gt; &lt;span class="n"&gt;manage&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;py&lt;/span&gt; &lt;span class="n"&gt;dbshell&lt;/span&gt;
&lt;span class="n"&gt;show&lt;/span&gt; &lt;span class="n"&gt;tables&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;You&lt;/span&gt; &lt;span class="n"&gt;can&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt; &lt;span class="n"&gt;see&lt;/span&gt; &lt;span class="n"&gt;farzi_app_employee&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nb"&gt;select&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;from&lt;/span&gt; &lt;span class="n"&gt;south_migrationhistory&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;This&lt;/span&gt; &lt;span class="n"&gt;gives&lt;/span&gt; &lt;span class="n"&gt;Empty&lt;/span&gt; &lt;span class="n"&gt;Set&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;You need to apply the migration you wrote. So, command you use is:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;python&lt;/span&gt; &lt;span class="n"&gt;manage&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;py&lt;/span&gt; &lt;span class="n"&gt;migrate&lt;/span&gt; &lt;span class="n"&gt;farzi_app&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;What happens when you run this command? &lt;/p&gt;
&lt;p&gt;South checks all the migration written for "farzi_app" in the directory "farzi_app/migrations". Then it checks the table "south_migrationhistory" to see what migrations have already been applied. If a migration has already been applied(if its applied,it is entered in south_migrationhistory), south will not try to apply that migration. For migrations which have not been applied till now(not entered in south_migrationhistory), south will try to apply those migrations and try making the corresponding change in the database. &lt;/p&gt;
&lt;p&gt;In present scenario, south could not find any entry in 'south_migrationhistory' table, so it assumes no migration has been applied till now and tries to apply whatever migrations are there in "farzi_app/migrations". Currently, we have only one migration named "0001_initial.py" in this directory. So, south will try to apply this migration. In this situation, migration would be successful and hence our command "python manage.py migrate farzi_app" is successful. 
Now, check the tables in database and entries in south_migrationhistory.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;python&lt;/span&gt; &lt;span class="n"&gt;manage&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;py&lt;/span&gt; &lt;span class="n"&gt;dbshell&lt;/span&gt;
&lt;span class="n"&gt;show&lt;/span&gt; &lt;span class="n"&gt;tables&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;You&lt;/span&gt; &lt;span class="n"&gt;can&lt;/span&gt; &lt;span class="n"&gt;see&lt;/span&gt; &lt;span class="n"&gt;farzi_app_employee&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nb"&gt;select&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;from&lt;/span&gt; &lt;span class="n"&gt;south_migrationhistory&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;This&lt;/span&gt; &lt;span class="n"&gt;contains&lt;/span&gt; &lt;span class="n"&gt;one&lt;/span&gt; &lt;span class="n"&gt;row&lt;/span&gt; &lt;span class="n"&gt;now&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt; &lt;span class="n"&gt;You&lt;/span&gt; &lt;span class="n"&gt;can&lt;/span&gt; &lt;span class="n"&gt;easily&lt;/span&gt; &lt;span class="n"&gt;identify&lt;/span&gt; &lt;span class="n"&gt;that&lt;/span&gt; &lt;span class="n"&gt;this&lt;/span&gt; &lt;span class="n"&gt;table&lt;/span&gt; &lt;span class="n"&gt;keeps&lt;/span&gt; &lt;span class="n"&gt;track&lt;/span&gt; &lt;span class="n"&gt;of&lt;/span&gt; &lt;span class="n"&gt;what&lt;/span&gt; &lt;span class="n"&gt;migrations&lt;/span&gt; &lt;span class="n"&gt;have&lt;/span&gt; &lt;span class="n"&gt;been&lt;/span&gt; &lt;span class="n"&gt;applied&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Let's change our model now. Add a new field named 'salary' to model 'Employee'. So, our model looks like.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;class&lt;/span&gt; &lt;span class="n"&gt;Employee&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;models&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Model&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;models&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CharField&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;max_length&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;salary&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;models&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;IntegerField&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;null&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  
    &lt;span class="s"&gt;&amp;quot;&amp;quot;&amp;quot;Yeah i know salary should not be left as null. But if we don&amp;#39;t use it, we will have to make some one-off value and all &lt;/span&gt;
&lt;span class="s"&gt;        which we don&amp;#39;t want to see right now.&amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Making this corresponding change to database would have been difficult with syncdb, but not with south. We need to write one more migration. This time we will use --auto(remember last time we used --initial). Let's write the migration.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;python&lt;/span&gt; &lt;span class="n"&gt;manage&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;py&lt;/span&gt; &lt;span class="n"&gt;schemamigration&lt;/span&gt; &lt;span class="n"&gt;farzi_app&lt;/span&gt; &lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="n"&gt;auto&lt;/span&gt;

&lt;span class="n"&gt;Output:&lt;/span&gt;
 &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;Added&lt;/span&gt; &lt;span class="n"&gt;field&lt;/span&gt; &lt;span class="n"&gt;salary&lt;/span&gt; &lt;span class="n"&gt;on&lt;/span&gt; &lt;span class="n"&gt;farzi_app&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Employee&lt;/span&gt;
&lt;span class="n"&gt;Created&lt;/span&gt; &lt;span class="mo"&gt;0002&lt;/span&gt;&lt;span class="n"&gt;_auto__add_field_employee_salary&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;py&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt; &lt;span class="n"&gt;You&lt;/span&gt; &lt;span class="n"&gt;can&lt;/span&gt; &lt;span class="n"&gt;now&lt;/span&gt; &lt;span class="n"&gt;apply&lt;/span&gt; &lt;span class="n"&gt;this&lt;/span&gt; &lt;span class="n"&gt;migration&lt;/span&gt; &lt;span class="n"&gt;with:&lt;/span&gt; &lt;span class="o"&gt;./&lt;/span&gt;&lt;span class="n"&gt;manage&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;py&lt;/span&gt; &lt;span class="n"&gt;migrate&lt;/span&gt; &lt;span class="n"&gt;farzi_app&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;What happens when we run this command? &lt;/p&gt;
&lt;p&gt;South sees our current code, sees the last migration which we wrote, which in current situation is 0001_initial.py, figures out what has changed since our last migration and then writes the information about the changes in our new migration(0002_auto__add_field_employee_salary.py). 
Just creating this migration would not make the corresponding change in our database i.e at this point column 'salary' is not added to table 'farzi_app_employee'. For that, we need to run this migration.Let's do that:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;python&lt;/span&gt; &lt;span class="n"&gt;manage&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;py&lt;/span&gt; &lt;span class="n"&gt;migrate&lt;/span&gt; &lt;span class="n"&gt;farzi_app&lt;/span&gt;

&lt;span class="n"&gt;Output:&lt;/span&gt;
&lt;span class="n"&gt;Running&lt;/span&gt; &lt;span class="n"&gt;migrations&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;farzi_app:&lt;/span&gt;
&lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;Migrating&lt;/span&gt; &lt;span class="n"&gt;forwards&lt;/span&gt; &lt;span class="n"&gt;to&lt;/span&gt; &lt;span class="mo"&gt;0002&lt;/span&gt;&lt;span class="n"&gt;_auto__add_field_employee_salary&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;farzi_app:0002_auto__add_field_employee_salary&lt;/span&gt;
&lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;Loading&lt;/span&gt; &lt;span class="n"&gt;initial&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;farzi_app&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;
&lt;span class="n"&gt;No&lt;/span&gt; &lt;span class="n"&gt;fixtures&lt;/span&gt; &lt;span class="n"&gt;found&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;What happened when we ran "python manage.py migrate farzi_app"?&lt;/p&gt;
&lt;p&gt;Similar to what we saw earlier. South checks all the migrations in farzi_app/migrations/ . It sees two migrations namely '0001_initial.py' and '0002_auto__add_field_employee_salary.py'. It then checks 'south_migrationhistory' table to see what migrations have been applied. It could find one row(this row was inserted by south when we last ran 'python manage.py migrate farzi_app'). So, south figured out that '0001_initial.py' is applied since this entry is there in table 'south_migrationhistory'. Also, south figured out that '0002_auto__add_field_employee_salary.py' is not applied since this entry was not in table 'south_migrationhistory'. So, it tries applying this migration i.e 0002_auto__add_field_employee_salary.py'. In this case, this try is successful and corresponding change is made in table farzi_app_employee. Also, an entry would be now made in 'south_mihgrationhistory' that tells that '0002_auto__add_field_employee_salary.py' is applied. So, next time somebody runs migrate, this migration '0002_auto__add_field_employee_salary.py' will not be applied. Check your database now.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;python&lt;/span&gt; &lt;span class="n"&gt;manage&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;py&lt;/span&gt; &lt;span class="n"&gt;dbshell&lt;/span&gt;
&lt;span class="n"&gt;desc&lt;/span&gt; &lt;span class="n"&gt;farzi_app_employee&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;you&lt;/span&gt; &lt;span class="n"&gt;can&lt;/span&gt; &lt;span class="n"&gt;see&lt;/span&gt; &lt;span class="n"&gt;column&lt;/span&gt; &lt;span class="n"&gt;salary&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;
&lt;span class="nb"&gt;select&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;from&lt;/span&gt; &lt;span class="n"&gt;south_migrationhistory&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;south_migrationhistory has two rows now, which indicates both the migrations we wrote till now has been applied. Next time user runs migrate, south will not try to apply these migrations.&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Understanding --fake:&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;Let's get some errors intentionally which will help understand --fake better. Delete the second row in "south_migrationhistory" table. We will see an actual use of --fake in the next scenario, but i am doing this just to illustrate the use of --fake.&lt;/p&gt;
&lt;p&gt;Deleting the second migration from south_migrationhistory:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="nb"&gt;delete&lt;/span&gt; &lt;span class="n"&gt;from&lt;/span&gt; &lt;span class="n"&gt;south_migrationhistory&lt;/span&gt; &lt;span class="n"&gt;where&lt;/span&gt; &lt;span class="n"&gt;migration&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;0002_auto__add_field_employee_salary&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Now, only one row remains in 'south_migrationhistory'.
Let's change our Employee model a bit and write a migration. Add one more field to 'Employee', so it looks like:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;class&lt;/span&gt; &lt;span class="n"&gt;Employee&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;models&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Model&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;models&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CharField&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;max_length&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;salary&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;models&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;IntegerField&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;null&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;age&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;models&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;IntegerField&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;null&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Writing the migration:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;python&lt;/span&gt; &lt;span class="n"&gt;manage&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;py&lt;/span&gt; &lt;span class="n"&gt;schemamigration&lt;/span&gt; &lt;span class="n"&gt;farzi_app&lt;/span&gt; &lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="n"&gt;auto&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;This creates a migration named '0003_auto__add_field_employee_age.py' in directory farzi_app/migrations. Hereafter we will be referring to this migration as 0003 and will refer to the other two migrations as 0002 and 0001. To add the column 'age' to table 'farzi_app_employee', you need to run this migration i.e 0003.
Let's try running the migration.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;python&lt;/span&gt; &lt;span class="n"&gt;manage&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;py&lt;/span&gt; &lt;span class="n"&gt;migrate&lt;/span&gt; &lt;span class="n"&gt;farzi_app&lt;/span&gt;

&lt;span class="n"&gt;Output:&lt;/span&gt;
&lt;span class="n"&gt;Running&lt;/span&gt; &lt;span class="n"&gt;migrations&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;farzi_app:&lt;/span&gt;
&lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;Migrating&lt;/span&gt; &lt;span class="n"&gt;forwards&lt;/span&gt; &lt;span class="n"&gt;to&lt;/span&gt; &lt;span class="mo"&gt;0003&lt;/span&gt;&lt;span class="n"&gt;_auto__add_field_employee_age&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;farzi_app:0002_auto__add_field_employee_salary&lt;/span&gt;
&lt;span class="o"&gt;!&lt;/span&gt; &lt;span class="n"&gt;Error&lt;/span&gt; &lt;span class="n"&gt;found&lt;/span&gt; &lt;span class="n"&gt;during&lt;/span&gt; &lt;span class="n"&gt;real&lt;/span&gt; &lt;span class="n"&gt;run&lt;/span&gt; &lt;span class="n"&gt;of&lt;/span&gt; &lt;span class="n"&gt;migration&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt; &lt;span class="n"&gt;Aborting&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;

&lt;span class="o"&gt;!&lt;/span&gt; &lt;span class="n"&gt;Since&lt;/span&gt; &lt;span class="n"&gt;you&lt;/span&gt; &lt;span class="n"&gt;have&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="n"&gt;database&lt;/span&gt; &lt;span class="n"&gt;that&lt;/span&gt; &lt;span class="n"&gt;does&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;support&lt;/span&gt; &lt;span class="n"&gt;running&lt;/span&gt;
&lt;span class="o"&gt;!&lt;/span&gt; &lt;span class="n"&gt;schema&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;altering&lt;/span&gt; &lt;span class="n"&gt;statements&lt;/span&gt; &lt;span class="n"&gt;in&lt;/span&gt; &lt;span class="n"&gt;transactions&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;we&lt;/span&gt; &lt;span class="n"&gt;have&lt;/span&gt; &lt;span class="n"&gt;had&lt;/span&gt; 
&lt;span class="o"&gt;!&lt;/span&gt; &lt;span class="n"&gt;to&lt;/span&gt; &lt;span class="n"&gt;leave&lt;/span&gt; &lt;span class="n"&gt;it&lt;/span&gt; &lt;span class="n"&gt;in&lt;/span&gt; &lt;span class="n"&gt;an&lt;/span&gt; &lt;span class="n"&gt;interim&lt;/span&gt; &lt;span class="n"&gt;state&lt;/span&gt; &lt;span class="n"&gt;between&lt;/span&gt; &lt;span class="n"&gt;migrations&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;

   &lt;span class="o"&gt;!&lt;/span&gt; &lt;span class="n"&gt;You&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;might&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;be&lt;/span&gt; &lt;span class="n"&gt;able&lt;/span&gt; &lt;span class="n"&gt;to&lt;/span&gt; &lt;span class="n"&gt;recover&lt;/span&gt; &lt;span class="n"&gt;with:&lt;/span&gt;   &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ALTER&lt;/span&gt; &lt;span class="n"&gt;TABLE&lt;/span&gt; &lt;span class="sb"&gt;`farzi_app_employee`&lt;/span&gt; &lt;span class="n"&gt;DROP&lt;/span&gt; &lt;span class="n"&gt;COLUMN&lt;/span&gt; &lt;span class="sb"&gt;`salary`&lt;/span&gt; &lt;span class="n"&gt;CASCADE&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="o"&gt;[]&lt;/span&gt;

&lt;span class="o"&gt;!&lt;/span&gt; &lt;span class="n"&gt;The&lt;/span&gt; &lt;span class="n"&gt;South&lt;/span&gt; &lt;span class="n"&gt;developers&lt;/span&gt; &lt;span class="n"&gt;regret&lt;/span&gt; &lt;span class="n"&gt;this&lt;/span&gt; &lt;span class="n"&gt;has&lt;/span&gt; &lt;span class="n"&gt;happened&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="n"&gt;would&lt;/span&gt;
&lt;span class="o"&gt;!&lt;/span&gt; &lt;span class="n"&gt;like&lt;/span&gt; &lt;span class="n"&gt;to&lt;/span&gt; &lt;span class="n"&gt;gently&lt;/span&gt; &lt;span class="n"&gt;persuade&lt;/span&gt; &lt;span class="n"&gt;you&lt;/span&gt; &lt;span class="n"&gt;to&lt;/span&gt; &lt;span class="n"&gt;consider&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="n"&gt;slightly&lt;/span&gt;
&lt;span class="o"&gt;!&lt;/span&gt; &lt;span class="n"&gt;easier&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;to&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;deal&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;with&lt;/span&gt; &lt;span class="n"&gt;DBMS&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;
&lt;span class="o"&gt;!&lt;/span&gt; &lt;span class="n"&gt;NOTE:&lt;/span&gt; &lt;span class="n"&gt;The&lt;/span&gt; &lt;span class="n"&gt;error&lt;/span&gt; &lt;span class="n"&gt;which&lt;/span&gt; &lt;span class="n"&gt;caused&lt;/span&gt; &lt;span class="n"&gt;the&lt;/span&gt; &lt;span class="n"&gt;migration&lt;/span&gt; &lt;span class="n"&gt;to&lt;/span&gt; &lt;span class="n"&gt;fail&lt;/span&gt; &lt;span class="n"&gt;is&lt;/span&gt; &lt;span class="n"&gt;further&lt;/span&gt; &lt;span class="n"&gt;up&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;
   &lt;span class="n"&gt;Traceback&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;most&lt;/span&gt; &lt;span class="n"&gt;recent&lt;/span&gt; &lt;span class="n"&gt;call&lt;/span&gt; &lt;span class="k"&gt;last&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
 &lt;span class="n"&gt;File&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;manage.py&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;line&lt;/span&gt; &lt;span class="mi"&gt;14&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;in&lt;/span&gt; &lt;span class="sr"&gt;&amp;lt;module&amp;gt;&lt;/span&gt;
   &lt;span class="n"&gt;execute_manager&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;settings&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
 &lt;span class="n"&gt;File&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;/usr/local/lib/python2.7/dist-packages/django/core/management/__init__.py&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;line&lt;/span&gt; &lt;span class="mi"&gt;438&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;in&lt;/span&gt; &lt;span class="n"&gt;execute_manager&lt;/span&gt;
   &lt;span class="n"&gt;utility&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;execute&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
 &lt;span class="n"&gt;File&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;/usr/local/lib/python2.7/dist-packages/django/core/management/__init__.py&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;line&lt;/span&gt; &lt;span class="mi"&gt;379&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;in&lt;/span&gt; &lt;span class="n"&gt;execute&lt;/span&gt;
   &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;fetch_command&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;subcommand&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;run_from_argv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;argv&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
 &lt;span class="n"&gt;File&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;/usr/local/lib/python2.7/dist-packages/django/core/management/base.py&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;line&lt;/span&gt; &lt;span class="mi"&gt;191&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;in&lt;/span&gt; &lt;span class="n"&gt;run_from_argv&lt;/span&gt;
   &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;execute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;options&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;__dict__&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
 &lt;span class="n"&gt;File&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;/usr/local/lib/python2.7/dist-packages/django/core/management/base.py&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;line&lt;/span&gt; &lt;span class="mi"&gt;220&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;in&lt;/span&gt; &lt;span class="n"&gt;execute&lt;/span&gt;
   &lt;span class="n"&gt;output&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;handle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;options&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
 &lt;span class="n"&gt;File&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;/usr/local/lib/python2.7/dist-packages/south/management/commands/migrate.py&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;line&lt;/span&gt; &lt;span class="mi"&gt;105&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;in&lt;/span&gt; &lt;span class="n"&gt;handle&lt;/span&gt;
   &lt;span class="n"&gt;ignore_ghosts&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ignore_ghosts&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
 &lt;span class="n"&gt;File&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;/usr/local/lib/python2.7/dist-packages/south/migration/__init__.py&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;line&lt;/span&gt; &lt;span class="mi"&gt;191&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;in&lt;/span&gt; &lt;span class="n"&gt;migrate_app&lt;/span&gt;
   &lt;span class="n"&gt;success&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;migrator&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;migrate_many&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;target&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;workplan&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;database&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
 &lt;span class="n"&gt;File&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;/usr/local/lib/python2.7/dist-packages/south/migration/migrators.py&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;line&lt;/span&gt; &lt;span class="mi"&gt;221&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;in&lt;/span&gt; &lt;span class="n"&gt;migrate_many&lt;/span&gt;
   &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;migrator&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;__class__&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;migrate_many&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;migrator&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;target&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;migrations&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;database&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
 &lt;span class="n"&gt;File&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;/usr/local/lib/python2.7/dist-packages/south/migration/migrators.py&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;line&lt;/span&gt; &lt;span class="mi"&gt;292&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;in&lt;/span&gt; &lt;span class="n"&gt;migrate_many&lt;/span&gt;
   &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;migrate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;migration&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;database&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
 &lt;span class="n"&gt;File&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;/usr/local/lib/python2.7/dist-packages/south/migration/migrators.py&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;line&lt;/span&gt; &lt;span class="mi"&gt;125&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;in&lt;/span&gt; &lt;span class="n"&gt;migrate&lt;/span&gt;
   &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;migration&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
 &lt;span class="n"&gt;File&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;/usr/local/lib/python2.7/dist-packages/south/migration/migrators.py&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;line&lt;/span&gt; &lt;span class="mi"&gt;99&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;in&lt;/span&gt; &lt;span class="n"&gt;run&lt;/span&gt;
   &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;run_migration&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;migration&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
 &lt;span class="n"&gt;File&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;/usr/local/lib/python2.7/dist-packages/south/migration/migrators.py&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;line&lt;/span&gt; &lt;span class="mi"&gt;81&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;in&lt;/span&gt; &lt;span class="n"&gt;run_migration&lt;/span&gt;
   &lt;span class="n"&gt;migration_function&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
 &lt;span class="n"&gt;File&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;/usr/local/lib/python2.7/dist-packages/south/migration/migrators.py&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;line&lt;/span&gt; &lt;span class="mi"&gt;57&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;in&lt;/span&gt; &lt;span class="sr"&gt;&amp;lt;lambda&amp;gt;&lt;/span&gt;
   &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;lambda:&lt;/span&gt; &lt;span class="n"&gt;direction&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;orm&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
 &lt;span class="n"&gt;File&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;/home/akshar/Posts/learnsouth/southlearn/farzi_app/migrations/0002_auto__add_field_employee_salary.py&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;line&lt;/span&gt; &lt;span class="mi"&gt;12&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;in&lt;/span&gt; &lt;span class="n"&gt;forwards&lt;/span&gt;
   &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;add_column&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;farzi_app_employee&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;#39;salary&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;gf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;django.db.models.fields.IntegerField&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)(&lt;/span&gt;&lt;span class="n"&gt;null&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;True&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;keep_default&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;False&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
 &lt;span class="n"&gt;File&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;/usr/local/lib/python2.7/dist-packages/south/db/generic.py&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;line&lt;/span&gt; &lt;span class="mi"&gt;282&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;in&lt;/span&gt; &lt;span class="n"&gt;add_column&lt;/span&gt;
   &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;execute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sql&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
 &lt;span class="n"&gt;File&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;/usr/local/lib/python2.7/dist-packages/south/db/generic.py&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;line&lt;/span&gt; &lt;span class="mi"&gt;150&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;in&lt;/span&gt; &lt;span class="n"&gt;execute&lt;/span&gt;
   &lt;span class="n"&gt;cursor&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;execute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sql&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
 &lt;span class="n"&gt;File&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;/usr/local/lib/python2.7/dist-packages/django/db/backends/util.py&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;line&lt;/span&gt; &lt;span class="mi"&gt;34&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;in&lt;/span&gt; &lt;span class="n"&gt;execute&lt;/span&gt;
   &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;cursor&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;execute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sql&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
 &lt;span class="n"&gt;File&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;/usr/local/lib/python2.7/dist-packages/django/db/backends/mysql/base.py&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;line&lt;/span&gt; &lt;span class="mi"&gt;86&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;in&lt;/span&gt; &lt;span class="n"&gt;execute&lt;/span&gt;
   &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;cursor&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;execute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
 &lt;span class="n"&gt;File&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;/usr/lib/pymodules/python2.7/MySQLdb/cursors.py&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;line&lt;/span&gt; &lt;span class="mi"&gt;166&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;in&lt;/span&gt; &lt;span class="n"&gt;execute&lt;/span&gt;
   &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;errorhandler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;exc&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
 &lt;span class="n"&gt;File&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;/usr/lib/pymodules/python2.7/MySQLdb/connections.py&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;line&lt;/span&gt; &lt;span class="mi"&gt;35&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;in&lt;/span&gt; &lt;span class="n"&gt;defaulterrorhandler&lt;/span&gt;
   &lt;span class="n"&gt;raise&lt;/span&gt; &lt;span class="n"&gt;errorclass&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;errorvalue&lt;/span&gt;
   &lt;span class="n"&gt;_mysql_exceptions&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;OperationalError:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1060&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;Duplicate column name &amp;#39;salary&amp;#39;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;OOPS, you got an error and migration did not run properly. Why this happened?&lt;/p&gt;
&lt;p&gt;South saw the migrations directory and saw three migrations there namely 0001, 0002 and 0003. Then it checked 'south_migrationhistory' table and found out only one row in the table which corresponds to the migration 0001 (remember , we deleted 0002). So, south feels that migration 0002 and 0003 needs to be applied. Remember, 0002 was written to add the column 'salary' to table 'farzi_app_employee'. So while running 0002, south tries adding column 'salary' while actually, that column exists in the database (this was added when we ran migrate for the second time). So, this causes the error. This is evident from the last line of the error we got, which says "_mysql_exceptions.OperationalError: (1060, "Duplicate column name 'salary'")".&lt;/p&gt;
&lt;p&gt;So, we need to FAKE the migration which is causing this error. What we want to do is, we somehow lead south to beleive that migration 0002 has been applied and south should not try to apply this migration next time we run migrate. So, our command will be:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;python&lt;/span&gt; &lt;span class="n"&gt;manage&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;py&lt;/span&gt; &lt;span class="n"&gt;migrate&lt;/span&gt; &lt;span class="n"&gt;farzi_app&lt;/span&gt; &lt;span class="mo"&gt;0002&lt;/span&gt; &lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="n"&gt;fake&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;So what this command did was, it created an entry into 'south_migrationhistory' corresponding to migration 0002. So, south now beleives that 0002 has been applied. But this command did not try to make any changes to the database. So, we did not get any error. Check 'south_migrationhistory', you would again see two rows there each corresponding to migration 0001 and 0002.&lt;/p&gt;
&lt;p&gt;Now, run the migration to add the column 'age', which has to be done by migration 0003.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;python&lt;/span&gt; &lt;span class="n"&gt;manage&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;py&lt;/span&gt; &lt;span class="n"&gt;migrate&lt;/span&gt; &lt;span class="n"&gt;farzi_app&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;This should run without giving any error now. What we talked about --fake was just to see what --fake does, we will see a practical use of --fake in our next scenario, which is eventually my next post.&lt;/p&gt;</description><guid>http://agiliq.com/blog/2012/01/south/</guid></item><item><title>Behind the Scenes: Request to Response</title><link>http://agiliq.com/blog/2012/01/behind-the-scenes-request-to-response/</link><description>&lt;p&gt;In the previous installment of &amp;quot;Behind the Scenes&amp;quot;, we saw how the control flows from &lt;a class="reference external" href="http://agiliq.com/blog/2011/09/behind-the-scenes-from-html-form-to-storage/"&gt;Form to File Storage&lt;/a&gt;. Today, we are going to see how the application reacts from request to response.&lt;/p&gt;
&lt;p&gt;In this post, we are going to assume that we are using django's inbuilt &lt;tt class="docutils literal"&gt;runserver&lt;/tt&gt;. The flow doesn't change much for other WSGI servers available.&lt;/p&gt;
&lt;p&gt;When you invoke the &lt;tt class="docutils literal"&gt;runserver&lt;/tt&gt; management command, the command line options are validated and an instance of &lt;a class="reference external" href="https://code.djangoproject.com/browser/django/trunk/django/core/servers/basehttp.py#L113"&gt;WSGIServer&lt;/a&gt; is created and passed the &lt;a class="reference external" href="https://code.djangoproject.com/browser/django/trunk/django/core/servers/basehttp.py#L130"&gt;WSGIRequestHandler&lt;/a&gt;, which is used to create the request object (&lt;a class="reference external" href="https://code.djangoproject.com/browser/django/trunk/django/core/handlers/wsgi.py#L128"&gt;WSGIRequest&lt;/a&gt;). After the request object is created and the request started signal is fired, the response is fetched through the &lt;a class="reference external" href="https://code.djangoproject.com/browser/django/trunk/django/core/handlers/base.py#L72"&gt;WSGIRequestHandler.get_response(request)&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;In the &lt;tt class="docutils literal"&gt;get_response&lt;/tt&gt; method of the request handler, first the urlconf location (by default the &lt;tt class="docutils literal"&gt;urls.py&lt;/tt&gt;) is setup based on the &lt;tt class="docutils literal"&gt;settings.ROOT_URLCONF&lt;/tt&gt;. Then a &lt;a class="reference external" href="https://code.djangoproject.com/browser/django/trunk/django/core/urlresolvers.py#L219"&gt;RegexURLResolver&lt;/a&gt; compiles the regular expressions in the urlconf file. Next, the request middlewares are called in the order specified in the &lt;tt class="docutils literal"&gt;settings.MIDDLEWARE_CLASSES&lt;/tt&gt; followed by the view middlewares after matching the view (&lt;tt class="docutils literal"&gt;callback&lt;/tt&gt;) function against the compiled regular expressions from the urlconf. Then the view (&lt;tt class="docutils literal"&gt;callback&lt;/tt&gt;) is invoked and verified that it does not return &lt;tt class="docutils literal"&gt;None&lt;/tt&gt; before calling the response middlewares.&lt;/p&gt;
&lt;p&gt;You can see the pictorial representation of the flow below:&lt;/p&gt;
&lt;a class="reference external image-reference" href="http://agiliq.com/static/dumps/images/20120102/request_to_response.png"&gt;&lt;img alt="Request to Response Flow" class="align-center" src="http://agiliq.com/static/dumps/images/20120102/request_to_response.png" style="width: 543px; height: 792px;" /&gt;&lt;/a&gt;
</description><guid>http://agiliq.com/blog/2012/01/behind-the-scenes-request-to-response/</guid></item><item><title>Haml for Django developers</title><link>http://agiliq.com/blog/2011/12/haml-for-django-developers/</link><description>&lt;p&gt;Haml is taking the Ruby(and Rails) world by storm. Its not used as heavily by Python(and Django) developers as the Python solutions aren't as mature. I &lt;em&gt;finally&lt;/em&gt; gave Haml a try and was pleasantly surprised how easy it was.&lt;/p&gt;
&lt;p&gt;The most mature Python implementation of &lt;a href="https://github.com/jessemiller/HamlPy"&gt;Haml is hamlpy&lt;/a&gt;, which converts the hamlpy code to Django templates.
Others are &lt;a href="http://shpaml.webfactional.com/"&gt;shpaml&lt;/a&gt; and &lt;a href="https://github.com/derdon/ghrml"&gt;GHRML&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Lets look at some templates from &lt;a href="https://docs.djangoproject.com/en/1.2/intro/tutorial03/"&gt;Django tutorial&lt;/a&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="cp"&gt;{%&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nv"&gt;latest_poll_list&lt;/span&gt; &lt;span class="cp"&gt;%}&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;ul&amp;gt;&lt;/span&gt;
    &lt;span class="cp"&gt;{%&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="nv"&gt;poll&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="nv"&gt;latest_poll_list&lt;/span&gt; &lt;span class="cp"&gt;%}&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;li&amp;gt;&amp;lt;a&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;/polls/&lt;/span&gt;&lt;span class="cp"&gt;{{&lt;/span&gt; &lt;span class="nv"&gt;poll.id&lt;/span&gt; &lt;span class="cp"&gt;}}&lt;/span&gt;&lt;span class="s"&gt;/&amp;quot;&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;{{&lt;/span&gt; &lt;span class="nv"&gt;poll.question&lt;/span&gt; &lt;span class="cp"&gt;}}&lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;&lt;/span&gt;
    &lt;span class="cp"&gt;{%&lt;/span&gt; &lt;span class="k"&gt;endfor&lt;/span&gt; &lt;span class="cp"&gt;%}&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/ul&amp;gt;&lt;/span&gt;
&lt;span class="cp"&gt;{%&lt;/span&gt; &lt;span class="k"&gt;endif&lt;/span&gt; &lt;span class="cp"&gt;%}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Here is this template converted to Haml&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;latest_poll_list&lt;/span&gt;
 &lt;span class="nv"&gt;%ul&lt;/span&gt; 
  &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;poll&lt;/span&gt; &lt;span class="n"&gt;in&lt;/span&gt; &lt;span class="n"&gt;latest_poll_list&lt;/span&gt; 
    &lt;span class="nv"&gt;%li&lt;/span&gt;
        &lt;span class="nv"&gt;%a&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;href&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;/polls/{{ poll.id }}&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;poll&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;question&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;You can see that this lost a lot of noise from the Django template. Being a Django programmer,
significant whitespace is very pleasing.&lt;/p&gt;
&lt;p&gt;Here is another one from the same tutorial.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="nt"&gt;&amp;lt;h1&amp;gt;&lt;/span&gt;{{ poll.question }}&lt;span class="nt"&gt;&amp;lt;/h1&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;ul&amp;gt;&lt;/span&gt;
{% for choice in poll.choice_set.all %}
    &lt;span class="nt"&gt;&amp;lt;li&amp;gt;&lt;/span&gt;{{ choice.choice }}&lt;span class="nt"&gt;&amp;lt;/li&amp;gt;&lt;/span&gt;
{% endfor %}
&lt;span class="nt"&gt;&amp;lt;/ul&amp;gt;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;And converted to hamlpy&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="c"&gt;%h1&lt;/span&gt;
    &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;poll&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;question&lt;/span&gt;
&lt;span class="c"&gt;%ul&lt;/span&gt;
    &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;choice&lt;/span&gt; &lt;span class="n"&gt;in&lt;/span&gt; &lt;span class="n"&gt;poll&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;choice_set&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;all&lt;/span&gt;
        &lt;span class="c"&gt;%li&lt;/span&gt;
            &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;choice&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;choice&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Again, I lose a lot of noise from the templates, and the signifiant whitespace improve the chance that the out put would be valid html.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://github.com/shabda/django-haml-examples"&gt;Here are a few more templates&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;In particular see &lt;a href="https://github.com/shabda/django-haml-examples/blob/master/6.haml"&gt;this&lt;/a&gt; which is haml for &lt;a href="https://github.com/pinax/pinaxproject.com/blob/master/pinaxsite_project/templates/biblion/blog_base.html"&gt;this Pinax file&lt;/a&gt;&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;Resource&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a href="http://haml-lang.com/"&gt;Haml&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/jessemiller/HamlPy"&gt;Hamlpy&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;</description><guid>http://agiliq.com/blog/2011/12/haml-for-django-developers/</guid></item><item><title>Behind the Scenes: From HTML Form to Storage</title><link>http://agiliq.com/blog/2011/09/behind-the-scenes-from-html-form-to-storage/</link><description>&lt;p&gt;In this post, we are going to see what happens behind the scenes when a file is uploaded to a django powered web application.&lt;/p&gt;
&lt;a class="reference external image-reference" href="http://agiliq.com/dumps/images/20110921/file_storage.gif"&gt;&lt;div align="center" class="align-center"&gt;&lt;img alt="File Upload Flow" class="align-center" src="http://agiliq.com/dumps/images/20110921/file_storage.gif" style="width: 543px; height: 792px;" /&gt;&lt;/div&gt;
&lt;/a&gt;
&lt;p&gt;An HTML form with a file input (atleast one) and encoding set to &lt;a class="reference external" href="https://docs.djangoproject.com/en/dev/ref/forms/api/#binding-uploaded-files"&gt;multipart/form-data&lt;/a&gt; is submitted. The &lt;a class="reference external" href="https://code.djangoproject.com/browser/django/trunk/django/http/multipartparser.py#L31"&gt;MultiPartParser&lt;/a&gt; parses the POST request and returns a tuple of the POST and FILES data &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;(request.POST,&lt;/span&gt; &lt;span class="pre"&gt;request.FILES)&lt;/span&gt;&lt;/tt&gt;. The MultiPartParser processes the uploaded data using the &lt;a class="reference external" href="https://docs.djangoproject.com/en/dev/topics/http/file-uploads/#upload-handlers"&gt;File Upload Handlers&lt;/a&gt; objects (through the &lt;a class="reference external" href="https://code.djangoproject.com/browser/django/trunk/django/core/files/uploadhandler.py#L87"&gt;new_file&lt;/a&gt;, &lt;a class="reference external" href="https://code.djangoproject.com/browser/django/trunk/django/core/files/uploadhandler.py#L100"&gt;receive_data_chunk&lt;/a&gt; and &lt;a class="reference external" href="https://code.djangoproject.com/browser/django/trunk/django/core/files/uploadhandler.py#L116"&gt;upload_complete&lt;/a&gt; methods). The &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;request.FILES&lt;/span&gt;&lt;/tt&gt; values are a sequence of instances of &lt;a class="reference external" href="https://docs.djangoproject.com/en/dev/topics/http/file-uploads/#uploadedfile-objects"&gt;UploadedFile&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;In the django form, we pass the &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;request.FILES&lt;/span&gt;&lt;/tt&gt; MultiValueDict. These UploadedFile instances are validated by the &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;full_clean&lt;/span&gt;&lt;/tt&gt; method on the &lt;a class="reference external" href="https://docs.djangoproject.com/en/dev/ref/forms/api/"&gt;Form&lt;/a&gt;. The &lt;a class="reference external" href="https://code.djangoproject.com/browser/django/trunk/django/forms/forms.py#L254"&gt;full_clean&lt;/a&gt; method in turn calls the &lt;a class="reference external" href="https://code.djangoproject.com/browser/django/trunk/django/forms/forms.py#L273"&gt;_clean_fields&lt;/a&gt; method which calls the &lt;a class="reference external" href="https://code.djangoproject.com/browser/django/trunk/django/forms/fields.py#L493"&gt;clean&lt;/a&gt; method on the &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;forms.FileField&lt;/span&gt;&lt;/tt&gt; and checks if the data is empty.&lt;/p&gt;
&lt;p&gt;After the form is successfully validated, we might assign and save the &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;cleaned_data&lt;/span&gt;&lt;/tt&gt; of the form to a model instance (or by saving the &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;ModelForm&lt;/span&gt;&lt;/tt&gt;). When the &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;save&lt;/span&gt;&lt;/tt&gt; method on the model instance is called, the &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;save_base&lt;/span&gt;&lt;/tt&gt; method calls a &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;pre_save&lt;/span&gt;&lt;/tt&gt; method on each field of the model. This &lt;a class="reference external" href="https://code.djangoproject.com/browser/django/trunk/django/db/models/fields/files.py#L244"&gt;pre_save&lt;/a&gt; method returns the value of the file instance bound to that FileField and calls it's &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;save&lt;/span&gt;&lt;/tt&gt; method. This &lt;a class="reference external" href="https://code.djangoproject.com/browser/django/trunk/django/db/models/fields/files.py#L84"&gt;save&lt;/a&gt; method (on the models.FileField) in turn calls the &lt;a class="reference external" href="https://code.djangoproject.com/browser/django/trunk/django/core/files/storage.py#L34"&gt;save (Storage)&lt;/a&gt; method on the &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;Storage&lt;/span&gt;&lt;/tt&gt; which is either picked up from the arguments passed to the FileField (&lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;FileField(storage=...)&lt;/span&gt;&lt;/tt&gt;) or the &lt;a class="reference external" href="https://docs.djangoproject.com/en/dev/ref/settings/#std:setting-DEFAULT_FILE_STORAGE"&gt;DEFAULT_FILE_STORAGE&lt;/a&gt; settings attribute.&lt;/p&gt;
&lt;p&gt;This is the flow from the HTML Form all the way upto the File Storage. Hope you liked it.&lt;/p&gt;
</description><guid>http://agiliq.com/blog/2011/09/behind-the-scenes-from-html-form-to-storage/</guid></item><item><title>Real time applications with Django, XMPP and StropheJS</title><link>http://agiliq.com/blog/2010/12/real-time-applications-with-django-xmpp-and-stroph/</link><description>&lt;div class="section" id="tl-dr"&gt;
&lt;h1&gt;TL;DR:&lt;/h1&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;django-pubsub allows you to create Twitter like real-time updates for your models with Admin like ease.&lt;/li&gt;
&lt;li&gt;Demo at &lt;a class="reference external" href="http://chat.agiliq.com/pubsub/"&gt;http://chat.agiliq.com/pubsub/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Code at &lt;a class="reference external" href="https://github.com/agiliq/django-pubsub"&gt;https://github.com/agiliq/django-pubsub&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class="section" id="introduction"&gt;
&lt;h1&gt;Introduction:&lt;/h1&gt;
&lt;p&gt;PubSub is a XMPP extension which allows publishing and subscribing to events.
This is useful when you instantly want to notify many clients about something
interesting happening on your server.&lt;/p&gt;
&lt;p&gt;Quoting the authors of &lt;a class="reference external" href="http://xmpp.org/extensions/xep-0060.html"&gt;PubSub specs&lt;/a&gt;:&lt;/p&gt;
&lt;pre class="literal-block"&gt;
The protocol enables XMPP entities to create nodes (topics) at a
pubsub service and publish information at those nodes; an event
notification (with or without payload) is then broadcasted to all
entities that have subscribed to the node. Pubsub therefore
adheres to the classic Observer design pattern and can serve as
the foundation for a wide variety of applications, including news
feeds, content syndication, rich presence, geolocation, workflow
systems, network management systems, and any other application
that requires event notifications.
&lt;/pre&gt;
&lt;p&gt;To understand this better, think of newspapers as publishers and the
people who subscribe to the newspapers as subscribers. Getting your
daily newspaper is similar to checking your RSS feeds because you
only get information at regular intervals. (Of course you could keep
buying newspapers every 'x' hours, i.e. keep refreshing your RSS
reader so often). This is as inefficient as it sounds. For
instance, you never know if a newspaper actually has new stuff, you
need to buy and read it before you realize there's nothing new. And
there will be always be a delay (unless you are really lucky) between
the time something happens and you read it in the your 'n'th
newspaper of the day.&lt;/p&gt;
&lt;p&gt;PubSub solves this problem by having a system where subscribers subscribe to
nodes and the publisher notifies its subscribers when something happens. Nodes
are like TV channels, so you only subscribe to the channels you are interested
in.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="how-it-can-be-useful-to-you"&gt;
&lt;h1&gt;How it can be useful to you:&lt;/h1&gt;
&lt;p&gt;In addition to the points mentioned in the quote, pubSub can be used
in your project to send instant notifications, maintain the same
state across multiple sessions, or monitor live activity.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="introducing-django-pubsub"&gt;
&lt;h1&gt;Introducing django-pubsub:&lt;/h1&gt;
&lt;p&gt;&lt;a class="reference external" href="https://github.com/agiliq/django-pubsub"&gt;django-pubsub&lt;/a&gt; allows you write PubSub enabled applications easily.&lt;/p&gt;
&lt;p&gt;&lt;a class="reference external" href="http://chat.agiliq.com/pubsub/"&gt;This demo&lt;/a&gt; using django-pubsub shows how to use the module. The stack used
in the demo is:&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;fcgi&lt;/li&gt;
&lt;li&gt;nginx&lt;/li&gt;
&lt;li&gt;ejabberd with mod_http_bind and mod_pubsub&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;You can register a model with the pubsub app and all registered models
will automatically send out notification (with the payload) on &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;save&lt;/span&gt;&lt;/tt&gt;
to the default node.&lt;/p&gt;
&lt;p&gt;Then you can use the PubSub client provided in &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;media&lt;/span&gt;&lt;/tt&gt; to subscribe and
receive events from the registered models.&lt;/p&gt;
&lt;p&gt;The default payload includes an XML serialized instance of the model.
You can use jquery to extract required &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;fields&lt;/span&gt;&lt;/tt&gt; from the payload.&lt;/p&gt;
&lt;p&gt;You can also directly use &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;pubsub.publish&lt;/span&gt;&lt;/tt&gt; to publish any item to any
node. An example is provided in the demo included with the app.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="how-it-works"&gt;
&lt;h1&gt;How it works:&lt;/h1&gt;
&lt;p&gt;Since XMPP and HTTP speak different languages, you need some kind of a
bridge to connect these two. This can be achieved using &lt;a class="reference external" href="http://en.wikipedia.org/wiki/BOSH"&gt;BOSH&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The BOSH bridge is provided by ejabberd's &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;mod_http_bind&lt;/span&gt;&lt;/tt&gt;
module. (You can also use &lt;a class="reference external" href="https://github.com/twonds/punjab"&gt;Punjab&lt;/a&gt; for this purpose)&lt;/p&gt;
&lt;p&gt;If you are using mod_http_bind, you will also need to setup
appropriate url forwarding using nginx because mod_http_bind listens
on the port 5280 and will not be able to communicate with the client
on port 8080.&lt;/p&gt;
&lt;p&gt;Strophe will use the BOSH url to talk to ejabberd. Our PubSub
client which is written using Strophe will then be able to subscribe
and receive notifications from the server.&lt;/p&gt;
&lt;p&gt;On the server side, the pubsub app uses xmpppy to send out the correct &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;Iq&lt;/span&gt;&lt;/tt&gt;
stanzas on &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;save&lt;/span&gt;&lt;/tt&gt; or &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;publish&lt;/span&gt;&lt;/tt&gt;. The client will receive these stanzas
on subscribing to the appropriate node.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="conclusion"&gt;
&lt;h1&gt;Conclusion:&lt;/h1&gt;
&lt;p&gt;If your app needs real-time updates, push notifications, and scalable
infrastructure, you can make use of XMPP and Strophejs.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="references"&gt;
&lt;h1&gt;References:&lt;/h1&gt;
&lt;p&gt;ejabberd's blog post on related topic:&lt;/p&gt;
&lt;p&gt;&lt;a class="reference external" href="http://www.process-one.net/en/blogs/article/introducing_the_xmpp_application_server"&gt;http://www.process-one.net/en/blogs/article/introducing_the_xmpp_application_server&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;a similar project using comet, orbit and twisted instead of xmpp:&lt;/p&gt;
&lt;p&gt;&lt;a class="reference external" href="http://www.clemesha.org/blog/realtime-web-apps-python-django-orbited-twisted"&gt;http://www.clemesha.org/blog/realtime-web-apps-python-django-orbited-twisted&lt;/a&gt;&lt;/p&gt;
&lt;/div&gt;
</description><guid>http://agiliq.com/blog/2010/12/real-time-applications-with-django-xmpp-and-stroph/</guid></item><item><title>Seven reasons why you should switch to Vim</title><link>http://agiliq.com/blog/2010/11/seven-reasons-why-you-should-switch-to-vim-for-dja/</link><description>&lt;p&gt;So you want a better IDE for developing django, huh? Why not give good old vim a try?&lt;/p&gt;
&lt;p&gt;Use &lt;a href="https://github.com/tpope/vim-pathogen"&gt;pathogen&lt;/a&gt; to maintain your vim plugins (and sanity).
Using this, you can clone the repositories listed here to &lt;code&gt;.vim/bundle/&lt;/code&gt; and start using them
right away.&lt;/p&gt;
&lt;p&gt;Also, consider adding your &lt;code&gt;.vimrc&lt;/code&gt; and &lt;code&gt;.vim&lt;/code&gt; to a repository. Include &lt;code&gt;.vimrc&lt;/code&gt; inside &lt;code&gt;.vim&lt;/code&gt; and
symlink &lt;code&gt;.vim/.vimrc&lt;/code&gt; to &lt;code&gt;~/.vimrc&lt;/code&gt; to version control your &lt;code&gt;.vimrc&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;My vim files can be found &lt;a href="https://github.com/tuxcanfly/CalVIM"&gt;here&lt;/a&gt;. Also, here's an &lt;a href="http://imgur.com/a/MEYkV/1"&gt;imgur album&lt;/a&gt; demonstrating
these plugins in action.&lt;/p&gt;
&lt;h2&gt;1. Syntax highlighting for django templates&lt;/h2&gt;
&lt;p&gt;Starting from vim 7.1, syntax highlight for django templates works out
of the box. (Check your vim version using &lt;code&gt;vim --version&lt;/code&gt; or &lt;code&gt;:version&lt;/code&gt; within vim)&lt;/p&gt;
&lt;p&gt;If you are on an older version, use &lt;a href="http://www.vim.org/scripts/script.php?script_id=1487"&gt;this plugin&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;2. Django snippets with snipmate&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://github.com/msanders/snipmate.vim"&gt;SnipMate&lt;/a&gt; provides commonly used "snippets". This eliminates a lot of
boiler plate code genreally required to start a django project from scratch.&lt;/p&gt;
&lt;p&gt;Django specific snippets can be found at &lt;a href="https://github.com/robhudson/snipmate_for_django"&gt;robhudson's repository&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Its very easy to write custom snippets in case you need them.&lt;/p&gt;
&lt;h2&gt;3. On-the-fly error checking with pyflakes&lt;/h2&gt;
&lt;p&gt;This one is not django specific, but it can save a lot of time spent debugging typos or silly mistakes.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://github.com/kevinw/pyflakes-vim"&gt;PyFlakes&lt;/a&gt; detects errors in your python code and highlights the 
offending lines so you can easily rectify them.&lt;/p&gt;
&lt;h2&gt;4. Git integration with fugitive&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://github.com/tpope/vim-fugitive"&gt;Fugitive&lt;/a&gt; is a git plugin for vim.&lt;/p&gt;
&lt;p&gt;This one integrates seamlessly with my workflow. You can add/reset files, commit them, view diff, blame, logs all 
within vim!&lt;/p&gt;
&lt;h2&gt;5. Auto-completion using pysmell&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://github.com/orestis/pysmell"&gt;Pysmell&lt;/a&gt; is great for autocompleting your django project code.&lt;/p&gt;
&lt;h2&gt;6. Browse code with taglist&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://github.com/mexpolk/vim-taglist"&gt;Taglist&lt;/a&gt; allows you to view your code structure and jump between
classes/functions.&lt;/p&gt;
&lt;h2&gt;7. Write faster html using sparkup&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://github.com/bingaman/vim-sparkup"&gt;Sparkup&lt;/a&gt; allows you write &lt;a href="http://code.google.com/p/zen-coding/"&gt;zen code&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;Other tips:&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;set &lt;code&gt;makeprg&lt;/code&gt; to &lt;code&gt;python manage.py syncdb&lt;/code&gt;. Run &lt;code&gt;:make&lt;/code&gt; from your vim to start &lt;code&gt;syncdb&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;use &lt;a href="https://github.com/scrooloose/nerdtree"&gt;nerdtree&lt;/a&gt;/&lt;a href="https://github.com/vim-scripts/LustyExplorer"&gt;lusty explorer&lt;/a&gt; for file
management&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;use &lt;a href="https://github.com/tuxcanfly/ViMango"&gt;vimango&lt;/a&gt; for navigating your django project&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;</description><guid>http://agiliq.com/blog/2010/11/seven-reasons-why-you-should-switch-to-vim-for-dja/</guid></item><item><title>Importing wordpress</title><link>http://agiliq.com/blog/2010/10/importing-wordpress/</link><description>&lt;p&gt;We now have a way to import &lt;a href="http://github.com/agiliq/django-wordpress/blob/master/wp/management/commands/import_to_blogango.py"&gt;wordpress to blogango&lt;/a&gt;, and all our old posts are on this blog.&lt;/p&gt;
&lt;p&gt;Thanks for reading.&lt;/p&gt;</description><guid>http://agiliq.com/blog/2010/10/importing-wordpress/</guid></item><item><title>Getting trending Github projects via YQL</title><link>http://agiliq.com/blog/2010/10/getting-trending-github-projects-via/</link><description>&lt;p&gt;&lt;a href="http://github.com/explore"&gt;Github.com/explore&lt;/a&gt; allows you to see the trending Github topics. They use &lt;a href="http://repopular.com/"&gt;repopular.com&lt;/a&gt; for this,
which use twitter retweets to find out the popular Github repos.&lt;/p&gt;
&lt;p&gt;Since neither Repopular, nor Github have a RSS of these trending repos, I wanted to get a list of these. Here is how easy it is with 
&lt;a href="http://developer.yahoo.com/yql/"&gt;YQL&lt;/a&gt;.&lt;/p&gt;
&lt;script src="http://gist.github.com/643959.js?file=repopular_projects.py"&gt;&lt;/script&gt;

&lt;h2&gt;How we do it&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Go to &lt;a href="http://developer.yahoo.com/yql/console/?q=use%20&amp;apos;http://yqlblog.net/samples/data.html.cssselect.xml&amp;apos;%20as%20data.html.cssselect;%20select%20*%20from%20data.html.cssselect%20where%20url%3D%22www.yahoo.com%22%20and%20css%3D%22%23news%20a%22#h=use%20%27http%3A//yqlblog.net/samples/data.html.cssselect.xml%27%20as%20data.html.cssselect%3B%20select%20*%20from%20data.html.cssselect%20where%20url%3D%22repopular.com%22%20and%20css%3D%22div.bd%20a%22"&gt;YQL console&lt;/a&gt;. Give the SQL query to get the data from the webpage. &lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;where url="repopular.com" and css="div.pad a"&lt;/code&gt; is the magic which select the webpage, and also what DOM elemenst we are interested in.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;We get this data in JSON format which is munged to get the list of links.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;This list of links is passed via &lt;code&gt;is_github_project&lt;/code&gt; which gets me just the Github projects.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;And we are done.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;script src="http://gist.github.com/643970.js?file=gistfile1.txt"&gt;&lt;/script&gt;

&lt;p&gt;PS. &lt;a href="http://developer.yahoo.com/yql/"&gt;YQL&lt;/a&gt; is amazing.&lt;/p&gt;</description><guid>http://agiliq.com/blog/2010/10/getting-trending-github-projects-via/</guid></item><item><title>Django is not flexible</title><link>http://agiliq.com/blog/2010/10/django-is-not-flexible/</link><description>&lt;p&gt;Django is not flexible at all because you can not do simple
things like. &lt;br /&gt;
&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Using various authentication mechanisms.&lt;br /&gt;
You can authenticate via &lt;a href="http://docs.djangoproject.com/en/dev/topics/auth/#authentication-in-web-requests"&gt;Username&lt;/a&gt;,
&lt;a href="http://www.davidcramer.net/code/224/logging-in-with-email-addresses-in-django.html"&gt;emails&lt;/a&gt;,
&lt;a href="http://github.com/agiliq/Django-Socialauth"&gt;Facebook, Twitter&lt;/a&gt; or any combination of these.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Using different database backends.&lt;br /&gt;
Use MySQL, PostgreSQL,
&lt;a href="http://www.allbuttonspressed.com/projects/djangoappengine"&gt;Non-relational databases&lt;/a&gt;,
&lt;a href="http://docs.djangoproject.com/en/dev/ref/databases/#using-a-3rd-party-database-backend"&gt;more&lt;/a&gt;
or a &lt;a href="http://docs.djangoproject.com/en/dev/topics/db/multi-db/"&gt;combination&lt;/a&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Use different mail sending strategies.&lt;br /&gt;
Send mail via &lt;a href="http://docs.djangoproject.com/en/dev/topics/email/#smtp-backend"&gt;smtp&lt;/a&gt;,
&lt;a href="http://github.com/jtauber/django-mailer"&gt;queue to database&lt;/a&gt;,
&lt;a href="http://docs.djangoproject.com/en/dev/topics/email/#file-backend"&gt;log to files&lt;/a&gt;
and more.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Different file storage method.&lt;br /&gt;
Store locally, &lt;a href="http://djangosnippets.org/snippets/1269/"&gt;FTP&lt;/a&gt;,
&lt;a href="http://code.welldev.org/django-storages/wiki/S3Storage"&gt;Amazon S3&lt;/a&gt;
or &lt;a href="http://docs.djangoproject.com/en/dev/howto/custom-file-storage/"&gt;write your own&lt;/a&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Store messages in &lt;a href="http://docs.djangoproject.com/en/dev/ref/contrib/messages/#storage-backends"&gt;Sessions, cookies or others&lt;/a&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Cache things in &lt;a href="http://docs.djangoproject.com/en/dev/topics/cache/#filesystem-caching"&gt;Files&lt;/a&gt;,
&lt;a href="http://docs.djangoproject.com/en/dev/topics/cache/#database-caching"&gt;DB&lt;/a&gt;,
&lt;a href="http://docs.djangoproject.com/en/dev/topics/cache/#memcached"&gt;Memcache&lt;/a&gt;
or &lt;a href="http://docs.djangoproject.com/en/dev/topics/cache/#dummy-caching-for-development"&gt;just fake it&lt;/a&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Save sessions in files, DB, Memcache or cookies.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Use &lt;a href="http://www.davidcramer.net/code/479/using-jinja2-with-django.html"&gt;Jinja&lt;/a&gt;,
&lt;a href="http://djangosnippets.org/snippets/97/"&gt;Mako or Gensi&lt;/a&gt; as templating library.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;p&gt;One of the most lingering criticisms of Django has been
that it is not flexible. People have criticised its design
as too-tightly coupled, hard to extend, and inflexible.
As a result, people have recommended to roll their own
using SQLchemy, Jinja or web.py.&lt;br /&gt;
&lt;/p&gt;
&lt;p&gt;I think this view is unfounded and wrong. You would be hard
pressed to get the choices and flexibility which Django offers.
Eg, while development I run with Sqlite, Dummy caching, and emails
on console, while on production I switch to PostgreSQL, Memcache, and
queued emails.&lt;br /&gt;
&lt;/p&gt;
&lt;p&gt;Many apps use this backend pattern themselves.
&lt;a href="http://docs.b-list.org/django-registration/0.8/backend-api.html"&gt;Django registeration&lt;/a&gt;,
&lt;a href="http://ask.github.com/celery/getting-started/first-steps-with-django.html"&gt;Django-celery&lt;/a&gt;
and our own &lt;a href="http://github.com/agiliq/merchant"&gt;merchant&lt;/a&gt;.&lt;br /&gt;
&lt;/p&gt;
&lt;p&gt;I have always been annoyed at Django is inflexible meme, and the recent 
&lt;a href="http://charlesleifer.com/blog/django-patterns-pluggable-backends/"&gt;Charles Leifer's post&lt;/a&gt;
put various Django plug points to make writing this too post easy to not do it.&lt;br /&gt;
&lt;/p&gt;</description><guid>http://agiliq.com/blog/2010/10/django-is-not-flexible/</guid></item><item><title>Rails and Django commands : comparison  and conversion</title><link>http://agiliq.com/blog/2010/03/rails-and-django-commands-comparison-and-conversio/</link><description>&lt;p&gt;The most commonly used Rails commands and their Django equivalents&lt;/p&gt;
&lt;h2&gt;Rails                   | Django&lt;/h2&gt;
&lt;p&gt;rails console            | manage.py shell                 &lt;br /&gt;
rails server             | manage.py runserver                &lt;br /&gt;
rake                     | None                            &lt;br /&gt;
rails generate           | None                            &lt;br /&gt;
rails dbconsole          | manage.py dbshell               &lt;br /&gt;
rails app_name           | django-admin.py startproject/manage.py startapp          &lt;br /&gt;
rake db:create           | manage.py syncdb    &lt;br /&gt;
&lt;/p&gt;
&lt;p&gt;The salient points to note are,&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Django has all commands via &lt;code&gt;manage.py&lt;/code&gt;, Rails has it broken into &lt;code&gt;rails&lt;/code&gt; and &lt;code&gt;rake&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Overall there are more Rails+Rake commands available than Django commands&lt;/li&gt;
&lt;li&gt;There is no one to one mapping between Rails and Django commands.
Eg. There are no equivalent to rake doc:* or rake notes in Django.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Similarly there is no equivalent to &lt;code&gt;manage.py createsuperuser&lt;/code&gt; in rails.&lt;/p&gt;
&lt;h4&gt;References&lt;/h4&gt;
&lt;p&gt;&lt;a href="http://docs.djangoproject.com/en/dev/ref/django-admin/"&gt;http://docs.djangoproject.com/en/dev/ref/django-admin/&lt;/a&gt;
&lt;a href="http://guides.rails.info/command_line.html"&gt;http://guides.rails.info/command_line.html&lt;/a&gt;
&lt;a href="http://github.com/uswaretech/Acts-as-Django/blob/master/commands.markdown"&gt;http://github.com/uswaretech/Acts-as-Django/blob/master/commands.markdown&lt;/a&gt;&lt;/p&gt;</description><guid>http://agiliq.com/blog/2010/03/rails-and-django-commands-comparison-and-conversio/</guid></item><item><title>Doing things with Django models - aka - Django models tutorial</title><link>http://agiliq.com/blog/2010/01/doing-things-with-django-models-aka-django-models-/</link><description>&lt;p&gt;Django abstracts most of the actions you would be doing with the Database.
What it doesn't abstracts, and doesn't try to abstract is the Database modelling part. This is a quick tutorial
describing to how model your data in Django models.py, and how to access and modify them.&lt;/p&gt;
&lt;p&gt;Consider a hypothetical HR department, which wants you to build an application to track and manage their processes.
They have employees who work for a department, contractors who work for multiple department. Let's see how you
you would do that in Django.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;from django.db import models

class Employee(models.Model):
    name = models.CharField(max_length = 100)
    department = models.ForeignKey(&amp;quot;Department&amp;quot;)

class Department(models.Model):
    name = models.CharField(max_length = 100)

class EmployeeHistory(models.Model):
    employee = models.OneToOneField(Employee)
    date_joined = models.DateField()
    marital_status = models.BooleanField()

class Contactor(models.Model):
    name = models.CharField(max_length = 100)
    departments = models.ManyToManyField(Department)
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Let's see the type of relationship we created here.&lt;/p&gt;
&lt;p&gt;An &lt;code&gt;Employee&lt;/code&gt; has a Many-to-one relationship with &lt;code&gt;Department&lt;/code&gt;, (i.e. One department will have many
&lt;code&gt;Employee&lt;/code&gt;, but one employee will have a single departments.)&lt;/p&gt;
&lt;p&gt;So &lt;code&gt;Employee&lt;/code&gt; has a field &lt;code&gt;department = models.ForeignKey("Department")&lt;/code&gt;. See that the &lt;code&gt;ForeignKey&lt;/code&gt; field
was added on the class which has in &lt;em&gt;many&lt;/em&gt;. In database, this creates a FK from in &lt;code&gt;Employee&lt;/code&gt; table which refernces
&lt;code&gt;Departments&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;A &lt;code&gt;Contractor&lt;/code&gt; has many-to-many relationships with &lt;code&gt;Department&lt;/code&gt;, so it has a &lt;code&gt;ManyToMany&lt;/code&gt; field. This field can be created
on either classes. At a database level this creates a new table which has a FK to both the tables.&lt;/p&gt;
&lt;p&gt;A &lt;code&gt;Employee&lt;/code&gt; has one-to-one relationship with &lt;code&gt;EmployeeHistory&lt;/code&gt;. The thing to note here is that whatever we could do with
OneToOneField, we can do by including the fields in the Other Class directly. However when there are fields which are only rarely
needed with a given model, it is useful to separate them via a one-to-one field. The one to one field can be on either class.&lt;/p&gt;
&lt;h4&gt;Accessing objects.&lt;/h4&gt;
&lt;h5&gt;Getting a specific employee.&lt;/h5&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;Employee.objects.get(pk = someval)
Employee.objects.get(name= someval)
&lt;/pre&gt;&lt;/div&gt;


&lt;h5&gt;Given an department get all employees.&lt;/h5&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;department.employee_set.all()
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;The &lt;code&gt;department&lt;/code&gt; gets an attribute name &lt;code&gt;&amp;lt;FKClass&amp;gt;_set&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Given an employee, get all colleagues.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;employee.department.employee_set.objects.all()
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;To get siblings, get parents, and get all children.&lt;/p&gt;
&lt;p&gt;Given an department, get number of employees.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;department.employee_set.all().count()
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Ok so the HR department bosses are happy with what they see, and ask you to track this data,
who is the manager of each employee, who is the HOD of each department and when did each employee took leave.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;from django.db import models

class Employee(models.Model):
    name = models.CharField(max_length = 100)
    manager = models.ForeignKey(&amp;quot;self&amp;quot;, blank = True, null = True)
    department = models.ForeignKey(&amp;quot;Department&amp;quot;)

class Department(models.Model):
    hod = models.ForeignKey(&amp;quot;Employee&amp;quot;)
    name = models.CharField(max_length = 100)

class EmployeeHistory(models.Model):
    employee = models.OneToOneField(Employee)
    date_joined = models.DateField()
    marital_status = models.BooleanField()

class Contactors(models.Model):
    name = models.CharField(max_length = 100)
    departments = models.ManyToManyField(Department)

class EmployeeLeave(models.Model):
    leave_taken = models.DateField()
    employee = models.ForeignKey(Employee)
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;So we now have new fields &lt;code&gt;hod = models.OneToOneField("Employee")&lt;/code&gt; in department and
&lt;code&gt;manager = models.ForeignKey("self", blank = True, null = True)&lt;/code&gt; and a new model &lt;code&gt;EmployeeLeave&lt;/code&gt;. Let su see
the new realtions,&lt;/p&gt;
&lt;p&gt;As one &lt;code&gt;Department&lt;/code&gt; will have one &lt;code&gt;Employee&lt;/code&gt; as hod, and &lt;code&gt;Employee&lt;/code&gt; can head at max one &lt;code&gt;Department&lt;/code&gt;, we have a one to one relationship&lt;br /&gt;
As many &lt;code&gt;Employee&lt;/code&gt; will report to another &lt;code&gt;Employee&lt;/code&gt;, so we have a FK on &lt;code&gt;Employee&lt;/code&gt;, referencing &lt;code&gt;self&lt;/code&gt;.
As &lt;code&gt;Employee&lt;/code&gt; will take many &lt;code&gt;EmployeeLeave&lt;/code&gt;, &lt;code&gt;EmployeeLeave&lt;/code&gt; has a FK to &lt;code&gt;Epployee&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;Let us see some queries.&lt;/p&gt;
&lt;p&gt;Get all leaves taken by an employee this year&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;import datetime
today = datetime.date.today()
start_of_year = datetime.datetime(today.year, 1, 1)
leaves_taken = employee.employeeleave_set.filter(leave_taken__gt=start_of_year, leave_taken__lt = today)
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Get a list of all HODs.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;#As there are going to be as many Employees as departments
departments = Department.objects.all()
employees = [department.hod for department in departments]
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Get a list of all departments a contractor works for.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;contractor.department_set.all()
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Get a list of all contractor who work for a department.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;department.contractor_set.all()
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Note that each side of a many to many relationship get a Manager.&lt;/p&gt;
&lt;p&gt;List of all managers in a given department.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;Todo#(Can&amp;#39;t think of any one query way to do this. If you know, let me know :) )
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;List of all leaves taken in a given department.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;EmployeeLeave.objects.filter(employee__department = department)
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;None that we used double underscores &lt;code&gt;__&lt;/code&gt; to do a filtering on a field across Entities.&lt;/p&gt;
&lt;p&gt;List of all employees which joined a given department this year.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;Employee.objects.filter(department = department, employment_history__date_joined__gte=start_of_year, )
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Note that we used a double underscore &lt;code&gt;__&lt;/code&gt; twice, first to go across entities, and then to define the type of filter(&lt;code&gt;__gte&lt;/code&gt;).
Also we specified two filter conditions, so they were &lt;code&gt;ANDed&lt;/code&gt; together.&lt;/p&gt;
&lt;p&gt;List all employees which either report too a given employee, or joined before him.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;Employee.objects.filter(Q(manager = employee)|Q(employee_history__date_joined__lt = employee.employee_history.date_joined))
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Note the new construct &lt;code&gt;Q&lt;/code&gt;, they are used to specify complex boolean operations. Here we used the &lt;code&gt;|&lt;/code&gt; (or operator) to specify or condition.&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;&lt;a href="http://feeds.feedburner.com/uswarearticles"&gt;Do you subscribe to our rss feed&lt;/a&gt;? The new feed has full text feed and many other goodness. So make sure you are subscribed to the new feed with extra fortified vitamins. &lt;a href="http://feeds.feedburner.com/uswarearticles"&gt;Subscribe now&lt;/a&gt;.&lt;/p&gt;</description><guid>http://agiliq.com/blog/2010/01/doing-things-with-django-models-aka-django-models-/</guid></item><item><title>Wordpress and Django: best buddies</title><link>http://agiliq.com/blog/2010/01/wordpress-and-django-best-buddies/</link><description>&lt;p&gt;Summary:
How to integrate a non Django database system in your Django code, using Wordpress
as example. &lt;a href="http://github.com/uswaretech/django-wordpress"&gt;The completed code is available at github&lt;/a&gt; or you can &lt;a href="#screenshots_wp"&gt;see some screnshots&lt;/a&gt;&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;Though there are quite a &lt;a href="http://github.com/montylounge/django-mingus"&gt;few good&lt;/a&gt; &lt;a href="http://byteflow.su/"&gt;Django blog&lt;/a&gt; applications, our blog is based on
&lt;a href="http://wordpress.org/"&gt;Wordpress&lt;/a&gt;. A &lt;a href="http://mitcho.com/code/yarpp/"&gt;number&lt;/a&gt; &lt;a href="http://diythemes.com/"&gt;of&lt;/a&gt; &lt;a href="http://www.backtype.com/"&gt;plugin's&lt;/a&gt;
make moving to a Django based app a bad decision
for us, and not in the spirit of "best tools for the job".&lt;/p&gt;
&lt;p&gt;We moved the other way, and decided to use &lt;a href="http://github.com/uswaretech/django-wordpress"&gt;Django to admin the
Wordpress database&lt;/a&gt;. The completed code is available on &lt;a href="http://github.com/uswaretech/django-wordpress"&gt;Github&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;It is not too hard, with the the builtin Django commands. Django provides the
&lt;a href="http://www.djangobook.com/en/1.0/chapter16/"&gt;&lt;code&gt;inspectdb&lt;/code&gt;&lt;/a&gt; command which allows you to build your models.py from an existing
non Django database.&lt;/p&gt;
&lt;p&gt;Here we will see the steps followed for Wordpress, but it would be about the same for all
systems.&lt;/p&gt;
&lt;h5&gt;Take a back up of wordpress&lt;/h5&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;mysqldump -u wordpress_user -p --database wordpress_database &amp;gt; data.sql
&lt;/pre&gt;&lt;/div&gt;


&lt;h5&gt;Create a new project, and set its settings to use the Wordpress database.&lt;/h5&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;    DATABASE_ENGINE = &amp;#39;mysql&amp;#39;           # &amp;#39;postgresql_psycopg2&amp;#39;, &amp;#39;postgresql&amp;#39;, &amp;#39;mysql&amp;#39;, &amp;#39;sqlite3&amp;#39; or &amp;#39;oracle&amp;#39;.
    DATABASE_NAME = &amp;#39;&amp;#39;             # Or path to database file if using sqlite3.
    DATABASE_USER = &amp;#39;&amp;#39;             # Not used with sqlite3.
    DATABASE_PASSWORD = &amp;#39;&amp;#39;         # Not used with sqlite3.
    DATABASE_HOST = &amp;#39;&amp;#39;             # Set to empty string for localhost. Not used with sqlite3.
    DATABASE_PORT = &amp;#39;&amp;#39;             # Set to empty string for default. Not used with sqlite3.
&lt;/pre&gt;&lt;/div&gt;


&lt;h5&gt;Get the initial models.py&lt;/h5&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;./manage.py inspectdb &amp;gt; models.py
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;This will create all the database tables in a form Django can understand. Here is what this command creates for a
my Wordpress installation with the YARPP plugin. &lt;a href="http://gist.github.com/278962"&gt;http://gist.github.com/278962&lt;/a&gt;&lt;/p&gt;
&lt;h5&gt;Create a new app and put this models.py there.&lt;/h5&gt;
&lt;p&gt;With this done, you can treat the non Django part as a
standalone application. Since Wordpress appends all its table with &lt;code&gt;wp_&lt;/code&gt; prefix,
we name this applications &lt;code&gt;wp&lt;/code&gt; to maintain table name compatibility with Django naming
conventions.&lt;/p&gt;
&lt;p&gt;You will notice that all models have the &lt;code&gt;db_table&lt;/code&gt; populated, so we can rename tables, without changes to the database.&lt;/p&gt;
&lt;h5&gt;Differences between Wordpress and Django style naming.&lt;/h5&gt;
&lt;p&gt;At this point you will notice some differences in how Django names things (in a
best practice sort of way), and how Wordpress does it.&lt;/p&gt;
&lt;p&gt;a. Django table and model class name are (generally) singular. eg &lt;code&gt;class Post(models.Models)&lt;/code&gt; leads to table &lt;code&gt;app_post&lt;/code&gt;.
Wordpress tables are (most of them) named plural eg &lt;code&gt;wp_posts&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;b. Django attributes are generally named without the table name part. Eg&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;class Comment(models.Model):
    author_name = models.TextField()
    content = models.TextField()
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Wordpress is explicit here and includes the table prefix with attributes.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;mysql&amp;gt; desc wp_comments;
+----------------------+---------------------+------+-----+---------------------+----------------+
| Field                | Type                | Null | Key | Default             | Extra          |
+----------------------+---------------------+------+-----+---------------------+----------------+
| comment_ID           | bigint(20) unsigned | NO   | PRI | NULL                | auto_increment | 
| comment_post_ID      | bigint(20) unsigned | NO   | MUL | 0                   |                | 
| comment_author       | tinytext            | NO   |     | NULL                |                | 
| comment_author_email | varchar(100)        | NO   |     |                     |                |

.....
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;I believe this is due to the way you would generally be using the code. In Django you would do
&lt;code&gt;comment.author&lt;/code&gt; where being explicit doesn't add any value, while in Wordpress, you would use,
&lt;code&gt;select comment_author, post_title ... from wp_comment, wp_post ... where join&lt;/code&gt;, where being explicit
is useful.&lt;/p&gt;
&lt;p&gt;You can decouple the Django and database names by using the &lt;code&gt;db_table&lt;/code&gt; and &lt;code&gt;db_column&lt;/code&gt; attributes.
We choose to rename the Class names to match Django conventions while we let the column names remain the same.&lt;/p&gt;
&lt;h5&gt;Add Admin and other Django niceties.&lt;/h5&gt;
&lt;p&gt;Wordpress doesn't (seem to) have foreign key constraints setup correctly, and
uses  &lt;code&gt;bigint(20) unsigned&lt;/code&gt; without foreign key constraints to refer to referred entities.
This means Django creates all ForeignKeys as IntegerFields.&lt;/p&gt;
&lt;p&gt;Modify them to use ForeignKey instead. Also add &lt;code&gt;__unicode__&lt;/code&gt;, to your classes.&lt;/p&gt;
&lt;p&gt;Add an &lt;code&gt;admin.py&lt;/code&gt; to register all your classes. &lt;/p&gt;
&lt;p&gt;And you are done! Now you can access, and work with your Wordpress data inside Django
and Django admin.&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;There are a few more things which will allow a easier Wordpress setup.&lt;/p&gt;
&lt;h5&gt;Create template tags to show the latest posts and comments.&lt;/h5&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;@register.inclusion_tag(&amp;quot;wp/recent_posts.html&amp;quot;)
def show_posts(num_comments):
    return {&amp;quot;posts&amp;quot;: Post.objects.filter(post_type=&amp;quot;post&amp;quot;, post_status=&amp;quot;publish&amp;quot;).order_by(&amp;quot;-post_date&amp;quot;)[:num_comments]}
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;So you can see that there is nothing Wordpress specific we need too do here.&lt;/p&gt;
&lt;h5&gt;Create a better admin.&lt;/h5&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;Add ModelAdmin to generally used models.
&lt;/pre&gt;&lt;/div&gt;


&lt;h5&gt;Allows accessing attributes via the Django style names.&lt;/h5&gt;
&lt;p&gt;If you override &lt;code&gt;__getattr__&lt;/code&gt;, you can access
the attributes via other names. Eg in the current setup you need to do &lt;code&gt;comment.comment_content&lt;/code&gt;, &lt;code&gt;comment.comment_author&lt;/code&gt; etc,
while we would like to do &lt;code&gt;comment.content&lt;/code&gt;  and &lt;code&gt;comment.author&lt;/code&gt; as a shortcut.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;class WordPressModel(object):    
    def __getattr__(self, v):
        if v in self.__dict__:
            return self.__dict__[v]
        else:
            new_v = &amp;quot;%s_%s&amp;quot; % (self.__class__.__name__.lower(),  v)
            if new_v in self.__dict__:
                return self.__dict__[new_v]
            else:
                raise AttributeError
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;It is highly debatable whether this is a good idea :), but it is too convenient right now not to test this method out.&lt;/p&gt;
&lt;p&gt;&lt;a name="screenshots_wp" /&gt;
Here are some screenshots.&lt;/p&gt;
&lt;img alt="" src="http://uswaretech.com/dump/screenshots/screenshot_010.png" title="Wordpress django admin" class="alignnone" width="600" /&gt;

&lt;img alt="" src="http://uswaretech.com/dump/screenshots/screenshot_011.png" title="Wordpress django admin" class="alignnone" width="600" /&gt;

&lt;hr /&gt;
&lt;p&gt;&lt;a href="http://feeds.feedburner.com/uswarearticles"&gt;Do you subscribe to our feed&lt;/a&gt;? We recently made a full text feed available, so if you are using the old feed, you should change it. &lt;a href="http://feeds.feedburner.com/uswarearticles"&gt;Subscribe now&lt;/a&gt;.&lt;/p&gt;</description><guid>http://agiliq.com/blog/2010/01/wordpress-and-django-best-buddies/</guid></item><item><title>Doing things with Django forms</title><link>http://agiliq.com/blog/2010/01/doing-things-with-django-forms/</link><description>&lt;p&gt;Forms are one of the best features of Django. (After models, admin, url routing etc :) ). Here is a quick tutorial describing how to do things with Django forms.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Basic form&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Prob. You want to show a form, validate it and display it.&lt;/p&gt;
&lt;p&gt;Ans. Create a simple form. &lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;class UserForm(forms.Form):
    username = forms.CharField()
    joined_on = forms.DateField()
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;This wil take care that the form is displayed with two text field,
and a value for them are filled in, and the second field has correct formatting for a date.&lt;/p&gt;
&lt;p&gt;2.&lt;/p&gt;
&lt;p&gt;Prob. Create a form which has values populated depending upon a runtime value,
eg you might want to show only the values corresponding to the current subdomain.&lt;/p&gt;
&lt;p&gt;Ans. Create a form with an custom &lt;code&gt;__init__&lt;/code&gt;.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;class UserForm(forms.Form):
    username = forms.CharField()
    plan = forms.ModelChoiceField(queryset = Plan.objects.none())

    def __init__(self, subdomain, *args, **kwargs):
        self.default_username = default_username
        super(UserForm, self).__init__(*args, **kwargs)
        self.fields[&amp;#39;plan&amp;#39;].queryset = Plan.objects.filter(subdomain = subdomain)
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Here in the &lt;code&gt;__init__&lt;/code&gt; we are overriding the default queryset on field &lt;code&gt;plan&lt;/code&gt;. Any of the attributes can similarly be overridden.&lt;/p&gt;
&lt;p&gt;However the &lt;code&gt;self.fields&lt;/code&gt; is populated only after &lt;code&gt;super(UserForm, self).__init__(*args, **kwargs)&lt;/code&gt; is called.&lt;/p&gt;
&lt;p&gt;3.&lt;/p&gt;
&lt;p&gt;Prob. The same form is used in multiple views, and handles the &lt;code&gt;cleaned_data&lt;/code&gt; similarly.&lt;/p&gt;
&lt;p&gt;Ans. Create a form with a custom .save()&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;class UserForm(forms.Form):
    username = forms.CharField()

    def save(self):
        data = self.cleaned_data
        user = User.objects.create(username = data[&amp;#39;username&amp;#39;])
        #create a profile
        UserProfile.objects.create(user = user, ...some more data...)
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;You could have called this method anything, but this is generally called save, to maintain similarity with &lt;code&gt;ModelForm&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;4.&lt;/p&gt;
&lt;p&gt;Prob. You need to create a form with fields which have custom validations.&lt;/p&gt;
&lt;p&gt;Ans. Create a form with custom clean_fieldname&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;class UserForm(forms.Form):
    username = forms.CharField()

    def clean_username(self):
        data = self.cleaned_data
        try:
            User.objects.get(username = data[&amp;#39;username&amp;#39;])
        except User.DoesNotExist:
            return data[&amp;#39;username&amp;#39;]
        raise forms.ValidationError(&amp;#39;This username is already taken.&amp;#39;)
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Here we can validate that the usernames are not repeated.&lt;/p&gt;
&lt;p&gt;5.&lt;/p&gt;
&lt;p&gt;Prob. You want to create a field which has cross field validations.&lt;/p&gt;
&lt;p&gt;Ans. Create a field with a .clean&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;class UserForm(forms.Form):
    username = forms.CharField()

    password1 = forms.PasswordField()
    password2 = forms.PasswordField()

    def clean(self):
        data = self.cleaned_data
        if &amp;quot;password1&amp;quot; in data and &amp;quot;password2&amp;quot; in data and data[&amp;quot;password1&amp;quot;] != data[&amp;quot;password2&amp;quot;]:
            raise forms.ValudationError(&amp;quot;Passwords must be same&amp;quot;)
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;6.&lt;/p&gt;
&lt;p&gt;Problem.&lt;/p&gt;
&lt;p&gt;You need a form the fields of which depends on some value in the database.
Eg. The field to be shown are customisable per user.&lt;/p&gt;
&lt;p&gt;Create a form dynamically&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;def get_user_form_for_user(user):
        class UserForm(forms.Form):
            username = forms.CharField()
            fields = user.get_profile().all_field()
            #Use field to find what to show.
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;&lt;a href="http://uswaretech.com/blog/2008/10/dynamic-forms-with-django/"&gt;This post provides much more details&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;7.&lt;/p&gt;
&lt;p&gt;Prob. You need to create a Html form which writes to multiple Django models.&lt;/p&gt;
&lt;p&gt;Ans. Django forms are not a one to one mapping to Html forms. &lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;#in forms.py
class UserForm(forms.ModelForm):
    class Meta:
        model = User
        fields = [&amp;quot;username&amp;quot;, &amp;quot;email&amp;quot;]

class UserProfileForm(forms.ModelForm):
    class Meta:
        model = UserProfile

#in views.py
def add_user(request):
    ...
    if request.method == &amp;quot;POST&amp;quot;:
        uform = UserForm(data = request.POST)
        pform = UserProfileForm(data = request.POST)
        if uform.is_valid() and pform.is_valid():
            user = uform.save()
            profile = pform.save(commit = False)
            profile.user = user
            profile.save()
            ....
    ...

#in template
&lt;span class="nt"&gt;&amp;lt;form&lt;/span&gt; &lt;span class="na"&gt;method=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;post&amp;quot;&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    {{ uform.as_p }}
    {{ pform.as_p }}
    &lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;submit&amp;quot;&lt;/span&gt; &lt;span class="err"&gt;...&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/form&amp;gt;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;8.&lt;/p&gt;
&lt;p&gt;Prob. You want to use multiple forms of same type on one page.&lt;/p&gt;
&lt;p&gt;Ans.&lt;/p&gt;
&lt;p&gt;a. If you want a datagrid style ui, use formset.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;from django.forms.formsets import formset_factory
forms = formset_factory(UserForm, extra = 4)
#
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;&lt;a href="http://docs.djangoproject.com/en/dev/topics/forms/formsets/"&gt;Formsets are described much more comprehensively here&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;b. If you do not need a datagrid style ui, use &lt;code&gt;prefix&lt;/code&gt; argument to forms.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;Eg. you have a survey app, and you want a page with all questions from that survey displayed.

#IN views.py
def survey(request, survey_slug)
    ...
    questions = survey.questions.all()
    question_forms = []
    for question in questions:
        qform = QuestionForm(question=question, prefix = question.slug)
        question_forms.append(qform)
        ...
    if request.method == &amp;quot;POST&amp;quot;:
        for question in questions:
            qform = QuestionForm(question=question, prefix = question.slug, data = request.POST)
        #Validate and do save action
        ...
    ...
&lt;/pre&gt;&lt;/div&gt;


&lt;hr /&gt;
&lt;p&gt;&lt;a href="http://feeds.feedburner.com/uswarearticles"&gt;Do you subscribe to our feed&lt;/a&gt;? We recently made a full text feed available, so if you are using the old feed, you should change it. &lt;a href="http://feeds.feedburner.com/uswarearticles"&gt;Subscribe now&lt;/a&gt;.&lt;/p&gt;</description><guid>http://agiliq.com/blog/2010/01/doing-things-with-django-forms/</guid></item><item><title>django-forum</title><link>http://agiliq.com/blog/2010/01/django-forum/</link><description>&lt;h3&gt;twitter ready version:&lt;/h3&gt;
&lt;p&gt;We have released a &lt;a href="http://uswaretech.com/forum/"&gt;Django forum&lt;/a&gt; application, with some cool features not in any other Django based forum. &lt;a href="http://github.com/uswaretech/Dinette"&gt;You can get it here&lt;/a&gt; or &lt;a href="http://uswaretech.com/forum/"&gt;see it in action&lt;/a&gt;. &lt;/p&gt;
&lt;h3&gt;blog version&lt;/h3&gt;
&lt;p&gt;There are quite a few &lt;a href="http://code.djangoproject.com/wiki/ForumAppsComparison"&gt;Django based forum applications&lt;/a&gt;, so why another? Its a bit of a rhetorical question,  as the answer is "none of them met my needs exactly, so we created my own", as you might expect.&lt;/p&gt;
&lt;p&gt;Without further ado here is a list of features. It is available on &lt;a href="http://uswaretech.com/forum/"&gt;uswaretech.com/forum/&lt;/a&gt;.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Based on, inspired by and ripped from &lt;a href="http://punbb.informer.com/"&gt;PunBB&lt;/a&gt;. (Thanks!)&lt;/li&gt;
&lt;li&gt;PunBB like 3 phased hierarchy [Forum]-&amp;gt;Subforum-&amp;gt;Topic-&amp;gt;Post&lt;/li&gt;
&lt;li&gt;Tightly integrated with &lt;a href="http://github.com/uswaretech/Django-Socialauth"&gt;Socialauth&lt;/a&gt;. (Screenshots)&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.gravatar.com/"&gt;Gravatar&lt;/a&gt; support&lt;/li&gt;
&lt;li&gt;Moderation features (Close, stikify, make announcement etc.)&lt;/li&gt;
&lt;li&gt;Ajax based posting&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;We are starting our forums based on this app, so we plan to be supporting and developing this for foreseeable future. &lt;a href="http://github.com/uswaretech/Dinette"&gt;Fork this on Github&lt;/a&gt; or &lt;a href="http://uswaretech.com/forum/"&gt;check this out now&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;a name="screenshots"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;Screenshots&lt;/h3&gt;
&lt;p&gt;Main page&lt;/p&gt;
&lt;p&gt;&lt;a href="http://uswaretech.com/dump/screenshots/screenshot_007.png"&gt;&lt;img alt="" src="http://uswaretech.com/dump/screenshots/screenshot_007.png" title="Dinette screenshot" class="alignnone" width="640" height="420" /&gt;&lt;/a&gt; &lt;br /&gt; &lt;br /&gt;&lt;/p&gt;
&lt;p&gt;Post page&lt;/p&gt;
&lt;p&gt;&lt;a href="http://uswaretech.com/dump/screenshots/screenshot_008.png"&gt;&lt;img alt="" src="http://uswaretech.com/dump/screenshots/screenshot_008.png" title="Dinette screenshot" class="alignnone"  width="640" height="420" /&gt;&lt;/a&gt; &lt;br /&gt; &lt;br /&gt;&lt;/p&gt;
&lt;p&gt;Login Page&lt;/p&gt;
&lt;p&gt;&lt;a href="http://uswaretech.com/dump/screenshots/screenshot_009.png"&gt;&lt;img alt="" src="http://uswaretech.com/dump/screenshots/screenshot_009.png" title="Dinette screenshot" class="alignnone"  width="640" height="420" /&gt;&lt;/a&gt; &lt;br /&gt; &lt;br /&gt;&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;We build amazing web apps. &lt;a href="http://uswaretech.com/contact/"&gt;Contact us&lt;/a&gt;&lt;/p&gt;</description><guid>http://agiliq.com/blog/2010/01/django-forum/</guid></item><item><title>Using bpython shell with django (and some Ipython features you should know)</title><link>http://agiliq.com/blog/2009/12/using-bpython-shell-with-django-and-some-ipython-f/</link><description>&lt;h3&gt;What is bpython?&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;bpython is a fancy interface to the Python interpreter for Unix-like operating system.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;says the &lt;a href="http://bpython-interpreter.org/"&gt;bpython&lt;/a&gt; home page. It provides syntax highlighting, auto completion, auto-indentation and such stuff.&lt;/p&gt;
&lt;p&gt;Unlike &lt;a href="http://ipython.scipy.org/moin/"&gt;iPython&lt;/a&gt;, which implements then entire shell functions and emulates the standard python shell, and adds enhancements, bpython just adds features on top of the existing python shell functionality, using the curses module. &lt;/p&gt;
&lt;img src="http://i.imgur.com/cqky1.png" alt="bpython" /&gt;

&lt;p&gt;The "killer feature" of bpython is, as you can see from the image above, the IDE like prompting of the function parameters and the doc string of the function dynamically. I have always thought, what &lt;a href="http://www.jetbrains.com/idea/"&gt;IntellijIDEA&lt;/a&gt; is to Java, IPython is to Python*. But bpython makes it more so, in terms of the code completion, which adds a lot of value to a &lt;em&gt;ramping up developer&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;The only Python IDE that provides Source Assistant and Go-To-Source functionality conveniently, is the commercial one, &lt;a href="http://www.wingide.com/wingide"&gt;Wing IDE Professional&lt;/a&gt;. Even with that, since all the defined models are replaced (by using meta-classes) in the runtime, that source assistant is not perfect. Newer versions of Wing seems to claim to obtain data dynamically at the runtime, but its not always comfortable to write code, keeping the IDE in a breakpoint. But hey, bpython provides all these for free!&lt;/p&gt;
&lt;h3&gt;But I already use Ipython&lt;/h3&gt;
&lt;p&gt;You do? So do I. In fact, I am a Power Ipython user, I use all kinds of &lt;a href="http://ipython.scipy.org/doc/stable/html/interactive/reference.html#magic-command-system"&gt;%magic&lt;/a&gt; functions: %whos, &lt;a href="http://ipython.scipy.org/doc/stable/html/interactive/reference.html#session-logging-and-restoring"&gt;%logstart&lt;/a&gt;, %bookmark, %ed  and sometimes use Ipython as an alternative even to bash: %cd, %ls, %ll. And even for doc testing: &lt;a href="http://ipython.scipy.org/doc/stable/html/interactive/reference.html#pasting-of-code-starting-with-or"&gt;%doctest_mode&lt;/a&gt;, copy-pasting %hist -n or running some code module in the interpreter namespace: %run -i and searching code %psearch. You can also give any arbitrary bash(or your default shell) command by escaping it with !. Oh, ?, ?? and / are of course the starters.&lt;/p&gt;
&lt;p&gt;In fact did you know, you could get to ipython shell within any arbitrary place within your django code? Just use the following:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;from IPython.Shell import IPShellEmbed
ipython = IPShellEmbed()
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;and then call ipython() anywhere within your view, model, forms and you will be dropped to the shell. Its &lt;a href="http://aymanh.com/python-debugging-techniques"&gt;like ipdb.set_trace()&lt;/a&gt; only better (unless you want to step through, that is).&lt;/p&gt;
&lt;h3&gt;The Python readline bug&lt;/h3&gt;
&lt;p&gt;The Python version 2.6.4 (the version that is shipped with Ubuntu 9.10), introduced a &lt;a href="http://bugs.python.org/issue5833"&gt;readline bug&lt;/a&gt; that adds spaces after tab completion. This bug also affects the Ipython, as it uses the same readline module. If you spend a lot of time on the shell (if you use python, you must, right?), it is very annoying to backspace after each tab, all the time.&lt;/p&gt;
&lt;p&gt;Although the bug got fixed pretty soon, it hasn't yet made it to any release that ubuntu updates to. There are ways to workaround this problem, by fixing it at the python level and at the Ipython level, many of them are discussed on the corresponding &lt;a href="https://bugs.launchpad.net/ipython/+bug/470824"&gt;Ipython bug&lt;/a&gt; &lt;/p&gt;
&lt;h3&gt;Using bpython with django&lt;/h3&gt;
&lt;p&gt;Now that you want to use bpython with django, either because you like the auto completion, or because you find the read line bug annoying (and don't want/care-enough to patch your python locally), or you just want to try it, how to do it?&lt;/p&gt;
&lt;p&gt;&lt;code&gt;django manage.py shell&lt;/code&gt; unfortunately, drops only into the ipython shell (if you have ipython installed), and there is no straight forward way to get it to drop to bpython.&lt;/p&gt;
&lt;p&gt;But there is still a way to use bpython with django. Just modify your ~/.bashrc to define a python startup environment variable&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;export PYTHONSTARTUP=~/.pythonrc
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;And within it, setup the django environment, that is, do it here manually the thing that &lt;code&gt;python manage.py shell&lt;/code&gt; would do for you:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;#.pythonrc
try:
    from django.core.management import setup_environ
    import settings
    setup_environ(settings)
    print &amp;#39;imported django settings&amp;#39;
except:
    pass
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;This way, &lt;code&gt;bpython&lt;/code&gt; or even just &lt;code&gt;python&lt;/code&gt; on the command line, should import the django environment for you.&lt;/p&gt;
&lt;h3&gt;Importing all models automatically into the shell&lt;/h3&gt;
&lt;p&gt;But then, if you are possibly already used to &lt;code&gt;python manage.py shell_plus&lt;/code&gt; (If you are not, you should be.) that is defined by &lt;a href="http://wiki.github.com/django-extensions/django-extensions/current-command-extensions"&gt;django_command_extensions&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;So while we are at setting up the django environment, lets just also import all the models into the shell namespace, so that it is convenient to work. Following is some ugly quick hack to get it done.&lt;/p&gt;
&lt;script src="http://gist.github.com/231878.js?file=.pythonrc.py"&gt;&lt;/script&gt;

&lt;p&gt;This can of course be improved upon. If you do it, just leave it in the comments! In fact it would be good if it also includes &lt;code&gt;from startup.py import *&lt;/code&gt; in a try catch, so that, you can put some extra code into startup.py. Saving into startup.py from within a bpython shell is just a &lt;code&gt;Ctrl+s&lt;/code&gt; anyway. That way each time you get to the shell, you can have the same expected environment; and it is quite easy to change that file.&lt;/p&gt;
&lt;p&gt;*I know, I know, IPython doesn't refactor code, nor build, nor does a million things that Intellij does, but &lt;a href="http://dirtsimple.org/2004/12/python-is-not-java.html"&gt;Python is not Java&lt;/a&gt; and basically both intend to enhance developer productivity. And I spend a lot of time on the IPython shell and find it to be a tool just like Intellij is a tool, for Java.&lt;/p&gt;</description><guid>http://agiliq.com/blog/2009/12/using-bpython-shell-with-django-and-some-ipython-f/</guid></item><item><title>Python metaclasses and how Django uses them</title><link>http://agiliq.com/blog/2009/12/python-metaclasses-and-how-django-uses-them/</link><description>&lt;p&gt;&lt;a href="http://foss.in/2009/"&gt;Foss.in&lt;/a&gt; is without doubt India's &lt;a href="http://twitter.com/#search?q=fossdotin"&gt;largest&lt;/a&gt; FOSS technology conference. &lt;a href="http://foss.in/2009/schedules/talkdetailspub.php?talkid=44"&gt;Lakshman gave a talk&lt;/a&gt; today on "Python metaclasses and how Django uses them". Here are the slides from that talk.&lt;/p&gt;
&lt;div style="width:425px;text-align:left" id="__ss_2642704"&gt;&lt;a style="font:14px Helvetica,Arial,Sans-serif;display:block;margin:12px 0 3px 0;text-decoration:underline;" href="http://www.slideshare.net/uswaretech/doing-magic-with-python-metaclasses" title="Doing magic with python metaclasses"&gt;Doing magic with python metaclasses&lt;/a&gt;&lt;object style="margin:0px" width="425" height="355"&gt;&lt;param name="movie" value="http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=foos-lakshman-091203110615-phpapp02&amp;stripped_title=doing-magic-with-python-metaclasses" /&gt;&lt;param name="allowFullScreen" value="true"/&gt;&lt;param name="allowScriptAccess" value="always"/&gt;&lt;embed src="http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=foos-lakshman-091203110615-phpapp02&amp;stripped_title=doing-magic-with-python-metaclasses" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="425" height="355"&gt;&lt;/embed&gt;&lt;/object&gt;&lt;div style="font-size:11px;font-family:tahoma,arial;height:26px;padding-top:2px;"&gt;View more &lt;a style="text-decoration:underline;" href="http://www.slideshare.net/"&gt;documents&lt;/a&gt; from &lt;a style="text-decoration:underline;" href="http://www.slideshare.net/uswaretech"&gt;Usware Technologies&lt;/a&gt;.&lt;/div&gt;&lt;/div&gt;

&lt;hr /&gt;
&lt;p&gt;[Edit]
Some reactions,&lt;br /&gt;
&lt;a href="http://twitter.com/jaideep2588/status/6295483833"&gt;http://twitter.com/jaideep2588/status/6295483833&lt;/a&gt;&lt;br /&gt;
&lt;a href="http://twitter.com/kunalbharati/status/6296572939"&gt;http://twitter.com/kunalbharati/status/6296572939&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;And the talk images, &lt;a href="http://twitpic.com/rxhn7"&gt;http://twitpic.com/rxhn7&lt;/a&gt;&lt;br /&gt;
&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;&lt;a href="http://twitter.com/uswaretech"&gt;You should follow us on twitter&lt;/a&gt; and &lt;a href="http://feeds.feedburner.com/uswarearticles"&gt;Subscribe to our blog&lt;/a&gt;&lt;/p&gt;</description><guid>http://agiliq.com/blog/2009/12/python-metaclasses-and-how-django-uses-them/</guid></item><item><title>Django quiz</title><link>http://agiliq.com/blog/2009/12/django-quiz/</link><description>&lt;p&gt;A quick django quiz. Answers available tomorrow. Get it as a text file &lt;a href='http://dl.dropbox.com/u/271935/django-quiz.txt'&gt;(django-quiz)&lt;/a&gt; or on &lt;a href="http://docs.google.com/Doc?docid=0AYLjHVQq0A8aZGZ0NTRxOXBfMGhxY2g2ZDhk&amp;amp;hl=en"&gt;google docs&lt;/a&gt; or read below.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;### Easy

1. You have a class defined as

    class Post(models.Model):
        name = models.CharField(max_length=100)
        is_active = models.BooleanField(default=False)

You create multiple objects of this type. If you do
Post.objects.get(is_active=False),

what exceptions is raised?

a. MultipleObjectsReturned
b. ManyObjectsReturned
c. SyntaxError
d. MultipleModelReturned
e. ManyModelReturned

2. Where is the function render_to_response defined?

a. django.views
b. django.shortcuts
c. django.templates
d. django.contrib.templates
e. django.contrib.shortcuts

3. What is the default name for the table created for model named Post
in application blog

a. post_blog
b. blog_post
c. postblog
d. blogpost
e. Postblog

4. How do you send a 302 redirect using django?

a. return HttpRedirectResponse()
b. return HttpResponseRedirect()
c. return HttpRedirectResponse(permanent=True)
d. return HttpResponseRedirect(permanent=True)
e. return HttpRedirectResponse

5. In django.contrib.auth, Users passwords are kept in what form?
a. Plain text
b. Hashed
c. Encrypted
d. Hashed then encrypted
3. Encrypted then hashed

6. Which of the following is correct way to find out if a request uses
HTTP POST method?

a. request.is_post() == True
b. request.METHOD == &amp;#39;post&amp;#39;
c. request.METHOD == &amp;#39;POST&amp;#39;
d. request.method == &amp;#39;post&amp;#39;
e. request.method == &amp;#39;POST&amp;#39;

7. Generic views have access to request context.

a. True
b. False
c. Default is True but can be set to False by GENERIC_REQUEST_CONTEXT in settings.
d. Default is False but can be set to True by GENERIC_REQUEST_CONTEXT in settings.
e. Can not be determined without extra information.

8. The current released version of Django is

a. 0.96
b. 1.0
c. 1.1
d. 1.2
e. Vyper logix 2.0

9. Which of these is a correct context_processor?

a.

def featured_posts(request):
    return Post.objects.filter(is_featured=True)

b.

def featured_posts(request):
    return {&amp;#39;featured_posts&amp;#39;: Post.objects.filter(is_featured=True)}

c.

def featured_posts(request, response):
    return Post.objects.filter(is_featured=True)

d.

def featured_posts(request, response):
    return {&amp;#39;featured_posts&amp;#39;: Post.objects.filter(is_featured=True)}

e.     
def featured_posts(request, response):
    response.write(&amp;#39;featured_posts&amp;#39;= Post.objects.filter(is_featured=True))

10. Which of the following is a valid Middleware?

a.

class LatestPostMiddleware:
    def process_request(request):
        request.latest_post = Post.objects.latest()

b.

class LatestPostMiddleware(django.middlewares.BaseMiddleWare):
    def process_request(request):
        request.latest_post = Post.objects.latest()

c.

class LatestPostMiddleware(django.middlewares.BaseMiddleWare):
    def process_request(request):
        return {&amp;#39;latest_post&amp;#39;: Post.objects.latest()}

d.

class LatestPostMiddleware():
    def process_request(request):
        return {&amp;#39;latest_post&amp;#39;: Post.objects.latest()}

e.

class LatestPostMiddleware():
    def process_request(request):
        request.write(&amp;#39;latest_post&amp;#39;= Post.objects.latest())

#Moderate

11. In the model below which line can be removed for the class to work

class Post(models.Model):
    name = models.CharField(max_length = 100)#Line 1
    desc = models.TextField()#Line 2
    post = models.ForeignKey(Blog)#Line 3
    blog = models.ForeignKey(Blog)#Line 4

a. Line 1
b. Line 2
c. Line 3
d. Line 4
e. Either of line 3 or 4

12. Who can access the admin site in Django?

a. user with is_super_user True
b. user with is_staff True
c. user with is_admin True
d. Either of a or b
e. Either of a, b, c

13. Which of the following code is closest to login_required decorator in Django?

a.

def login_required2(request):
    if request.user.is_authenticated():
        return True
    else:
        return False

b.

def login_required2(request, view_func):
    def check_login(request):
        if request.is_authenticated() and request.has_permissions(request.REQUIRED_PERMISSIONS):
            return view_function(request)
        else:
            return HttpResponseRedirect(&amp;#39;/login/&amp;#39;)
    return check_login(view_func)

c.

def login_required2(request, view_func):
    def check_login(request):
        if request.is_authenticated():
            return view_function(request)
        else:
            return HttpResponseRedirect(&amp;#39;/login/&amp;#39;)
    return check_login(view_func)

d.

def login_required2(view_func):
    def new_func(request):
        if request.user.is_authenticated():
            return view_func(request)
        else:
            return HttpResponseRedirect(&amp;#39;/login/&amp;#39;)
    return new_func

e.

def login_required2(view_func):
    def new_func(request):
        if request.user.is_authenticated() and request.has_permissions(request.REQUIRED_PERMISSIONS):
            return view_func(request)
        else:
            return HttpResponseRedirect(&amp;#39;/login/&amp;#39;)
    return new_func

14. Which of the following is a valid method to model Many to many relation ship in Django?

a.

class Foo(models.Model):
    bar = models.ManyToManyField(Bar)

class Bar(models.Model):
    foo = models.ManyToManyField(Foo)

b.

class Foo(models.Model):
    bar = models.ForeignKey(Bar)

class Bar(models.Model):
    foo = models.ForeignKey(Foo)

c.

class Foo(models.Model):
    bar = models.ManyToManyField(Bar)

class Bar(models.Model):
    pass

d. both B and C

e. All a, b, c

15. Which of the following is not included by default in TEMPLATE_CONTEXT_PROCESSORS

a. django.core.context_processors.auth
b. django.core.context_processors.debug
c. django.core.context_processors.i18n
d. django.core.context_processors.media
e. django.core.context_processors.request

16. Which of these is the currect way to validate uniqueness of a field named &amp;quot;slug&amp;quot; in a form
subclassing django.form.Forms.

a.

def clean(self):
    try:
        Post.objects.get(slug = self.cleaned_data[&amp;#39;slug&amp;#39;])
        raise forms.Error(ValidationError, &amp;#39;This slug already exists&amp;#39;)
    except Post.DoesNotExist:
        return self.cleaned_data

b.

def clean(self):
    try:
        Post.objects.get(slug = self.cleaned_data[&amp;#39;slug&amp;#39;])
        raise ValidationError(&amp;#39;This slug already exists&amp;#39;)
    except Post.DoesNotExist:
        return self.cleaned_data

c.

def clean_slug(self):
    try:
        Post.objects.get(slug = self.cleaned_data[&amp;#39;slug&amp;#39;])
        raise forms.Error(ValidationError, &amp;#39;This slug already exists&amp;#39;)
    except Post.DoesNotExist:
        return self.cleaned_data

d.

def clean_slug(self):
    try:
        Post.objects.get(slug = self.cleaned_data[&amp;#39;slug&amp;#39;])
        raise ValidationError(&amp;#39;This slug already exists&amp;#39;)
    except Post.DoesNotExist:
        return self.cleaned_data

e.

17. To add custom commands to your project setup, you need to,

1. Add management/command/commandname.py to your django app.
2. Add management/command/commandname.py to your django project.
3. Add command/commandname.py to your django app.
4. Add command/commandname.py to your django project.
5. Add management/command/manage.py to yout django project.

18. You want to enable caching for Django pages for AnonymousUser, which of these
is a valid way to do this.

a.

MIDDLEWARE_CLASSES = (
    &amp;#39;django.middleware.common.CommonMiddleware&amp;#39;,
    &amp;#39;django.middleware.cache.CacheMiddleware&amp;#39;,
    &amp;#39;django.contrib.sessions.middleware.SessionMiddleware&amp;#39;,
    &amp;#39;django.contrib.auth.middleware.AuthenticationMiddleware&amp;#39;,
)

b.

MIDDLEWARE_CLASSES = (
    &amp;#39;django.middleware.common.CommonMiddleware&amp;#39;,
    &amp;#39;django.contrib.sessions.middleware.SessionMiddleware&amp;#39;,
    &amp;#39;django.middleware.cache.CacheMiddleware&amp;#39;,
    &amp;#39;django.contrib.auth.middleware.AuthenticationMiddleware&amp;#39;,
)

c.

MIDDLEWARE_CLASSES = (
    &amp;#39;django.middleware.common.CommonMiddleware&amp;#39;,
    &amp;#39;django.contrib.sessions.middleware.SessionMiddleware&amp;#39;,
    &amp;#39;django.contrib.auth.middleware.AuthenticationMiddleware&amp;#39;,
    &amp;#39;django.middleware.cache.CacheMiddleware&amp;#39;,
)

d.

MIDDLEWARE_CLASSES = (
    &amp;#39;django.middleware.cache.CacheMiddleware&amp;#39;,
    &amp;#39;django.middleware.common.CommonMiddleware&amp;#39;,
    &amp;#39;django.contrib.sessions.middleware.SessionMiddleware&amp;#39;,
    &amp;#39;django.contrib.auth.middleware.AuthenticationMiddleware&amp;#39;,
)

e.

MIDDLEWARE_CLASSES = (
    &amp;#39;django.middleware.cache.CacheMiddleware&amp;#39;,
    &amp;#39;django.middleware.common.CommonMiddleware&amp;#39;,
    &amp;#39;django.contrib.sessions.middleware.SessionMiddleware&amp;#39;,
)

19.

Consider the urlconf given below

    from django.conf.urls.defaults import *

    urlpatterns = patterns(&amp;#39;news.views&amp;#39;,
        (r&amp;#39;^articles/2003/$&amp;#39;, &amp;#39;year_archive_2003&amp;#39;),
        (r&amp;#39;^articles/(\d{4})/&amp;#39;, &amp;#39;year_archive&amp;#39;),
        (r&amp;#39;^articles/2003/(\d{2})/$&amp;#39;, &amp;#39;month_archive_2003&amp;#39;),
        (r&amp;#39;^articles/(\d{4})/(\d{2})/&amp;#39;, &amp;#39;month_archive&amp;#39;),
        (r&amp;#39;^articles/(\d{4})/10/&amp;#39;, &amp;#39;month_archive_october&amp;#39;),
    )
What view is called when accessing /articles/2003/10/

a. year_archive_2003
b. year_archive
c. month_archive_2003
d. month_archive
e. month_archive_october

20.

Consider the urlpatterns.

    urlpatterns = patterns(&amp;#39;blogapp.views&amp;#39;,
        (r&amp;#39;^list/(?P&amp;lt;year&amp;gt;\d{4})/(?P&amp;lt;month&amp;gt;[a-z]{3})/$&amp;#39;,&amp;#39;archive_month&amp;#39;),
    )

Which if the following is a valid view function which will be called on accesing
/list/2009/jun/

a. def archive_month(request):
        ...

b. def archive_month(request, *args):

c. def archive_month(request, **kwargs):

d. def  archive_month(request, year, month,):

e. Both c and d

# Hard

None yet
&lt;/pre&gt;&lt;/div&gt;


&lt;hr /&gt;
&lt;p&gt;&lt;a href="http://twitter.com/uswaretech"&gt;Follow us on twitter&lt;/a&gt; or &lt;a href="http://feeds.feedburner.com/uswarearticles"&gt;subscribe to our blog&lt;/a&gt;&lt;/p&gt;</description><guid>http://agiliq.com/blog/2009/12/django-quiz/</guid></item><item><title>Django for a Rails Developer</title><link>http://agiliq.com/blog/2009/11/django-for-a-rails-developer/</link><description>&lt;p&gt;This is not yet another &lt;a href="http://www.djangoproject.com/"&gt;Django&lt;/a&gt; vs &lt;a href="http://rubyonrails.org/"&gt;Rails&lt;/a&gt; blog post. It is a compilation of notes I made working with Django after having worked on Rails for years.&lt;/p&gt;
&lt;p&gt;In this post I want to give a brief introduction to Django project layout from a Rails developer point of view, on what is there, what is not there and where to look for things. It should help a rails developer working on django be able to find the necessary files and underatnd the layout of the project files.&lt;/p&gt;
&lt;p&gt;Once you have both the frameworks installed on your system you can create the projects using the commands&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;# creating a rails project
rails rails_project
# creating a Django project
django-admin.py startproject django_project
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Lets look at the files and structure created by the respective frameworks&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;#rails_project
README
Rakefile
app/
    controllers/
        application_controller.rb
    helpers/
        application_helper.rb
    models/
    views/
        layouts/
config/
    boot.rb
    database.yml
    environment.rb
    environments/
        development.rb
        production.rb
        test.rb
    initializers/
        backtrace_silencers.rb
        inflections.rb
        mime_types.rb
        new_rails_defaults.rb
        session_store.rb
    locales/
        en.yml
    routes.rb
db/
    seeds.rb
doc/
    README_FOR_APP
lib/
    tasks/
log/
    development.log
    production.log
    server.log
    test.log
public/
    404.html
    422.html
    500.html
    favicon.ico
    images/
        rails.png
    index.html
    javascripts/
        application.js
        controls.js
        dragdrop.js
        effects.js
        prototype.js
    robots.txt
    stylesheets/
script/
    about
    console
    dbconsole
    destroy
    generate
    performance/
        benchmarker
        profiler
    plugin
    runner
    server
test/
    fixtures/
    functional/
    integration/
    performance/
        browsing_test.rb
    test_helper.rb
    unit/
tmp/
    cache/
    pids/
    sessions/
    sockets/
vendor/
    plugins/
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;that is huge....&lt;/p&gt;
&lt;p&gt;lets look at the django project files&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;# django_project
__init__.py
manage.py
settings.py
urls.py
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;far lesser when compared to the rails project.&lt;/p&gt;
&lt;p&gt;In fact a rails project comes with everything a web application needs. When I say everything I mean everything..... base application, routing, database configuration, development, test and production environment specific configurations and their respective log files,  javascript, test, some standard html files and some helpful scripts for developing.&lt;/p&gt;
&lt;p&gt;Why then does a Django project have so less number of files? It has got to do with the Django's philosophy and the concept of applications. The django project is not complete without the application, so lets create a application inside the project and have a look at the structure&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;django-admin.py startapp app

# django_project
__init__.py
app/
    __init__.py
    models.py
    tests.py
    views.py
manage.py
settings.py
urls.py
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;even after including this, the number of files is still less than the rails project.&lt;/p&gt;
&lt;p&gt;Lets break it down and relate both the frameworks. &lt;/p&gt;
&lt;table width='100%' border='1px'&gt;
    &lt;thead&gt;
        &lt;tr&gt;
            &lt;th&gt;&lt;/th&gt;
            &lt;th&gt;Rails&lt;/th&gt;
            &lt;th&gt;Django&lt;/th&gt;
        &lt;/tr&gt;
    &lt;/thead&gt;
    &lt;tbody&gt;
        &lt;tr&gt;
            &lt;td width='20%'&gt;Configuration Files&lt;/td&gt;
            &lt;td width='40%'&gt;
                &lt;li&gt;config/database.yml for database settings&lt;/li&gt;
                config/environments/
                &lt;li&gt;development.rb for development specific settings&lt;/li&gt;
                &lt;li&gt;production.rb for production specific settings&lt;/li&gt;
                &lt;li&gt;test.rb for test specific settings&lt;/li&gt;
            &lt;/td&gt;
            &lt;td width='40%'&gt;
                settings.py, one file for everything, database configuration and any other configuaration or settings will be in this file
            &lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
            &lt;td&gt;URLs&lt;/td&gt;
            &lt;td&gt;
                config/routes.rb
            &lt;/td&gt;
            &lt;td&gt;
                urls.py
            &lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
            &lt;td&gt;Schema/Models&lt;/td&gt;
            &lt;td&gt;
                &lt;li&gt;db/schema.rb for the ruby version of db schema&lt;/li&gt;
                &lt;li&gt;app/models/* for the models&lt;/li&gt;
            &lt;/td&gt;
            &lt;td&gt;
                &lt;li&gt;complete schema is not stored any where&lt;/li&gt;
                &lt;li&gt;Under every application in your project, models.py file will contain the table specific schema stored as django models&lt;/li&gt;
            &lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
            &lt;td&gt;Management Commands&lt;/td&gt;
            &lt;td&gt;
                &lt;li&gt;./script/server,  start server&lt;/li&gt;
                &lt;li&gt;./script/console, ruby console&lt;/li&gt;
                &lt;li&gt;./script/dbconsole, database console&lt;/li&gt;
                &lt;li&gt;rake db:migrate, run database migrations&lt;/li&gt;
            &lt;/td&gt;
            &lt;td&gt;
                manage.py is the file for all your tasks
                &lt;li&gt;./manage.py runserver, start server&lt;/li&gt;
                &lt;li&gt;./manage.py shell, python console&lt;/li&gt;
                &lt;li&gt;./manage.py dbshell, database console&lt;/li&gt;
                &lt;li&gt;./manage.py syncdb&lt;/li&gt;
            &lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
            &lt;td&gt;Application Code&lt;/td&gt;
            &lt;td&gt;
                app/controllers/* will contain the application logic
            &lt;/td&gt;
            &lt;td&gt;
                views.py file under each application folder is the place to write to your application logic, file can be named with any name, views.py is the general convention
            &lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
            &lt;td&gt;Application templates&lt;/td&gt;
            &lt;td&gt;
                app/views/&lt;controller_name&gt;/* is the place for the templates
            &lt;/td&gt;
            &lt;td&gt;
                &lt;li&gt; default: looks inside 'templates' directory, under the application directory&lt;/li&gt;
                &lt;li&gt; looks in the directory specified by 'TEMPLATE_DIRS' in settings.py &lt;/li&gt;
            &lt;/td&gt;
        &lt;/tr&gt;

&lt;/tbody&gt;
&lt;/table&gt;

&lt;p&gt;and lets have a look at the other things in rails_project
    &lt;ul&gt;
        &lt;li&gt;Logging, unders the logs directory &lt;/li&gt;
        &lt;li&gt;Some default html files for some standard http errors, under the public directory &lt;/li&gt;
        &lt;li&gt;Rails has very good support for testing, for that bunch of files under tests &lt;/li&gt;
        &lt;li&gt;Vendor/Plugin, place for some third party plugins/applications. &lt;/li&gt;
    &lt;/ul&gt;&lt;/p&gt;
&lt;p&gt;Missing pieces in Django (for a rails developer)
    &lt;ul&gt;
        &lt;li&gt;Scaffold magic&lt;/li&gt;
        &lt;li&gt;Generate commands&lt;/li&gt;
        &lt;li&gt;Migrations&lt;/li&gt;
    &lt;/ul&gt;&lt;/p&gt;
&lt;p&gt;and what is Django is providing by default? Sorry no extra files in the project; but you will get an authentication system and Django's killer feature, admin, just by modifying your 'INSTALLED_APPS' in your settings. It is similar to the plugins feature in Rails, Django's philosophy of resusable apps helps you in getting any particular functionality into your project.&lt;/p&gt;
&lt;p&gt;Following is a list of what I like in Django (and associated apps):
&lt;li&gt;Admin (almost everybodys favourite)&lt;/li&gt;
&lt;li&gt;Generic Views, helps from writing a lot of repetetive code, &lt;a href='http://www.b-list.org/weblog/2006/nov/16/django-tips-get-most-out-generic-views/'&gt;James Bennett's blog on generic views&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Django DB API &amp;amp; QuerySets, (chaining and the filters that are missing in ActiveRecord)&lt;/li&gt;
&lt;li&gt;Forms and above all, my favorite yet: &lt;a href="http://docs.djangoproject.com/en/dev/topics/forms/modelforms/"&gt;ModelForm&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;You can get the migrations feature in Django using &lt;a href="http://south.aeracode.org/"&gt;South&lt;/a&gt;. Being an external app, it a bit of pain in setting it up to work with South. Other than that it is more like rails migrations&lt;/li&gt;
&lt;li&gt;&lt;a href="http://code.google.com/p/django-command-extensions/"&gt;django-command-extensions&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://haystacksearch.org/"&gt;Search the Django way&lt;/a&gt;&lt;/li&gt;&lt;/p&gt;
&lt;p&gt;Following are the questions that I keep getting, 
 &lt;li&gt;When a project will almost have a application why creating project &amp;amp; app has to be two different steps?&lt;/li&gt;
&lt;li&gt;Why not create a 'templates' directoy and a 'base.html' either in project's directory or in the apps's directory, because creating the same templates directory and same base.html for every project is not DRY :) ?&lt;/li&gt;
&lt;li&gt; Why serving static files in development has to be a additional setup, as no developer wants to setup a server for serving static files, I am aware of 'django.static.serve' but still that is an additional setup, why not create a sample media directory and a url for the same in urls.py ?&lt;/li&gt;&lt;/p&gt;
&lt;p&gt;let me know via comments, if you have any answers &lt;/p&gt;
&lt;p&gt;program used for listing the files in a directory&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;import os
import sys

try:
    directory = sys.argv[1]
except IndexError:
    directory = os.path.dirname(os.path.abspath(__file__))

def r_list_dir(directory, indent=0):
    dir_files = sorted([os.path.join(directory, file_name) for file_name in  os.listdir(directory)])
    for item in dir_files:
        if os.path.isdir(item):
            print &amp;quot; &amp;quot; * indent + os.path.split(item)[1] + &amp;#39;/&amp;#39;
            r_list_dir(item, indent+4)
        else:
            print &amp;quot; &amp;quot; * indent + os.path.split(item)[1]

r_list_dir(directory)
&lt;/pre&gt;&lt;/div&gt;</description><guid>http://agiliq.com/blog/2009/11/django-for-a-rails-developer/</guid></item><item><title>Writing your own template loaders</title><link>http://agiliq.com/blog/2009/11/writing-your-own-template-loaders/</link><description>&lt;p&gt;Django has three builtin template loaders which are used to get the templates for rendering.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;TEMPLATE_LOADERS = (
    &amp;#39;django.template.loaders.filesystem.load_template_source&amp;#39;,
    &amp;#39;django.template.loaders.app_directories.load_template_source&amp;#39;,
#     &amp;#39;django.template.loaders.eggs.load_template_source&amp;#39;,
)
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Writing your template loader is a awfuly easy. It is a callable which&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Returns a tuple of (openfile, filename) if it can find the template.&lt;/li&gt;
&lt;li&gt;Raise TemplateDoesNotExist if the templates cannot be found.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The simplest template loader can be&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;from django.template import TemplateDoesNotExist
def load_template_source(template_name, template_dirs=None):
        try:
            return open(template_name).read(), template_name
        except IOError:
            raise TemplateDoesNotExist, template_name
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;if you put this to your template loaders directory,&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;TEMPLATE_LOADERS = (
    &amp;#39;django.template.loaders.filesystem.load_template_source&amp;#39;,
    &amp;#39;django.template.loaders.app_directories.load_template_source&amp;#39;,
    &amp;#39;dgrid.load_template_source&amp;#39;
#     &amp;#39;django.template.loaders.eggs.load_template_source&amp;#39;,
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;You can do access a template using an absolute path.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;In [6]: get_template(&amp;#39;/home/shabda/abc.txt&amp;#39;)
Out[6]: &amp;lt;django.template.Template object at 0x91c860c&amp;gt;

In [7]: temp = get_template(&amp;#39;/home/shabda/abc.txt&amp;#39;)

In [8]: temp
Out[8]: &amp;lt;django.template.Template object at 0x9358a0c&amp;gt;

In [9]: temp.render
Out[9]: &amp;lt;bound method Template.render of &amp;lt;django.template.Template object at 0x9358a0c&amp;gt;&amp;gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;hr /&gt;
&lt;p&gt;This is the first in the series of &lt;code&gt;short and sweet&lt;/code&gt; Django posts we are going to do. You are interested, right. Do follow us on &lt;a href="http://twitter.com/uswaretech"&gt;twitter&lt;/a&gt; or &lt;a href="http://feeds.feedburner.com/uswarearticles"&gt;subscribe to our feed&lt;/a&gt;.&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;We build &lt;em&gt;Amazing We Apps&lt;/em&gt;. &lt;a href="http://uswaretech.com/contact/"&gt;Talk to us&lt;/a&gt; or email us at sales@uswaretech.com .&lt;/p&gt;</description><guid>http://agiliq.com/blog/2009/11/writing-your-own-template-loaders/</guid></item><item><title>Django gotchas </title><link>http://agiliq.com/blog/2009/11/django-gotchas/</link><description>&lt;p&gt;This is announcement about our new work,  &lt;a href="http://djangogotchas.uswaretech.net/"&gt;Django Gotchas&lt;/a&gt;, a teeny tiny ebook about commonly occurring gotchas with Django. Here is the readme copied from the project.&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;Django-gotchas is a collections of gotchas which happen commonly when you are working with Django.
They are some errors which I have made commonly or seen others do, these are not the errors which
happen because they are hard to reason about, these are those errors which hapen when you close your
eyes for a moment when coding.&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;This is still very much a work in progress, released in the spirit of release early, release often. Click here to get it, or fork it on &lt;a href="http://bitbucket.org/uswaretech/django-gotchas/"&gt;Bitbucket&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;In Other news&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;We have slightly updated the &lt;a href="http://github.com/uswaretech/django-design-patterns/tree/master"&gt;Django design patterns&lt;/a&gt;, though not the public website.&lt;/li&gt;
&lt;li&gt;&lt;a href="http://github.com/cyrildoussin"&gt;cyrildoussin&lt;/a&gt; has done a lot of changes to Socialauth and made it much better.  &lt;a href="http://github.com/cyrildoussin/Django-Socialauth"&gt;You can get it here&lt;/a&gt; . Thank! We will be merging this soon.&lt;/li&gt;
&lt;/ul&gt;</description><guid>http://agiliq.com/blog/2009/11/django-gotchas/</guid></item><item><title>Django-SocialAuth - Login via twitter, facebook, openid, yahoo, google using a single app.</title><link>http://agiliq.com/blog/2009/08/django-socialauth-login-via-twitter-facebook-openi/</link><description>&lt;p&gt;TL;DR version: Here is an app to allow logging in via twitter, facebook, openid, yahoo, google, which should work transparently with Django authentication system. (@login_required, User and other infrastructure work as expected.) &lt;a href="http://socialauth.uswaretech.net/"&gt;Demo&lt;/a&gt; and &lt;a href="http://github.com/uswaretech/Django-Socialauth/tree/master"&gt;Code&lt;/a&gt;.Longer version follow:&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;We are releasing our new app. &lt;a href="http://github.com/uswaretech/Django-Socialauth/tree/master"&gt;&lt;strong&gt;Django-Socialauth&lt;/strong&gt;&lt;/a&gt;. This app makes it awfully easy,
to allow users to login your site using Yahoo/Google/Twitter/Facebook/Openid. A demo is available &lt;a href="http://socialauth.uswaretech.net/"&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;This is released under an &lt;a href="http://www.opensource.org/licenses/attribution.php"&gt;Attribution Assurance License&lt;/a&gt;. A copy of the same is
provided included with the code.&lt;/p&gt;
&lt;p&gt;After installing this app, you can use @login_required on any view and users identified
via any means can access protected content.&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;We provide services to integrate and implement this, for a low price of USD 1600.
Please contact us at &lt;a href="mailto:licenses@uswaretech.com"&gt;licenses@uswaretech.com&lt;/a&gt; to discuss your exact needs.&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;The README is copied here for convenience.&lt;/p&gt;
&lt;h3&gt;What it does.&lt;/h3&gt;
&lt;p&gt;Allow logging in via various providers.&lt;/p&gt;
&lt;h4&gt;Logging In&lt;/h4&gt;
&lt;p&gt;This is a application to enable authentication via various third party sites.
In particular it allows logging in via&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Twitter&lt;/li&gt;
&lt;li&gt;Gmail&lt;/li&gt;
&lt;li&gt;Facebook&lt;/li&gt;
&lt;li&gt;Yahoo(Essentially openid)&lt;/li&gt;
&lt;li&gt;OpenId&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Libs you need to install&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a href="http://pypi.python.org/pypi/python-openid/"&gt;python-openid&lt;/a&gt; (&lt;code&gt;easy_install&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;python-yadis (&lt;code&gt;easy_install&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;&lt;a href="http://oauth.googlecode.com/svn/code/python/oauth/"&gt;python-oauth&lt;/a&gt;(&lt;code&gt;easy_install&lt;/code&gt;)&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The API Keys are available from&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="http://www.facebook.com/developers/createapp.php"&gt;http://www.facebook.com/developers/createapp.php&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developer.yahoo.com/dashboard/createKey.html"&gt;https://developer.yahoo.com/dashboard/createKey.html&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.google.com/accounts/ManageDomains"&gt;https://www.google.com/accounts/ManageDomains&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://twitter.com/oauth_clients"&gt;http://twitter.com/oauth_clients&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;How it works.&lt;/h4&gt;
&lt;p&gt;Openid: Users need to provide their openid providers. Talk to the providers and
login.&lt;br /&gt;
Yahoo: Yahoo is an openid provider. Talk to Yahoo endpoints. (Endpoint: http://yahoo.com)&lt;br /&gt;
Google: Google is a provider. Talk to them. (Endpoint: https://www.google.com/accounts/o8/id)&lt;br /&gt;
Facebook: Facebook connect provides authentication framework.&lt;br /&gt;
Twitter: We use Twitter Oauth for authentication. In theory, Oauth shouldn't be
used for authentication. (It is an autorisation framework, not an authentication one),
In practice it works pretty well. Once you have an access_token, and a name, essentially
authenticated.&lt;br /&gt;
&lt;/p&gt;
&lt;p&gt;References&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a href="http://socialauth.uswaretech.net/"&gt;Demo of app&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://github.com/uswaretech/Django-Socialauth/tree/master"&gt;Code for app&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://openid.net/developers/"&gt;http://openid.net/developers/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://developer.yahoo.com/openid/"&gt;http://developer.yahoo.com/openid/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://code.google.com/apis/accounts/docs/OpenID.html"&gt;http://code.google.com/apis/accounts/docs/OpenID.html&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://apiwiki.twitter.com/OAuth-FAQ"&gt;http://apiwiki.twitter.com/OAuth-FAQ&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://developers.facebook.com/connect.php"&gt;http://developers.facebook.com/connect.php&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;Below the hoods&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;For all providers(except Facebook) there are two urls and views. (start and done)&lt;/li&gt;
&lt;li&gt;Start sets up the required tokens, and redirects and hands off to the correct
provider.&lt;/li&gt;
&lt;li&gt;Provider handles authentication on their ends, and hands off to Us, providing
authorization tokens.&lt;/li&gt;
&lt;li&gt;In done, we check if the user with these details already exists, if yes, we
log them in. Otherwise we create a new user, and log them in.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;For all of these, we use standard django authenication system, with custom
&lt;code&gt;auth_backends&lt;/code&gt;, hence all existing views, and decorators as &lt;code&gt;login_required&lt;/code&gt;
will work as expected.&lt;/p&gt;
&lt;h2&gt;Urls&lt;/h2&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;/login/ Login page. Has all the login options  
/openid_login/ AND /openid_login/done/  
/yahoo_login/ AND /yahoo_login/done/  
/gmail_login/ AND /gmail_login/done/  
/twitter_login/ AND /twitter_login/done/  
/facebook_login/done/ We dont have a start url here, as the starting tokens are  
set in a popup, as per FB Connect recommendations.
&lt;/pre&gt;&lt;/div&gt;


&lt;h2&gt;Implementation&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;Install required libraries.&lt;/li&gt;
&lt;li&gt;Get tokens and populate in localsettings.py&lt;/li&gt;
&lt;li&gt;Set the token callback urls correctly at Twitter and Facebook.&lt;/li&gt;
&lt;li&gt;Add the OpenId middleware. Set the Authentication backends. (Set in localsettings.example.py)&lt;/li&gt;
&lt;/ol&gt;</description><guid>http://agiliq.com/blog/2009/08/django-socialauth-login-via-twitter-facebook-openi/</guid></item><item><title>A response to Dropping Django</title><link>http://agiliq.com/blog/2009/08/a-response-to-dropping-django/</link><description>&lt;p&gt;&lt;a href="http://blog.brandonbloom.name/2009/08/dropping-django.html"&gt;Brandon Bloom&lt;/a&gt; yesterday wrote an interesting post titled
dropping Django. Despite a lot of hand waving(We needed a pragmatic template language to replace Django's idealistic one.),
it raises some valid questions, so here is a solution to some of them.&lt;/p&gt;
&lt;h4&gt;No support for hierarchical url creation.&lt;/h4&gt;
&lt;p&gt;The simplest representation of nested urls I can think of is a nested tuple. Lets represent,
the urls for a simple app by,&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&amp;gt;&amp;gt;&amp;gt; tree_urls = (&amp;#39;&amp;#39;, &amp;#39;list&amp;#39;,
...     (&amp;#39;edit/&amp;#39;, &amp;#39;edit&amp;#39;, (&amp;#39;auto/&amp;#39;, &amp;#39;edit_auto&amp;#39;)),
...     (&amp;#39;^add/&amp;#39;, &amp;#39;add&amp;#39;),
...     (&amp;#39;delete/&amp;#39;, &amp;#39;delete&amp;#39;, (&amp;#39;hard/&amp;#39;, &amp;#39;delete_hard&amp;#39;))
...     )
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Guess what, urls.py is &lt;em&gt;just a python module which excepts a variable names urlpatterns&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;Which means it is very easy to write a function which converts this nested structure to flat, structure.
Here is a quick attempt at that,&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;def merge(url):
    full_url=[]
    for i, el in enumerate(url):
        if i%2==0:    
            full_url.append(el)
    full_url = &amp;#39;&amp;#39;.join(full_url)
    return full_url

def combineflatten(seq):
    items= tuple(item for item in seq if not isinstance(item, tuple))
    yield items
    for item in seq:
            if isinstance(item, tuple):
                for yielded in combineflatten(item):
                    yield items+yielded

def generate_flat_urls(tree_urls):
    &amp;quot;&amp;quot;&amp;quot;
    &amp;gt;&amp;gt;&amp;gt; tree_urls = (&amp;#39;&amp;#39;, &amp;#39;list&amp;#39;,
    ...     (&amp;#39;edit/&amp;#39;, &amp;#39;edit&amp;#39;, (&amp;#39;auto/&amp;#39;, &amp;#39;edit_auto&amp;#39;)),
    ...     (&amp;#39;^add/&amp;#39;, &amp;#39;add&amp;#39;),
    ...     (&amp;#39;delete/&amp;#39;, &amp;#39;delete&amp;#39;, (&amp;#39;delete/&amp;#39;, &amp;#39;delete_hard&amp;#39;))
    ...     )

    &amp;gt;&amp;gt;&amp;gt; generate_flat_urls(tree_urls)
    [(&amp;#39;^$&amp;#39;, &amp;#39;list&amp;#39;), (&amp;#39;^edit/$&amp;#39;, &amp;#39;edit&amp;#39;), (&amp;#39;^edit/auto/$&amp;#39;, &amp;#39;edit_auto&amp;#39;), (&amp;#39;^^add/$&amp;#39;, &amp;#39;add&amp;#39;), (&amp;#39;^delete/$&amp;#39;, &amp;#39;delete&amp;#39;), (&amp;#39;^delete/delete/$&amp;#39;, &amp;#39;delete_hard&amp;#39;)]
    &amp;quot;&amp;quot;&amp;quot;
    return [(&amp;#39;^%s$&amp;#39;%merge(el), el[-1]) for el in tuple(combineflatten(tree_urls))]
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;With this you can use hierarchical urls in urls.py as,&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;#All of urls.py
tree_urls = (&amp;#39;&amp;#39;, &amp;#39;list&amp;#39;,
    (&amp;#39;edit/&amp;#39;, &amp;#39;edit&amp;#39;, (&amp;#39;auto/&amp;#39;, &amp;#39;edit_auto&amp;#39;)),
    (&amp;#39;^add/&amp;#39;, &amp;#39;add&amp;#39;),
    (&amp;#39;delete/&amp;#39;, &amp;#39;delete&amp;#39;, (&amp;#39;delete/&amp;#39;, &amp;#39;delete_hard&amp;#39;))
    )

flat_urls = generate_flat_urls(tree_urls)

urlpatterns = patterns(&amp;#39;app.views&amp;#39;,
**flat_urls
)
&lt;/pre&gt;&lt;/div&gt;


&lt;h4&gt;No support for per user, per resource authorisation.&lt;/h4&gt;
&lt;p&gt;If you want to do this in a almost no-touching-the-existing-code way, replace all your &lt;code&gt;render_to_response&lt;/code&gt; with,&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;def render_with_auth_check(request, payload, request_context, *args, **kwrags):
    for el in payload.itervalues():
        try:
            has_auth = el.check_auth(request.user)
            if not has_auth:
                raise AuthFailException
        except ValueError:
            pass #Not all objects have check_auth
    return render_to_response(request, payload, request_context, *args, **kwrags)
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;And enable this middleware,&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;class AuthFailHandlerMiddleware:
    def process_exception(self, request, exception):
        if type(exception) == AuthFailException:
            return render_to_response(&amp;#39;accounts/login/&amp;#39;, {}, RequestContext(request))
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;This assumes that all resources which are authorisation protected have a &lt;code&gt;.check_auth&lt;/code&gt;,
but I cant see any way round that in any other way as well.&lt;/p&gt;
&lt;p&gt;A different, and more robust way would be to write custom managers for all resources, which need authorization.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;class ResourceAuthManager(models.Manager):
    def get(self, user, *args, **kwargs):
        res = super(ResourceAuthManager, self).get(*args, **kwargs)
        try:
            has_auth = res.check_auth(request.user)
            if not has_auth:
                raise AuthFailException
        except ValueError:
            pass #Not all objects have check_auth

    ...
&lt;/pre&gt;&lt;/div&gt;


&lt;h4&gt;The Django templating language is too constrained.&lt;/h4&gt;
&lt;p&gt;Despite believing that Django templating language hits the sweet spot between, power
and convenience to &lt;em&gt;people who would be using it&lt;/em&gt;, I never understood this argument,&lt;/p&gt;
&lt;p&gt;If you are using sqlalchemy with Django you lose the admin, what do you lose if you use Jinja?&lt;/p&gt;
&lt;p&gt;In particular what do you lose by replacing &lt;code&gt;render_to_response&lt;/code&gt; with this,&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;def render_jinja_to_response(template_name, payload):
    #This should probably go in settings.py
    from jinja2 import Environment
    env = Environment(loader=PackageLoader(&amp;#39;app&amp;#39;, &amp;#39;templates&amp;#39;))

    template = env.get_template(template_name)
    response = template.render(**payload)
    return HttpResponse(response)
&lt;/pre&gt;&lt;/div&gt;


&lt;h4&gt;Extending authentication - In particular enable loggin in with email&lt;/h4&gt;
&lt;p&gt;Django authenticates against a &lt;a href="http://www.google.co.in/search?hl=en&amp;amp;client=firefox-a&amp;amp;rls=org.mozilla%3Aen-US%3Aofficial&amp;amp;hs=GGQ&amp;amp;q=authentication+backends+site%3Adjangosnippets.org&amp;amp;btnG=Search&amp;amp;meta=&amp;amp;aq=f&amp;amp;oq="&gt;wide range of backends&lt;/a&gt;,
including Email, LDAP, Twitter and Facebook. While it is true that email backend doesn't work
with Admin login, Admin is meant for use by staff and superusers, so why cant we provide
them usernames?&lt;/p&gt;
&lt;p&gt;There are a few other questions raised, some of which I agree with("Sadly, it[the admin app]
struggles a little bit with nullable fields and is tricky to customize."), and some which I dont,
("I will never write CSS by hand again." - You shouldn't be, someone else on your team should be doing that. )
But this line is interesting &lt;code&gt;Personally, I've developed a moderate fear of the word "framework"&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;This is arguable, but the way all frameworks essentially help you is by providing
Dependency Injection, (the Hollywood principle - Dont call me, I will call you).
Django provides that in a lot of ways. (You write a middleware, and django calls
it at appropriate places - Dont call me, I will call you), but still leaves something to be desired.
My ideal framework would be one where models are POPO and views are functions which return strings
. (Plain old python objects -like POJO). &lt;a href="http://java.sun.com/developer/technicalArticles/J2EE/jpa/figure6.html"&gt;JPA&lt;/a&gt; does this correctly,
but then JPA has the typing information, so maybe in python the only way to provide the required typing
information is &lt;code&gt;name=models.CharField(...)&lt;/code&gt;. But the point being, we need better Dependency Inversion,
not less of it. We have been dow that path earlier, and it is a much harder way to build complex systems.&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;Resources&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a href="http://gist.github.com/171016"&gt;This code on github&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://stackoverflow.com/questions/1302653/convert-a-nested-dataset-to-a-flat-dataset-while-retaining-enough-data-to-conver"&gt;Discussion about converting the nested tuple to a flat one&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;hr /&gt;
&lt;p&gt;My apologies if this post was aggressive, argumentative or disrespectful to the
original author. We generally try to stay away from controversial posts on this blog. But
I believe that this post raised some valid technical questions, and the intent of this
post was to answer them. For Django to develop the best way, we need more of these kind
of "What is wrong with Django" posts, not less, so my thanks to the original author. :)&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;Do you want to build &lt;strong&gt;Amazing Web Apps&lt;/strong&gt;? &lt;a href="http://uswaretech.com/contact/"&gt;We can help&lt;/a&gt;.&lt;/p&gt;</description><guid>http://agiliq.com/blog/2009/08/a-response-to-dropping-django/</guid></item><item><title>Django aggregation tutorial</title><link>http://agiliq.com/blog/2009/08/django-aggregation-tutorial/</link><description>&lt;p&gt;One of the new and most awaited features with Django 1.1 was aggregation. As usual,
Django comes with a very &lt;a href="http://docs.djangoproject.com/en/dev/topics/db/aggregation/"&gt;comprehensive documentation&lt;/a&gt; for this. Here, I have tried to
put this in how-to form.&lt;/p&gt;
&lt;p&gt;&lt;a href="#howtos"&gt;Jump to howtos&lt;/a&gt; or &lt;a href="http://github.com/uswaretech/Shiny-New-Django-1.1/tree/master"&gt;Get source on Github&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Essentially, aggregations are nothing but a way to perform an operation on group of rows. In databases,
they are represented by operators as &lt;code&gt;sum&lt;/code&gt;, &lt;code&gt;avg&lt;/code&gt; etc.&lt;/p&gt;
&lt;p&gt;To do these operations Django added two new methods to querysets.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;code&gt;aggregate&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;annotate&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;When you are have a queryset you can do two operations on it,&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Operate over the rowset to get a single value from it. (Such as sum of all salaries in the rowset)&lt;/li&gt;
&lt;li&gt;Operate over the rowset to get a value for &lt;em&gt;each row in the rowset&lt;/em&gt; via some related table.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The thing to notice is that option 1, will create one row from rowset, while option 2 will
not change the number of rows in the rowset. If you are into analogies, you can think that
option 1 is like a &lt;a href="http://docs.python.org/library/functions.html#reduce"&gt;reduce&lt;/a&gt; and option 2 is like a &lt;a href="http://docs.python.org/library/functions.html#map"&gt;map&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;In sql terms, aggregate is a operation(SUM, AVG, MIN, MAX), without a group by,
while annotate is a operation with a group by on rowset_table.id. (Unless explicitly overriden).&lt;/p&gt;
&lt;p&gt;&lt;a name="howtos" &gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Ok enough talk, on to some actual work. Here is a fictional models.py representing
a HRMS application. We will use this to see how to use aggreagtion to solve
some common problems.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;from django.db import models

class Department(models.Model):
    dept_name = models.CharField(max_length = 100)
    established_on = models.DateField()

    def __unicode__(self):
        return self.dept_name

class Level(models.Model):
    level_name = models.CharField(max_length = 100)
    pay_min = models.PositiveIntegerField()
    pay_max = models.PositiveIntegerField()

    def __unicode__(self):
        return self.level_name

class Employee(models.Model):
    emp_name = models.CharField(max_length = 100)
    department = models.ForeignKey(Department)
    level = models.ForeignKey(Level)
    reports_to = models.ForeignKey(&amp;#39;self&amp;#39;, null=True, blank=True)

    pay = models.PositiveIntegerField()
    joined_on = models.DateField()

class Leave(models.Model):
    employee = models.ForeignKey(Employee)
    leave_day = models.DateField()

&amp;quot;&amp;quot;&amp;quot;
#Populate DB, so we can do some meaningful queries.
#Create Dept, Levels manually.
#Get the names file from http://dl.getdropbox.com/u/271935/djaggregations/names.pickle
#Or the whole sqlite database from http://dl.getdropbox.com/u/271935/djaggregations/bata.db
import random
from datetime import timedelta, date
import pickle
names = pickle.load(file(&amp;#39;/home/shabda/names.pickle&amp;#39;))
for i in range(1000):
    emp = Employee()
    emp.name = random.choice(names)
    emp.department = random.choice(list(Department.objects.all()))
    emp.level = random.choice(Level.objects.all())
    try: emp.reports_to = random.choice(list(Employee.objects.filter(department=emp.department)))
    except:pass
    emp.pay = random.randint(emp.level.pay_min, emp.level.pay_max)
    emp.joined_on = emp.department.established_on + timedelta(days = random.randint(0, 200))
    emp.save()
&amp;quot;&amp;quot;&amp;quot;

&amp;quot;&amp;quot;&amp;quot;
employees = list(Employees.objects.all())
for i in range(100):
    employee = random.choice(employees)
    leave = Leave(employee = employee)
    leave.leave_day = date.today() - timedelta(days = random.randint(0, 365))
    leave.save()

&amp;quot;&amp;quot;&amp;quot;
&lt;/pre&gt;&lt;/div&gt;


&lt;h4&gt;Find the total number of employees.&lt;/h4&gt;
&lt;p&gt;In sql you might want to do something like,&lt;/p&gt;
&lt;p&gt;&lt;code&gt;select count(id) from hrms_employee&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;Which becomes,&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Employee.objects.all().aggregate(total=Count('id'))&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;If fact doing a &lt;code&gt;connection.queries.pop()&lt;/code&gt; shows the exact query.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;SELECT COUNT("hrms_employee"."id") AS "total" FROM "hrms_employee"&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;But wait, we have a builtin method already for that, &lt;code&gt;Employee.objects.all().count()&lt;/code&gt;, so lets try something else.&lt;/p&gt;
&lt;h4&gt;Find the total pay of employees.&lt;/h4&gt;
&lt;p&gt;The CEO wants to find out what is the total salary expediture, this also converts
the queryset to a single value, so we want to &lt;code&gt;.aggregate&lt;/code&gt; here.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Employee.objects.all().aggregate(total_payment=Sum('pay'))&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;Gives you the total amount you are paying to your employees.&lt;/p&gt;
&lt;h4&gt;Find the total number of employees, per department.&lt;/h4&gt;
&lt;p&gt;Here we want a value per row in queryset, so we need to use aggregate here. Also,
there would be one aggregated value per dpeartment, so we need to annotate Department
queryset.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Department.objects.all().annotate(Count('employee'))&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;If you are only interested in name of department and employee count for it, you can do,
&lt;code&gt;Department.objects.values('dept_name').annotate(Count('employee'))&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;The sql is&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;SELECT &amp;quot;hrms_department&amp;quot;.&amp;quot;dept_name&amp;quot;, COUNT(&amp;quot;hrms_employee&amp;quot;.&amp;quot;id&amp;quot;) AS &amp;quot;employee__count&amp;quot; FROM &amp;quot;hrms_department&amp;quot; LEFT OUTER JOIN &amp;quot;hrms_employee&amp;quot; ON (&amp;quot;hrms_department&amp;quot;.&amp;quot;id&amp;quot; = &amp;quot;hrms_employee&amp;quot;.&amp;quot;department_id&amp;quot;) GROUP BY &amp;quot;hrms_department&amp;quot;.&amp;quot;dept_name&amp;quot;
&lt;/pre&gt;&lt;/div&gt;


&lt;h4&gt;Find the total number of employees, for a specific department.&lt;/h4&gt;
&lt;p&gt;Here you could use either of &lt;code&gt;.annotate&lt;/code&gt; or &lt;code&gt;.aggregate&lt;/code&gt;,&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;Department.objects.filter(dept_name=&amp;#39;Sales&amp;#39;).values(&amp;#39;dept_name&amp;#39;).annotate(Count(&amp;#39;employee&amp;#39;))
Department.objects.filter(dept_name=&amp;#39;Sales&amp;#39;).aggregate(Count(&amp;#39;employee&amp;#39;))
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;If you see the SQLs, you will see that &lt;code&gt;.annotate&lt;/code&gt; did a &lt;code&gt;group by&lt;/code&gt;, while the &lt;code&gt;.aggregate&lt;/code&gt;
did not, but as there was only one row, &lt;code&gt;group by&lt;/code&gt; had no effect.&lt;/p&gt;
&lt;h4&gt;Find the total number of employees, per department, per level&lt;/h4&gt;
&lt;p&gt;This time, we can not annotate either Department model, or the Level model, as we
need to &lt;code&gt;group by&lt;/code&gt; both department and level. So we will annotate on Employee&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;Employee.objects.values(&amp;#39;department__dept_name&amp;#39;, &amp;#39;level__level_name&amp;#39;).annotate(Count(&amp;#39;id&amp;#39;))
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;This leads to the sql,&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;SELECT &amp;quot;hrms_department&amp;quot;.&amp;quot;dept_name&amp;quot;, &amp;quot;hrms_level&amp;quot;.&amp;quot;level_name&amp;quot;, COUNT(&amp;quot;hrms_employee&amp;quot;.&amp;quot;id&amp;quot;) AS &amp;quot;id__count&amp;quot; FROM &amp;quot;hrms_employee&amp;quot; INNER JOIN &amp;quot;hrms_department&amp;quot; ON (&amp;quot;hrms_employee&amp;quot;.&amp;quot;department_id&amp;quot; = &amp;quot;hrms_department&amp;quot;.&amp;quot;id&amp;quot;) INNER JOIN &amp;quot;hrms_level&amp;quot; ON (&amp;quot;hrms_employee&amp;quot;.&amp;quot;level_id&amp;quot; = &amp;quot;hrms_level&amp;quot;.&amp;quot;id&amp;quot;) GROUP BY &amp;quot;hrms_department&amp;quot;.&amp;quot;dept_name&amp;quot;, &amp;quot;hrms_level&amp;quot;.&amp;quot;level_name
&lt;/pre&gt;&lt;/div&gt;


&lt;h4&gt;Which combination of Employee and Deparments employes the most people&lt;/h4&gt;
&lt;p&gt;We can order on the annotated fields, so the last query is modified to,&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;Employee.objects.values(&amp;#39;department__dept_name&amp;#39;, &amp;#39;level__level_name&amp;#39;).annotate(employee_count = Count(&amp;#39;id&amp;#39;)).order_by(&amp;#39;-employee_count&amp;#39;)[:1]
&lt;/pre&gt;&lt;/div&gt;


&lt;h4&gt;Which employee name is the most common.&lt;/h4&gt;
&lt;p&gt;We can want to &lt;code&gt;group by emp_name&lt;/code&gt;, so &lt;code&gt;emp_name&lt;/code&gt; is added to values. After that we order on the annotated field
and get the first element, to get the most common name.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Employee.objects.values('emp_name').annotate(name_count=Count('id')).order_by('-name_count')[:1]&lt;/code&gt;&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;This was a overview of how django annotations work. These remove a whole class of queries for which
you had to use custom sql queries in the past.&lt;/p&gt;
&lt;hr /&gt;
&lt;h3&gt;Resources&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a href="http://github.com/uswaretech/Shiny-New-Django-1.1/tree/master"&gt;Source on Github&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://dl.getdropbox.com/u/271935/djaggregations/bata.db"&gt;sqlite file for this model to test&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://docs.djangoproject.com/en/dev/topics/db/aggregation/"&gt;Aggregation on Django docs&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;hr /&gt;
&lt;p&gt;Want to build a Django app? &lt;a href="http://uswaretech.com/contact/"&gt;Talk to us&lt;/a&gt;&lt;/p&gt;</description><guid>http://agiliq.com/blog/2009/08/django-aggregation-tutorial/</guid></item><item><title>Aren&amp;#39;t django signals a little like comefrom?</title><link>http://agiliq.com/blog/2009/07/arent-django-signals-a-little-like-comefrom/</link><description>&lt;p&gt;&lt;blockquote class="right"&gt;&lt;br /&gt;In computer programming, COMEFROM (or COME FROM) is an obscure control flow&lt;br /&gt;structure used in some programming languages, primarily as a joke.&lt;br /&gt;&lt;/blockquote&gt;&lt;/p&gt;

&lt;p&gt;I never liked using signals. Recently I was asked that, and has no answer, but a little thinking led me to this question. Aren't signals a little like COMEFROM. If yes, aren't they as bad as COMEFROM? If you do not know what a COMEFROM is, [wikipedia to the rescue](http://en.wikipedia.org/wiki/COMEFROM)&lt;br /&gt;   &lt;br /&gt;Some hypothetical code using COMEFROM, again from wikipedia,&lt;/p&gt;

&lt;p&gt;    from goto import comefrom, label&lt;br /&gt;    comefrom .repeat&lt;br /&gt;    name = raw_input('what is your name? ')&lt;br /&gt;    if name:&lt;br /&gt;        print "Hello",name&lt;br /&gt;        label .repeat&lt;br /&gt;    print "Goodbye!"&lt;br /&gt;    &lt;br /&gt;    &lt;br /&gt;And Some actual Django code using signals&lt;/p&gt;

&lt;p&gt;    class Post(models.Model):&lt;br /&gt;        name = models.CharField(...)&lt;br /&gt;        ...&lt;br /&gt;        num_comments = models.PositiveIntegerField(default = 0)&lt;br /&gt;        &lt;br /&gt;    class Comment(models.Model):&lt;br /&gt;        ...&lt;br /&gt;        post = models.ForeignKey(Post)&lt;br /&gt;        &lt;br /&gt;    def handle_num_comments(sender, **kwargs):&lt;br /&gt;        instance = kwargs['instance']&lt;br /&gt;        instance.post.num_comments+=1&lt;br /&gt;        instance.post.save()&lt;br /&gt;        &lt;br /&gt;    from django.db.signals import post_save&lt;br /&gt;    &lt;br /&gt;    post_save.connect(handle_num_comments, sender=Comment)&lt;br /&gt;    &lt;br /&gt;And the same code using COMEFROM&lt;/p&gt;

&lt;p&gt;    class Post(models.Model):&lt;br /&gt;        name = models.CharField(...)&lt;br /&gt;        ...&lt;br /&gt;        num_comments = models.PositiveIntegerField(default = 0)&lt;br /&gt;        &lt;br /&gt;    class Comment(models.Model):&lt;br /&gt;        ...&lt;br /&gt;        post = models.ForeignKey(Post)&lt;br /&gt;        &lt;br /&gt;        def save(self, *args, **kwargs):&lt;br /&gt;            super(Comment, self).save(*args, **kwargs)&lt;br /&gt;            instance = self&lt;br /&gt;            LABEL .post_save&lt;br /&gt;        &lt;br /&gt;    def handle_num_comments(sender, **kwargs):&lt;br /&gt;        instance = kwargs['instance']&lt;br /&gt;        COMEFROM .post_save&lt;br /&gt;        instance.post.num_comments+=1&lt;br /&gt;        instance.post.save()&lt;br /&gt;        &lt;br /&gt;So isn't the signals code a little like COMEFROM, and why is it superior to COMEFROM?&lt;/p&gt;

&lt;p&gt;--------------&lt;br /&gt;* [There is a library to add goto and comefrom to Python](http://entrian.com/goto/)&lt;br /&gt;* [Discussion about COMEFROM](http://www.c2.com/cgi/wiki?ComeFrom)&lt;/p&gt;

&lt;p&gt;-------------&lt;br /&gt;You should follow me on [twitter here](http://twitter.com/uswaretech).&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;</description><guid>http://agiliq.com/blog/2009/07/arent-django-signals-a-little-like-comefrom/</guid></item><item><title>Django design patterns</title><link>http://agiliq.com/blog/2009/07/django-design-patterns/</link><description>&lt;p&gt;This is announcement about our new work, &lt;a href="http://djangodesignpatterns.uswaretech.net/"&gt;Django design patterns&lt;/a&gt;, a ebook about, well, Django design patterns. (Well imagine that!). Here is the readme copied from there.&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;[Edit] Syntax highlighting and indentation preservation were totally brroken. Fixed now.&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;Django design patterns is a book about commonly occuring patterns in Django. Not
patterns in Gof sense, but patterns in the sense, we work this way, and it works
for us. For us it is a ~pattern of work~ sense.&lt;/p&gt;
&lt;p&gt;At this point this is just a lot of brain dump from us.&lt;/p&gt;
&lt;p&gt;The latest sources are always available from
http://github.com/uswaretech/django-design-patterns/tree/master
and latest html from http://djangodesignpatterns.uswaretech.net/&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;Please leave errata, feedback, critique as comments here.&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;This is still very much a work in progress, released in the spirit of release early, release often. &lt;a href="http://djangodesignpatterns.uswaretech.net/"&gt;Click here&lt;/a&gt; to get it, or &lt;a href="http://github.com/uswaretech/django-design-patterns/tree/master"&gt;fork it on Github&lt;/a&gt;&lt;/p&gt;</description><guid>http://agiliq.com/blog/2009/07/django-design-patterns/</guid></item><item><title>Remote debugging - debugging pesky server only bugs</title><link>http://agiliq.com/blog/2009/07/remote-debugging-debugging-pesky-server-only-bugs/</link><description>&lt;p&gt;Here is a quick tip. (Obvious if you work with Django for any length of time, but I have seen a few people who are not aware)&lt;/p&gt;
&lt;p&gt;You can put debug trace &lt;code&gt;import pdb; pdb.set_trace()&lt;/code&gt; in your code, and put it on the server. When you access this view from your local browser, the debug is still hit and you have a debug shell on your server where you can step through. (Obviously this works only if you ran the code via &lt;code&gt;manage.py runserver&lt;/code&gt;. But &lt;code&gt;manage.py runserver&lt;/code&gt; start the server to listen only on local connections. If you want to access remotely you need to run as,&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;python manage.py runserver 0.0.0.0:8000
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Edit: As &lt;a href="http://tactful.co.nz/"&gt;SmileyChris&lt;/a&gt; commented, a faster way is,&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;python manage.py runserver 0:8000
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;The &lt;code&gt;0.0.0.0&lt;/code&gt; implies that remote connections are possible.&lt;/p&gt;
&lt;p&gt;For me, this has been a lifesaver against those pesky bugs which show themselves only on the server, but not on the local machine.&lt;/p&gt;</description><guid>http://agiliq.com/blog/2009/07/remote-debugging-debugging-pesky-server-only-bugs/</guid></item><item><title>Django Request Response processing</title><link>http://agiliq.com/blog/2009/06/django-request-response-processing/</link><description>&lt;p&gt;Have you wondered the steps a users request goes through before being responded to by Django? The answer lies in reading &lt;code&gt;django.core.handlers.base&lt;/code&gt; and &lt;code&gt;django.core.handlers.wsgi&lt;/code&gt;. Here is a diagram explaining what happens. (&lt;a href="http://uswaretech.com/blog/wp-content/uploads/2009/06/django_request_response_lifecycle.png"&gt;Click to enlarge&lt;/a&gt;.)&lt;/p&gt;
&lt;p&gt;&lt;a href="http://uswaretech.com/blog/wp-content/uploads/2009/06/django_request_response_lifecycle.png"&gt;&lt;img src="http://uswaretech.com/blog/wp-content/uploads/2009/06/django_request_response_lifecycle-300x207.png" alt="" title="django_request_response_lifecycle" width="300" height="207" class="alignnone size-medium wp-image-587" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;The steps are.
(With Apache/Mod_wsgi, similar steps for other setup.)&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;User's request comes to Apache etc.&lt;/li&gt;
&lt;li&gt;Apache sends request to &lt;code&gt;django.core.handlers.wsgi&lt;/code&gt; via &lt;code&gt;mod_wsgi&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;A list of request and response middleware callables is created.&lt;/li&gt;
&lt;li&gt;Request middleware is applied. If it sends a response, it is returned to the user.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;urlresolvers.resolve&lt;/code&gt; finds the view funcion to use.&lt;/li&gt;
&lt;li&gt;View middleware is applied. If response comes, it is sent back to the user.&lt;/li&gt;
&lt;li&gt;View function is called. It talks to models to do business logic, and renders the templates.&lt;/li&gt;
&lt;li&gt;The response middleware is applied, and response is sent back to the users.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;This misses a lot of important steps (Exception middleware, request_context populating, ...) but is a basic high level overview. &lt;/p&gt;
&lt;p&gt;Resources&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="http://code.djangoproject.com/browser/django/trunk/django/core/handlers/base.py"&gt;django/core/handlers/base.py&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://code.djangoproject.com/browser/django/trunk/django/core/handlers/wsgi.py"&gt;django/core/handlers/wsgi.py&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://github.com/uswaretech/Django-Request-Response/tree/master"&gt;.dia and other files for the image&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;p&gt;Do you &lt;a href="http://twitter.com/uswaretech"&gt;twitter&lt;/a&gt;? Do you &lt;a href="http://github.com/uswaretech"&gt;Github&lt;/a&gt;? Find us there.&lt;/p&gt;</description><guid>http://agiliq.com/blog/2009/06/django-request-response-processing/</guid></item><item><title>Better Python package management using source and version control systems</title><link>http://agiliq.com/blog/2009/06/better-python-package-management-using-source-and-/</link><description>&lt;p&gt;Thanks to awesome &lt;a href="http://www.djangoproject.com/community/"&gt;django community&lt;/a&gt;, there is plenty of open source &lt;a href="http://code.google.com/hosting/search?q=django&amp;amp;projectsearch=Search+projects"&gt;django&lt;/a&gt; &lt;a href="http://bitbucket.org/repo/all/?name=django"&gt;code&lt;/a&gt; &lt;a href="http://github.com/search?q=django&amp;amp;type=Everything&amp;amp;repo=&amp;amp;langOverride=&amp;amp;start_value=1"&gt;around&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;These packages get updated quite often and if you use it often like we do, you'd have possibly realized the need to manage these packages better.&lt;/p&gt;
&lt;p&gt;Thankfully, all python ever needs is the source, and all you need to do is to place the source in the python path. &lt;/p&gt;
&lt;p&gt;Most projects use Distributed Version Control Systems like Mercurial and Git, and they come locally with the entire history of the source which provides a lot of control to use any version of the code. For code that we use often, like django packages, using the source from a version control system seems to be the best way to manage.&lt;/p&gt;
&lt;p&gt;In order to install &lt;a href="http://bitbucket.org/ubernostrum/django-registration/"&gt;django-registration&lt;/a&gt;, a popular django app by &lt;a href="http://www.b-list.org/"&gt;James Bennett&lt;/a&gt;, you need to:&lt;/p&gt;
&lt;p&gt;Clone the repository:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;$ hg clone https://becomingguru@bitbucket.org/ubernostrum/django-registration/ django_registration
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Create a symbolic link in the python path:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;$ sudo ln -fs ~/django_registration/registration /usr/lib/python2.6/dist-packages/django_registration
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Thats it. &lt;code&gt;django_registration&lt;/code&gt; is now on the python path, courtesy of symbollic link, that links the django-registration source to python path, in this case the &lt;code&gt;dist-packages/&lt;/code&gt; folder; thus it will be possible to import this app within the python environment.&lt;/p&gt;
&lt;p&gt;You now have the latest version of the source in the folder &lt;code&gt;~/django_registration&lt;/code&gt;, which you can check, and modify. With an editor/IDE that has &lt;em&gt;go to source&lt;/em&gt; option, you can browse the source by using a simple short cut.(which may not have been simple if the code were is some egg file in a less well known folder)&lt;/p&gt;
&lt;p&gt;Because of cloning of the mercurial repository, you now have access to all the revisions of the application. So you can easily update, or change to other versions.&lt;/p&gt;
&lt;p&gt;To update to a newer version when one exists:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;$ hg pull -u
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;To move to any particular revision:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;$ hg update -r200
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;To check the tags:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;$ hg tags

tip                              221:b360801eae96
v0.7                             205:d073602dc103
v0.6                             154:e263c551ef7b
v0.5                             139:dc2bf754aa94
v0.4                             110:4d2a725d8c18
v0.3                              75:f41e8a239016
v0.2                              58:e5110bb8d48a
v0.1                              42:d28e5a770ff8
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;If you want to update to a recent release, say 0.7,&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt; $  hg update v0.7
7 files updated, 0 files merged, 0 files removed, 0 files unresolved
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;The same is also applicable while dealing with SVN repositories; alebit some of the revision changes go thro the network to the central server.&lt;/p&gt;
&lt;p&gt;In order to install and work with &lt;a href="http://code.djangoproject.com/svn/django/trunk/"&gt;django trunk&lt;/a&gt;, check out the trunk and add a symlink, as before&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;$ svn co http://code.djangoproject.com/svn/django/trunk/ django-trunk
$ cd django-trunk/django
$ sudo ln -fs . /usr/lib/python2.6/dist-packages/django-extensions
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;You will now be able to access the latest version of django:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;$ python
&amp;gt;&amp;gt;&amp;gt; import django
&amp;gt;&amp;gt;&amp;gt; django.get_version()
u&amp;#39;1.1 beta 1 SVN-11092&amp;#39;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;To use any other version of django you can do some SVN manipulation, as following:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;#To update to a latest version
svn up
At revision 11092.

#To update to a particular revision
svn update -r11090
At revision 11090.

#To update to a last committed version
svn up -r&amp;#39;COMMITTED&amp;#39;
At revision 11079.

#Change to a tagged version - to release 1.02
svn switch http://code.djangoproject.com/svn/django/tags/releases/1.0.2/

#Change to any branch
svn switch http://code.djangoproject.com/browser/django/branches/soc2009
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;&lt;code&gt;svn switch&lt;/code&gt; commands talk to the central servers and can be time consuming.&lt;/p&gt;
&lt;h3&gt;Possible shortcomings of using source and symbollic links:&lt;/h3&gt;
&lt;p&gt;Setuptools distribution adds to the python standard library &lt;a href="http://docs.python.org/distutils/"&gt;Distutils&lt;/a&gt; module, by adding a lot of functionality, among others that stores the package meta data like the version, location of download. If you perform&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;easy_install django
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;after installing it by source as above, &lt;code&gt;easy_install&lt;/code&gt; again downloads the latest released version of django 1.02, listed in the Python Package Index, as it hasn't been informed of django installation. &lt;/p&gt;
&lt;p&gt;If you are not going to use &lt;code&gt;easy_install&lt;/code&gt; at all, this isn't a problem; but it is good to also update setup tools that a version of this application exists, if you at all need. You can then use the &lt;code&gt;pkg_resources&lt;/code&gt; module installed with setup tools distibution, to query to find all the installed applications, from python.&lt;/p&gt;
&lt;p&gt;If the application contains a &lt;code&gt;setup.py&lt;/code&gt; file, you could manually inform setup tools to update using the following command&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;python setup.py develop
&lt;/pre&gt;&lt;/div&gt;


&lt;h3&gt;The workflow&lt;/h3&gt;
&lt;p&gt;To install packages, in a way with high control following needs to be done:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;* Checkout the repository
* Add a symbollic link to the repository
* Update setup tools of this installation.
&lt;/pre&gt;&lt;/div&gt;


&lt;h3&gt;Enter PIP&lt;/h3&gt;
&lt;p&gt;PIP is a package management tool that does the workflow we need, well. It automatically checks out from the repos and runs &lt;code&gt;python manage.py develop&lt;/code&gt; and updates few other resources, so that python package management tools in the system are well aware of the installed packages.&lt;/p&gt;
&lt;p&gt;If you are checking out the source and creating symbolic links, it is kind of awkward to have to create symbolic links all the time; Pip automates that. Pip also updates the setuptools with the metadata of the application, so that next time if you ask the same application to be installed, via &lt;code&gt;easy_install&lt;/code&gt; or &lt;code&gt;pip&lt;/code&gt;, it doesn't download and install again.&lt;/p&gt;
&lt;p&gt;So the following command:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;pip install -e hg+http://bitbucket.org/ubernostrum/django-registration/#egg=django_registration
&lt;/pre&gt;&lt;/div&gt;


&lt;ul&gt;
&lt;li&gt;Clones the mercurial repository django-registration locally, into &lt;code&gt;Env/src/django_registration&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Creates the required symbollic links in the python path, in this case in the &lt;code&gt;site-packages&lt;/code&gt; folder&lt;/li&gt;
&lt;li&gt;Updates the local package management tools by setup tools of the new package.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;code&gt;-e&lt;/code&gt; option tells pip to install the package as editable, that is to leave the repository undeleted. The &lt;code&gt;hg+&lt;/code&gt; and &lt;code&gt;egg=django_registration&lt;/code&gt; indicate the repository and the local folder to install to.&lt;/p&gt;
&lt;p&gt;Pip works well with git, SVN, Hg an Bzr. Provided you inform the pip of the repository and the folder name, pip completes the work-flow.&lt;/p&gt;
&lt;p&gt;Since the source is present in the &lt;code&gt;Env/src&lt;/code&gt; folder,  along with the SVN, Git or Hg data, one can modify the versions using version control systems, as illustrated in some of the commands above&lt;/p&gt;
&lt;h3&gt;Multiple environments&lt;/h3&gt;
&lt;p&gt;Most often the requirement will be just to update the package into the latest version, for which simple revision control update commands seem good enough. Its good to also mess around with the code changing into different versions and trying different things.&lt;/p&gt;
&lt;p&gt;But if you seem to be changing of the versions too often, for compatibility between different environments, you might want to using &lt;a href="http://pypi.python.org/pypi/virtualenv"&gt;virtualenv&lt;/a&gt;, that isolates a python working environment. &lt;a href="http://pypi.python.org/pypi/virtualenvwrapper"&gt;virtualenvwrapper&lt;/a&gt; adds a bash wrapper to use virtualenv conviniently.&lt;/p&gt;
&lt;p&gt;&lt;hr /&gt;
Do you also want your app development managed well? &lt;a href="http://uswaretech.com/contact/"&gt;Look us up&lt;/a&gt;&lt;/p&gt;</description><guid>http://agiliq.com/blog/2009/06/better-python-package-management-using-source-and-/</guid></item><item><title>Develop Twitter API application in django and deploy on Google App Engine</title><link>http://agiliq.com/blog/2009/04/develop-twitter-api-application-in-django-and-depl/</link><description>&lt;p&gt;Twitter's robust &lt;a href="http://apiwiki.twitter.com/Twitter-API-Documentation"&gt;REST API&lt;/a&gt; enables building of good applications that leverage its increasingly large and real-time data.&lt;/p&gt;
&lt;img class="alignright" title="Google App Engine" src="http://code.google.com/appengine/images/appengine_lowres.gif" alt="" width="142" height="109" /&gt;

&lt;p&gt;Google's cloud system &lt;a href="http://code.google.com/appengine/"&gt;App Engine&lt;/a&gt; not only provides a scalable platform for deploying applications, but also proves to be economically viable because of its pay per resource usage model and a large free quota.&lt;/p&gt;
&lt;p&gt;Little wonder then, there are increasingly large number of twitter apps being deployed on App Engine.&lt;/p&gt;
&lt;p&gt;In this post, I am going to examine how to create a simple application based on twitter's REST API and deploy it on Google App Engine. A deployed version can be found on &lt;a href="http://twitter-follow.appspot.com/"&gt;Twitter-Follow&lt;/a&gt;. The specification is simple. It finds if a twitter user is following another twitter user, given their user names.&lt;/p&gt;
&lt;p&gt;&lt;img class="alignright size-thumbnail wp-image-461" title="twitter-follow" src="http://uswaretech.com/blog/wp-content/uploads/2009/04/screenshot-150x150.png" alt="" width="150" height="150" /&gt;
The application is developed using django and deployed on Appengine using the &lt;a href="http://code.google.com/appengine/articles/app-engine-patch.html"&gt;app engine patch&lt;/a&gt; project.&lt;/p&gt;
&lt;p&gt;The code is open sourced with GPL v3 and can be checked out from &lt;a href="http://code.google.com/p/twitter-follow/"&gt;Google Code&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Lets get started building this application.&lt;/p&gt;
&lt;h3&gt;Create an application&lt;/h3&gt;
&lt;p&gt;Create a new application from &lt;a href="http://appengine.google.com/"&gt;App Engine Dashboard&lt;/a&gt; by registering an unique appspot.com sub-domain. This will be your application's unique identifier. You may have to register first.&lt;/p&gt;
&lt;h3&gt;Install App Engine SDK&lt;/h3&gt;
&lt;p&gt;&lt;a href="http://code.google.com/appengine/downloads.html#Google_App_Engine_SDK_for_Python"&gt;Download&lt;/a&gt; and install the App Engine SDK. There is no &lt;em&gt;installation&lt;/em&gt; for linux users, just place the folder in &lt;code&gt;/usr/local/google_appengine&lt;/code&gt;&lt;/p&gt;
&lt;h3&gt;Download app-engine-patch&lt;/h3&gt;
&lt;p&gt;Download the &lt;a href="http://app-engine-patch.googlecode.com/files/app-engine-patch-sample-1.0.zip"&gt;sample project&lt;/a&gt;. It comes bundled with all the essential django 1.0 files that are required.
Since we do not need the sample application, you may remove the unnecessary sample application folders and correspondingly modify settings.py, but for this demo app, it doesn't matter even if you dont.&lt;/p&gt;
&lt;h3&gt;Modify &lt;strong&gt;&lt;code&gt;app.yaml&lt;/code&gt;&lt;/strong&gt;:&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;application: twitter-follow
version: 1
runtime: python
api_version: 1

default_expiration: &amp;#39;3650d&amp;#39;

handlers:
- url: /media
static_dir: media

- url: /.*
script: common/appenginepatch/main.py
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;The only thing you need to modify in this file is the unique application name- for which you registered, and the static files' folder.&lt;/p&gt;
&lt;p&gt;As we are using the patch, the handler script to run should always point to &lt;code&gt;main.py&lt;/code&gt; of the appenginepatch folder. Leave it as it is.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;/media&lt;/code&gt; maps to the static directory &lt;code&gt;./media&lt;/code&gt;, in which you place the static JS and CSS files.&lt;/p&gt;
&lt;h3&gt;Modify &lt;strong&gt;&lt;code&gt;urls.py&lt;/code&gt;&lt;/strong&gt;&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;urlpatterns = auth_patterns + patterns(&amp;#39;&amp;#39;,
    (r&amp;#39;^$&amp;#39;, &amp;#39;views.disp&amp;#39;),
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Pretty much straight forward, we handle only 1 page and the request is directed to a specified view function ie &lt;code&gt;disp&lt;/code&gt; in &lt;code&gt;views.py&lt;/code&gt; file which we are going to create.&lt;/p&gt;
&lt;p&gt;There are some more imports in the file than django &lt;code&gt;urls.py&lt;/code&gt; for the patch to work. Leave them as it is.&lt;/p&gt;
&lt;h3&gt;What about &lt;strong&gt;&lt;code&gt;models.py&lt;/code&gt;&lt;/strong&gt;?&lt;/h3&gt;
&lt;p&gt;For this application, we do not need any database. We just query twitter as and when user requests.&lt;/p&gt;
&lt;p&gt;What about session persistence? Oh, we achieve that using hidden input fields in the form, as we will see in the views.&lt;/p&gt;
&lt;p&gt;Hence we don't even need to create an application, just a view and a form in the root directory&lt;/p&gt;
&lt;h3&gt;Write &lt;strong&gt;&lt;code&gt;forms.py&lt;/code&gt;&lt;/strong&gt;&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;from django import forms

class input_form(forms.Form):
    follower = forms.CharField(max_length=50, required=True, error_messages={&amp;#39;required&amp;#39;:&amp;#39;Follower Name is required&amp;#39;})
    following = forms.CharField(max_length=50, required=True, error_messages={&amp;#39;required&amp;#39;:&amp;#39;Following Name is required&amp;#39;})
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;We need a simple form that we can create in our function, so that it is displayed in the template, by the framework.&lt;/p&gt;
&lt;p&gt;After all, the django forms framework is one big advantage of using django over the App Engine's builtin webapp framework, even for simple applications. With forms now done, we proceed to the views.&lt;/p&gt;
&lt;h3&gt;Write &lt;strong&gt;&lt;code&gt;views.py&lt;/code&gt;&lt;/strong&gt;&lt;/h3&gt;
&lt;h4&gt;is_follows:&lt;/h4&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;def is_follows(follower, following):

    url = &amp;#39;http://twitter.com/friendships/exists.json?user_a=%s&amp;amp;user_b=%s&amp;#39; %(
    follower, following)

    password_mgr = urllib2.HTTPPasswordMgrWithDefaultRealm()
    top_level_url = &amp;quot;http://twitter.com/&amp;quot;
    password_mgr.add_password(None, top_level_url, settings.TWNAME, settings.TWPASSWORD)
    handler = urllib2.HTTPBasicAuthHandler(password_mgr)
    opener = urllib2.build_opener(urllib2.HTTPHandler, handler)
    urllib2.install_opener(opener)

    try:
    return simplejson.load(urllib2.urlopen(url))
    except IOError, e:
    #print &amp;quot;Something wrong. This shouldnt happen&amp;quot;
    print e,&amp;quot;Protected user&amp;#39;s details cant be found &amp;quot;
    return False
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;This function queries twitter and returns whether a &lt;code&gt;follower&lt;/code&gt; is following &lt;code&gt;following&lt;/code&gt;. Lot of boilerplate code, a standard way of adding authentication headers to all requests to the specified domain. Otherwise, the function just examines json returned by twitter and returns corresponding value.&lt;/p&gt;
&lt;h4&gt;disp and helper functions:&lt;/h4&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;def format_is_follows(follower, following):
    fol = &amp;#39;YES&amp;#39; if is_follows(follower,following) else &amp;#39;NO&amp;#39;
    new_entry = (fol,follower,following)
    return &amp;quot;%s:%s:%s&amp;quot; %new_entry

def get_entry_tuples(str1=&amp;quot;YES:str1:str2;NO:str3:str4&amp;quot;):
    list1 = str1.split(&amp;#39;;&amp;#39;)
    list2 = [tuple(i.split(&amp;quot;:&amp;quot;)) for i in list1]
    return list2

def disp(req):
    if req.method == &amp;#39;POST&amp;#39;:
    form = forms.input_form(req.POST)

    if form.is_valid():
        new_str = format_is_follows(form.cleaned_data[&amp;#39;follower&amp;#39;],
                    form.cleaned_data[&amp;#39;following&amp;#39;])
        old_str = req.POST[&amp;#39;old&amp;#39;]

        form_data = &amp;quot;%s;%s&amp;quot; %(new_str,old_str)
        entries = get_entry_tuples(form_data)[:-1]

        payload = {&amp;#39;entries&amp;#39;:entries,
               &amp;#39;form&amp;#39;:form,
               &amp;#39;disp&amp;#39;:True,
               &amp;#39;form_data&amp;#39;:form_data}
    else:
        payload = {&amp;#39;form&amp;#39;:form,
               &amp;#39;disp&amp;#39;:True}
    else:
    form = forms.input_form()
    payload =  {&amp;#39;form&amp;#39;:form,&amp;#39;disp&amp;#39;:False}
    return render_to_response(&amp;#39;page3.html&amp;#39;,payload,)
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;&lt;code&gt;disp&lt;/code&gt; is the function called by the framework each time an HTTP request arises. Validates the form data and passes contextual variables for displaying. Some additional code, for examining the previously queried values from the hidden field in the form.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;format_is_follows&lt;/code&gt; returns the follower following data in the format required by the template we are going to be using- a tuple of 3 values and &lt;code&gt;get_entry_tuples&lt;/code&gt; returns the data
that we are going to store in the hidden form. They are Separated into multiple functions here, just for clarity.&lt;/p&gt;
&lt;h3&gt;&lt;strong&gt;&lt;code&gt;template.html&lt;/code&gt;&lt;/strong&gt;&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="nt"&gt;&amp;lt;html&amp;gt;&amp;lt;body&amp;gt;&lt;/span&gt;

    &lt;span class="cp"&gt;{%&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="nv"&gt;fol&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="nv"&gt;entries&lt;/span&gt; &lt;span class="cp"&gt;%}&lt;/span&gt; 
        &lt;span class="cp"&gt;{%&lt;/span&gt; &lt;span class="k"&gt;ifequal&lt;/span&gt; &lt;span class="nv"&gt;fol.0&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;YES&amp;quot;&lt;/span&gt; &lt;span class="cp"&gt;%}&lt;/span&gt;
            Yes. &lt;span class="nt"&gt;&amp;lt;a&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;http://twitter.com/&lt;/span&gt;&lt;span class="cp"&gt;{{&lt;/span&gt;&lt;span class="nv"&gt;fol.1&lt;/span&gt;&lt;span class="cp"&gt;}}&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;@&lt;span class="cp"&gt;{{&lt;/span&gt;&lt;span class="nv"&gt;fol.1&lt;/span&gt;&lt;span class="cp"&gt;}}&lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;/a&amp;gt;&lt;/span&gt; is following &lt;span class="nt"&gt;&amp;lt;a&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;http://twitter.com/&lt;/span&gt;&lt;span class="cp"&gt;{{&lt;/span&gt;&lt;span class="nv"&gt;fol.2&lt;/span&gt;&lt;span class="cp"&gt;}}&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;@&lt;span class="cp"&gt;{{&lt;/span&gt;&lt;span class="nv"&gt;fol.2&lt;/span&gt;&lt;span class="cp"&gt;}}&lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;/a&amp;gt;&lt;/span&gt;  &lt;span class="cp"&gt;{%&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="cp"&gt;%}&lt;/span&gt; 
            No. &lt;span class="nt"&gt;&amp;lt;a&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;http://twitter.com/&lt;/span&gt;&lt;span class="cp"&gt;{{&lt;/span&gt;&lt;span class="nv"&gt;fol.1&lt;/span&gt;&lt;span class="cp"&gt;}}&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;@&lt;span class="cp"&gt;{{&lt;/span&gt;&lt;span class="nv"&gt;fol.1&lt;/span&gt;&lt;span class="cp"&gt;}}&lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;/a&amp;gt;&lt;/span&gt; is not following &lt;span class="nt"&gt;&amp;lt;a&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;http://twitter.com/&lt;/span&gt;&lt;span class="cp"&gt;{{&lt;/span&gt;&lt;span class="nv"&gt;fol.2&lt;/span&gt;&lt;span class="cp"&gt;}}&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;@&lt;span class="cp"&gt;{{&lt;/span&gt;&lt;span class="nv"&gt;fol.2&lt;/span&gt;&lt;span class="cp"&gt;}}&lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;/a&amp;gt;&lt;/span&gt;
        &lt;span class="cp"&gt;{%&lt;/span&gt; &lt;span class="k"&gt;endifequal&lt;/span&gt; &lt;span class="cp"&gt;%}&lt;/span&gt;
    &lt;span class="cp"&gt;{%&lt;/span&gt; &lt;span class="k"&gt;endfor&lt;/span&gt; &lt;span class="cp"&gt;%}&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;form&lt;/span&gt; &lt;span class="na"&gt;action=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;.&amp;quot;&lt;/span&gt; &lt;span class="na"&gt;method=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;POST&amp;quot;&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="cp"&gt;{{&lt;/span&gt; &lt;span class="nv"&gt;form.following.errors&lt;/span&gt; &lt;span class="cp"&gt;}}&lt;/span&gt; &lt;span class="cp"&gt;{{&lt;/span&gt; &lt;span class="nv"&gt;form.follower.errors&lt;/span&gt; &lt;span class="cp"&gt;}}&lt;/span&gt;
    Is &lt;span class="cp"&gt;{{&lt;/span&gt; &lt;span class="nv"&gt;form.follower&lt;/span&gt; &lt;span class="cp"&gt;}}&lt;/span&gt; following &lt;span class="cp"&gt;{{&lt;/span&gt; &lt;span class="nv"&gt;form.following&lt;/span&gt; &lt;span class="cp"&gt;}}&lt;/span&gt; 
    &lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;hidden&amp;quot;&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;old&amp;quot;&lt;/span&gt; &lt;span class="na"&gt;value=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&lt;/span&gt;&lt;span class="cp"&gt;{{&lt;/span&gt; &lt;span class="nv"&gt;form_data&lt;/span&gt; &lt;span class="cp"&gt;}}&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;submit&amp;quot;&lt;/span&gt; &lt;span class="na"&gt;align=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;center&amp;quot;&lt;/span&gt; &lt;span class="na"&gt;value=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Find out!&amp;quot;&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt; 
&lt;span class="nt"&gt;&amp;lt;/form&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;/body&amp;gt;&amp;lt;/html&amp;gt;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;It contains, the result display part and the form. The form also has a hidden input field. Thanks to django form framework not adding the &lt;code&gt;&amp;lt;form&amp;gt;&lt;/code&gt; tags and the &lt;code&gt;submit&lt;/code&gt; button. This provides us the flexibility to be able to add the hidden field with the content to be displayed in the next post request.&lt;/p&gt;
&lt;h3&gt;Run the server&lt;/h3&gt;
&lt;p&gt;With all the necessary files ready, you are now ready to run the server. In the command prompt enter&lt;/p&gt;
&lt;p&gt;&lt;code&gt;python manage.py runserver&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;Yes, you run the django &lt;code&gt;manage.py&lt;/code&gt;. The patch application has placed hooks around and starts the App Engine server. Verify the running application from &lt;a href="http://localhost:8000/"&gt;localhost&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;If you happen to have the latest version of Python, sorry. Use the python2.5 instead.&lt;/p&gt;
&lt;h3&gt;Upload the Application&lt;/h3&gt;
&lt;p&gt;Thats it. If you have got it working on the localhost, now throw the code at google's &lt;em&gt;scalable and no maintenance cloud&lt;/em&gt; and it starts working.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;python manage.py update&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;You don't bother about deployment, server maintenance or log files. Rather, check out the awesome &lt;a href="http://appengine.google.com/dashboard?&amp;amp;app_id=twitter-follow"&gt;application admin dashboard&lt;/a&gt; and if you run out of the allocated free quota, buy some more resource time. Its costs $0.10/CPU hour and one cent for 100 emails sent!&lt;/p&gt;
&lt;p&gt;A lot is happening in the field of App Engine support for twitter API. There is even a new App Engine module for twitter &lt;a href="http://github.com/tav/tweetapp/tree/master"&gt;oAuth authentication&lt;/a&gt;, out of the box, as there is &lt;a href="http://www.djangosnippets.org/snippets/1353/"&gt;one for django&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;App Engine is a powerful platform. django is a high productive framework. Combining them is very powerful and there is also an &lt;a href="http://code.djangoproject.com/wiki/AppEngine"&gt;ongoing project&lt;/a&gt; for enhancing the the patch project and making it totally compatible with django.&lt;/p&gt;
&lt;p&gt;Resources:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="http://code.google.com/appengine/articles/app-engine-patch.html"&gt;Jesaja Everling Tutorial&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://apiwiki.twitter.com/Twitter-API-Documentation"&gt;Twitter API Documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://code.google.com/appengine/docs/python/gettingstarted/"&gt;App Engine Tutorial on Webapp Framework&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://code.google.com/p/app-engine-patch/wiki/GettingStarted"&gt;App Engine Patch - Getting Started&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://code.google.com/p/app-engine-patch/wiki/Documentation"&gt;App Engine Patch - Documentation&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;hr /&gt;
Want to develop an application based on twitter API? &lt;a href="http://uswaretech.com/contact/"&gt;We can help&lt;/a&gt;.&lt;/p&gt;</description><guid>http://agiliq.com/blog/2009/04/develop-twitter-api-application-in-django-and-depl/</guid></item><item><title>An Interview with Adrian Holovaty - Creator of Django</title><link>http://agiliq.com/blog/2008/06/an-interview-with-adrian-holovaty-creator-of-djang/</link><description>&lt;p&gt;&lt;a href="http://www.holovaty.com/"&gt;Adrian Holovaty&lt;/a&gt; is the co-creator of Django, author of the Django book and is currently the BDFL of Django along with Jacob Kaplan-Moss. He studied journalism at &lt;a href="http://www.missouri.edu/about/mufacts.php"&gt;University of Missouriâ€“Columbia&lt;/a&gt; and has worked with many news sites including &lt;a href="http://www2.ljworld.com/"&gt;Lawrence Journal World&lt;/a&gt; and &lt;a href="http://www.washingtonpost.com/"&gt;Washington Post&lt;/a&gt;. He currently works at &lt;a href="http://everyblock.com/"&gt;EveryBlock&lt;/a&gt;, a startup he founded.&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;&lt;strong&gt;Shabda:&lt;/strong&gt; Would you tell a little about yourself? You majored in Journalism, how did you move to Programming?&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Adrian:&lt;/strong&gt; Sure! I have a dual background in journalism and computer science. I
intended to get a degree in journalism and a minor in computer
science, but things got a little off track. I heard from a
professional colleague that a certain Web site would probably hire me
if I graduated a semester early, so I hurriedly dropped my CS minor
and got special permission to graduate early -- but once the time came
to ask for that job, the company was in the middle of a hiring freeze
and didn't have a position for me. So, in hindsight, I should've stuck
with the minor, but things ended up working out OK.&lt;/p&gt;
&lt;p&gt;Because journalism and computer science don't normally go together,
I've had some success in this silly little niche of employing Web
development in news organizations -- "journalism via computer
programming." Professionally, I've always worked as a Web developer at
news organizations, up until my current gig, which is to run
&lt;a href="http://everyblock.com"&gt;EveryBlock&lt;/a&gt;. But in its own way, it's a news
organization as well.&lt;/p&gt;
&lt;p&gt;Aside from all of that, I'm quite into music, particularly gypsy jazz,
which is the music of Django Reinhardt (hence the name of the Web
framework). I just recently attended a &lt;a href="http://djangoinjune.com"&gt;week-long gypsy jazz guitar
camp in Massachusetts&lt;/a&gt; and had a tremendous time
staying up until early hours of the morning jamming with great
musicians from various parts of the world. If money were no object, I
would love to play music full time. In the meantime, I'll settle for
posting &lt;a href="http://youtube.com/adrianholovaty"&gt;YouTube videos of my guitar playing&lt;/a&gt;, for an audience that seems to be
comprised mostly of 16-year-old boys who constantly pester me for
transcriptions of my arrangements.&lt;/p&gt;
&lt;p&gt;I live with my wife in the beautiful city of Chicago.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Shabda:&lt;/strong&gt; What are your current roles and responsibilities at Django?&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Adrian:&lt;/strong&gt; Well, I co-created Django back in 2003 with my friend &lt;a href="http://simonwillison.net/"&gt;Simon Willison&lt;/a&gt;
while we were working together. Now, along with &lt;a href="http://www.jacobian.org/"&gt;Jacob Kaplan-Moss&lt;/a&gt;, I'm
Benevolent Dictator For Life of the project -- a title we shamelessly
ripped off from Guido/Python. This means that I have a hand in all
sorts of things, from high-level API design to checking in patches and
fixing bugs. I've touched probably every bit of the framework over the
years, including implementing the initial ORM (back when it was a code
generator!), pair-programming the original Django template system and
URLconf/view framework with Simon and building the original admin
application with design help from Wilson Miner.&lt;/p&gt;
&lt;p&gt;One of the things I enjoy the most is writing documentation -- both
because I like technical writing and because I cannot stand bad
open-source documentation.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Shabda:&lt;/strong&gt; Can you describe the philosophy behind Django. What are its overarching goals?&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Adrian:&lt;/strong&gt; A couple of years ago, I wrote the "&lt;a href="http://www.djangoproject.com/documentation/design_philosophies/"&gt;Design philosophies&lt;/a&gt;" document,
which sums up the main points nicely.&lt;/p&gt;
&lt;p&gt;Generally, the goal is to make Web development fast, fun and easy for
the developer, while keeping performance as fast as possible and code
as easy to understand as possible.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Shabda:&lt;/strong&gt; How did the move at WorldOnline from PHP to Python happen? Why did you start from scratch (which finally lead to creation of Django), instead of using something like Zope?&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Adrian:&lt;/strong&gt; Simon and I had been big fans of &lt;a href="http://diveintomark.org/"&gt;Mark Pilgrim&lt;/a&gt; (and still are!), and
we'd read his online book "&lt;a href="http://www.diveintopython.org/"&gt;Dive Into Python&lt;/a&gt;." This was around the same
time that the PHP "infrastructure" I'd developed had begun to feel
really, really crufty, so...one day we just decided to start using
Python! It's quite nice working at a small organization with a very
loose management structure; our boss, Rob Curley, was cool enough to
let the developers themselves decide which technologies to use, as
long as the work got done. "I don't care how the sausage is made," he
always used to say.&lt;/p&gt;
&lt;p&gt;We looked at the existing Python Web frameworks/libraries, but none of
them felt 100% right to us. Simon and I are both quite into best
practices, such as clean URLs, proper use of GET vs. POST, etc., so we
were very picky in our analysis of those existing tools.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Shabda:&lt;/strong&gt; Can you tell us about &lt;a href="http://everyblock.com/"&gt;Everyblock&lt;/a&gt;? Why did you choose to create your own mapping engine instead of using something like Google Maps? How hard has it been creating a new mapping engine?&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Adrian:&lt;/strong&gt; EveryBlock is the project I lead for my day job. It's funded by a
two-year grant from the &lt;a href="http://www.knightfoundation.org/"&gt;Knight Foundation&lt;/a&gt;, and the goal is to
experiment with block-specific news -- that is, the site lets you
enter an address (currently only in Chicago, New York City and San
Francisco) and view recent news within a very tight radius of that
address. I'm pretty confident it's the most granular attempt at local
news ever attempted on the Web. Nobody else is crazy enough to do it,
I guess!&lt;/p&gt;
&lt;p&gt;We do a TON of work collecting local information, normalizing it and
pulling it together for people in one place. A large part of what we
publish is government data such as crime reports, restaurant
inspections, building permits, business licenses...and even local
movie filmings. Much of this stuff either is buried in "deep Web"
government databases or has never before been available online. A
second part of what we do is detecting addresses and locations in news
articles and blog entries. Plus, we pull in various other geographic
Web stuff like Flickr photos and Yelp reviews.&lt;/p&gt;
&lt;p&gt;All in all, our goal is to show you recent, geographically relevant
stuff that you might not have heard about. Say the local newspaper
wrote something about your neighborhood on page B-23 -- would you
really have noticed that article? Say there was an aggravated assault
on your block -- would you really have remembered to check your police
department's crime-reports Web site on a daily basis? That's the basic
philosophy.&lt;/p&gt;
&lt;p&gt;Regarding our custom mapping engine...Let's face it: Google Maps is so
passe. As one of the original Google Maps mashup guys (I developed
&lt;a href="http://chicagocrime.org"&gt;chicagocrime.org&lt;/a&gt; by reverse-engineering Google's JavaScript, &lt;em&gt;before&lt;/em&gt;
the API was released), I have all the respect in the world for what
Google has done to invigorate the world of Web maps. But it's time to
take the next step. The Google Maps API doesn't give you any control
over the colors of the map tiles, or change the fonts in street
labels, or disable building footprints, or hide one-way street markers
or subway stations or bus stops or any of the other stuff that's
essentially hard-coded in the map. So, at EveryBlock, we rolled our
own maps so we could have much, much more fine-grained control over
all of these things. Not to mention it's a great way to differentiate
ourselves from the 2.5 million boring, same-old-yellow-blue-orange
Google Maps mashups out there.&lt;/p&gt;
&lt;p&gt;Paul Smith from the EveryBlock team has written an article at &lt;a href="http://www.alistapart.com/articles/takecontrolofyourmaps"&gt;A List
Apart with more of the technical specifics&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Shabda:&lt;/strong&gt; As per the &lt;a href="http://www.knightfoundation.org/grants/"&gt;Knight grant&lt;/a&gt; rules, you would be releasing the code for Everyblock next year. Would you not be giving away your secret sauce? How do you plan to maintain competitive advantage once that code is freely
 avaliable under a permissive license?&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Adrian:&lt;/strong&gt; Our competitive advantage is that we're an incredible team, and I'm
sure we'll come up with a way to feed our families.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Shabda:&lt;/strong&gt; What problems would you like Django to tackle after 1.0? What big features would you be most interested in having in Django, after it hits 1.0?&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Adrian:&lt;/strong&gt; Generally I'd like to add higher and higher levels of abstraction to
the framework. The Django admin application is a good example of that
-- it's not just an abstraction of an HTTP request; it's an
abstraction of an entire Web application! We should do more of those.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Shabda:&lt;/strong&gt; What is one thing about Django which you absolutely love, and one thing which you think Django should do differently?&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Adrian:&lt;/strong&gt; I love the way URLconfs work -- like a table of contents for your Web
app. I also love template inheritance. I don't love the fact that
we're generally slow in keeping up with tickets and feature requests.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Shabda:&lt;/strong&gt; A lot of people these days have to evaluate between Django and ROR. How can they make this decision? When should Adrian Holovaty use ROR? When should DHH use Django?&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Adrian:&lt;/strong&gt; My answer is simple: Try out both frameworks and see which one you like better.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Shabda:&lt;/strong&gt; Does Django need to market itself differently? What can Django community do for this?&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Adrian:&lt;/strong&gt; I'm comfortable with the amount of attention (or lack thereof,
depending on your perspective) that our project gets. I'm comfortable
with the size of the community. I'm comfortable with the fact that the
right people have found out about it through word of mouth, books,
blogs, &lt;a href="http://code.google.com/appengine/"&gt;Google App Engine&lt;/a&gt; or wherever else. If things continue at their
current rate, we'll continue to do just fine, as a healthy open-source
project.&lt;/p&gt;
&lt;p&gt;The one thing I'd ask the community to do is to continue staying
civil, polite and approachable.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Shabda:&lt;/strong&gt; What does the phrase 'journalism via computer programming' mean? How can these two divergent fields be tied together?&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Adrian:&lt;/strong&gt; "Journalism via computer programming," in my opinion, is when a
journalist writes code to tell a story. Instead of talking on the
phone with sources to gather facts, this could involve screen-scraping
Web sites to gather raw data. Instead of writing a newspaper article,
this could involve building a database-driven Web site.&lt;/p&gt;
&lt;p&gt;Journalism has several subdisciplines -- photography, information
graphics, video. I advocate that computer programming should be
another one of those subdisciplines. Just as a newspaper employs
photographers and graphic artists, it should employ programmers who
help gather information and tell stories with it.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Shabda:&lt;/strong&gt; How can traditional journalists do more 'journalism via computer programming'? How can programmers do more 'journalism via computer
programming'? Is it easier for Programmers to move to this field, or for
Journalists?&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Adrian:&lt;/strong&gt; I believe it's easier for programmers to become journalists than it is
for journalists to become programmers, but both sides need to gain an
appreciation for the other in order for this sort of thing to happen
more often. Fortunately, some news organizations are starting to hire
developers with this in mind, and some geeks are realizing journalism
is a great, (mostly) pure field that lets you improve the world
through information.&lt;/p&gt;
&lt;p&gt;One concrete thing programmers can do is to look for jobs at news
organizations, which desperately need technical talent. Developers,
you will be loved, you will be treated like geniuses, and your
non-techie coworkers will be very easily impressed!&lt;/p&gt;
&lt;p&gt;Another route programmers can take is to get training in journalism --
in fact, Northwestern University's journalism school is giving out
full-tuition scholarships for &lt;a href="http://www.medill.northwestern.edu/admissions/programmers.html"&gt;programmers who want to learn
journalism&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Shabda:&lt;/strong&gt; Thanks Adrian.&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;This was Adrian's interview, the last in django-interviews series. But we have a lot of interesting things coming up, so &lt;a href="http://42topics.com/blog/feed/"&gt;stay tuned&lt;/a&gt;.&lt;/p&gt;</description><guid>http://agiliq.com/blog/2008/06/an-interview-with-adrian-holovaty-creator-of-djang/</guid></item><item><title>An Interview with Jacob Kaplan-Moss - Creator of Django</title><link>http://agiliq.com/blog/2008/05/an-interview-with-jacob-kaplan-moss-creator-of-dja/</link><description>&lt;p&gt;&lt;img src="http://uswaretech.com/blog/wp-content/uploads/2008/05/jacob_headshot2.png" alt="Jacob Kaplan-Moss" title="jacob_headshot2" width="225" height="232" class="right frame" /&gt;
&lt;a href="http://djangopeople.net/jacobian/"&gt;Jacob Kaplan-Moss&lt;/a&gt; is the co-creator of Django along with Adrian Holovaty, as well as the author of &lt;a href="http://www.amazon.com/Definitive-Guide-Django-Development-Right/dp/1590597257"&gt;the Django Book&lt;/a&gt;. He has been involved with Django since before it was called Django. He is currently employed at Whiskey Media where his job is hacking at Django. He blogs on &lt;a href="http://www.jacobian.org/"&gt;Jacobian.org&lt;/a&gt;. He graciously agreed to be interviewed at the 42topics blog.&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;&lt;strong&gt;Shabda:&lt;/strong&gt; Would you tell a little about yourself? How did you get started with Django? What other software/applications have you worked with. (Both OSS and otherwise)?&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Jacob:&lt;/strong&gt; So a bit about me: I grew up in Silicon Valley, so like many other geeks I got started with computers really early; I was programming professionally before I graduated high school. I didn't start out doing web development; in college I worked on video surveillance systems for airports, harbors, marinas, and highways.   That's where I found Python: I rewrote a Java-based camera controller in Python and haven't looked back since.
I started doing web development pretty seriously when I moved to New York and took a job for a design firm there. The job was pretty terrible, and the technologies were worse: the good sites were PHP, and there was a bunch of WebLogic crap that was absolute hell to maintain.
So in 2004 I saw the &lt;a href="http://www.holovaty.com/blog/archive/2004/06/29/1135"&gt;job opening&lt;/a&gt; that &lt;a href="http://simonwillison.net/"&gt;Simon&lt;/a&gt; and &lt;a href="http://www.holovaty.com/"&gt;Adrian&lt;/a&gt; posted on their blogs  -- and jumped on it. Web development in Python seemed like a dream job, and it really was.
So that's how I ended up in Kansas working for the local paper. At that point I suppose I was using Django, though we didn't have a name for it yet: we just called it "The CMS".
I'd been getting more into Open Source all along, though I'd barely contributed (I think I got a single line into Python at one point years ago -- that was my largest contribution).&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Shabda:&lt;/strong&gt; What areas of Django have you worked most in? What are you current areas of focus?&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Jacob:&lt;/strong&gt; Well, at this point I've touched pretty much every part of Django at some point weather in the form of improvements, refactoring, or just small patches and bug fixes. I'm far from an expert in any particular area, though, so I'd say my main role is more holistic: I'm most concerned with making sure that Django "feels" correct and that APIs and conventions match across the framework.
Right now my current focus is documentation: I've been working on improving the structure and organization of the documentation so that it's easier to find what you're looking for. We've got something like 40,000 lines of documentation so organization and metadata is critical.
Now that I'm lucky enough to get to work on Django at work, I'll probably be able to take on some more big tasks like that in the future.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Shabda:&lt;/strong&gt; One of the most loved things about Django is its &lt;a href="http://www.djangoproject.com/documentation/"&gt;comprehensive documentation&lt;/a&gt;. What is the motivation behind refactoring this? What is going to be the new organization? How is this progressing?&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Jacob:&lt;/strong&gt; Thanks -- I've always thought that Django's documentation set us apart from most Open Source projects, and I've been really proud of what we've done there. However, over the past year or so as the size of the documentation (and Django itself) grew I think we've slipped from "outstanding" to merely "above average." To us (the core maintainers and I) that's not acceptable.
The best place to read up on the project and goals is in a &lt;a href="http://groups.google.com/group/django-developers/msg/d31fa312da5a9ec3"&gt;post&lt;/a&gt; I made to &lt;a href="http://groups.google.com/group/django-developers/"&gt;Django-dev&lt;/a&gt; a couple of months ago. In a nutshell, I'm breaking up the documentation into smaller, more manageable chunks -- the current DB API is almost sixty printed pages! I'm also separating more high-level how-to's and topical guides from the detailed API references that get in the way when you're just learning.
There's some tool improvements going on under the hood that'll make the documentation easier to write, edit, maintain, and contribute to; hopefully that'll help decrease the number of undocumented features.
The work's pretty close to done, actually. I was trying to finish before I went on vacation a month ago, but didn't quite get there. So that means I need to roll in a month's worth of documentation improvements that happened to the current docs while I was gone, but that shouldn't take much time. You can expect to see the new docs rolled out online very soon.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Shabda:&lt;/strong&gt; What does Whiskey Media, the startup you are currently associated with do? Is your role there developing Django, or are you associated with other day to day activities as well?&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Jacob:&lt;/strong&gt; I think I'll have to be a bit coy and not say very much about Whiskey Media; we'd rather let our actions speak for themselves than try to build some sort of artificial hype. I'll just say that we're trying to solve some of the big problems in web publishing; you can probably see why Django's the best technical bet for a company trying to be the on the cutting edge of content publishing.
Most of my time at Whiskey is devoted to working on Django -- coding, but also community management, evangelism, and organization. I also have some internal responsibilities, of course, but those are more nebulous: mostly I just help out wherever I'm needed.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Shabda:&lt;/strong&gt; As you said "we'd rather let our actions speak for themselves than try to build some sort of artificial hype". Do you see Django taking a potential hit in marketing due to similar belief of Django community? Does Django need to market itself differently than it has been doing till now? What can Django community do for this?&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Jacob:&lt;/strong&gt; Huh, that's a tricky one. Well, let me break down the question a bit and look at a few different angles.
So first, I've always been a bit uncomfortable with the idea -- pervasive in Open Source -- that this is some sort of popularity contest. People are always comparing traffic figures, or numbers of job postings, or numbers of Google results, or whatever. I think the idea's supposed to be that if Project Foo has more users than Project Bar that Foo somehow "wins". But I don't see it that way at all.
I mean, I moved from New York City to Lawrence, KS. New York City has a population of, what, 8 million or so? Lawrence has a population of around 80,000. Does that mean New York City is "better"? To most of those 8 million, sure... but to me? Hell no.
As in most areas, there's no accounting for taste: one of my good friends here in Lawrence is a die-hard Perl fan, and though it makes him a bit twisted it doesn't mean that I'm somehow "better" than him -- we just have different needs and different ways of thinking.
All that said, though, there is undeniably a value in popularity.
Only a tiny number of people who use a given piece of Open Source software become involved in the community, and only a tiny fraction of those contribute back to the project, and only a tiny fraction of those contributors become long-term committers. So more users translates directly to more contributors, and more contributors brings more "value" to the project.
(By "value" I'm referring to code, good ideas, etc.)
So as you can probably tell this is something we struggle with. On one hand I think Django's great, and it's in the project's best interest to persuade others to give it a shot. But on the other hand there's a huge amount of bullshitting that goes on where software is concerned, and I try my best to not add to the pile.
It's hard to tell when you've crossed the line from evangelism to hype, and hype can be toxic. Witness the recent backlash against Ruby on Rails: do you think they'd get such violent vitriol if they'd been more modest in their promotion?&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Shabda:&lt;/strong&gt; Talking of &lt;acronym title="Ruby on Rails"&gt;ROR&lt;/acronym&gt;, a lot of people these days have to evaluate between Django and ROR. What questions should they ask themselves to answer this question? (Well apart from "do you know Python better or Ruby better?"). To make this more interesting when would YOU choose ROR over Django, if you knew both Ruby and Python equally well?&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Jacob:&lt;/strong&gt; So first let me back up a step -- I'll answer directly in a moment -- and make a quick point about web development in general. The past couple-three years have seen a radical improvement in the quality of tools available to web developers. It really wasn't that long ago that CGI represented the state-of-the-art in web development.
Today, though, there's really some fantastic tools available. &lt;a href="http://rubyonrails.com/"&gt;Rails&lt;/a&gt;, &lt;a href="http://djangoproject.com/"&gt;Django&lt;/a&gt;, &lt;a href="http://www.symfony-project.org/"&gt;Symfony&lt;/a&gt;, &lt;a href="http://pylonshq.com/"&gt;Pylons&lt;/a&gt;, &lt;a href="http://turbogears.org/"&gt;TurboGears&lt;/a&gt;, &lt;a href="http://www.seaside.st/"&gt;Seaside&lt;/a&gt;... any of these tools represent a major improvement over the CGI/PHP model of web development. If you're still writing web sites the way you did five years ago, you're missing out.
When it comes to which of these tools to choose, of course, we're back to that question of taste. Each tool comes from a different world, and has a different "attitude" towards web development. The cool part, though, is that most new web development tools emphasize a quick start as a key feature: you could probably evaluate a dozen web development frameworks in just a couple of days. So my best advice is to to try a few and see what "clicks".
It's probably important to also pay attention to the language that the framework uses. One of the real pleasures of writing Django apps is that you get to take advantage of the awesome Python community. I've got a set of libraries in Python that I can't imagine developing web apps without; many of those libraries don't have analogues in any other environment.
So if I knew Python and Ruby equally well -- I don't -- I'd still probably lean towards Python, and towards Django. However, there's one place I can think of where Rails is far superior: Rails runs on the JVM. This is a big deal: there's any number of large corporate environments where the JVM is the only game in town. And obviously if I had to choose between Java and Ruby I'd choose Ruby!
I'll mention, though, that &lt;a href="http://www.jython.org/"&gt;Jython&lt;/a&gt; (Python on the JVM) is improving by leaps and bounds, and that getting Django working perfectly on the JVM is one of the &lt;a href="http://code.google.com/soc/2008/psf/appinfo.html?csaid=DA6AC3DE94E157E"&gt;Google Summer of Code projects&lt;/a&gt; the Jython team is sponsoring.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Shabda:&lt;/strong&gt; Coming back to the marketing question.. For most of non hackers choosing the framework to use is a big question, and the decision they will make depend on various non-tech factors, such as availability of capable skilled people. You mentioned that you would choose Django over Rails due to the awesome Python libraries. For the long term survival and growth of Django, do you not think that an early capture of mindshare in developer community is important? For example I have pitched Django to a fair number of people, and I always have to start with "Django, what?" as compared to "Yeah, we are evaluating Rails for our requirements."&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Jacob:&lt;/strong&gt; Sure, there's definitely a value of having Django be familiar to your friendly local Pointy Haired Boss, so in that context a certain amount of advertising is important. There's nothing worse than being forced by management to use the wrong tool for the job. Keep in mind, though, that this cuts both ways: I'd feel pretty unhappy if there was a team using Django because someone read about it in CTO Monthly. I'd agree that we could be doing more in terms of "brand awareness" or something, but all in all I'm pretty happy with the size and quality of Django's community.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Shabda:&lt;/strong&gt; There is not much information about the early days of Django, so a little about that. How did the move at &lt;a href="http://www2.ljworld.com/"&gt;WorldOnline&lt;/a&gt; from PHP to Python happen? Why did you create a new framework, instead of reusing something like Zope?&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Jacob:&lt;/strong&gt; I wasn't yet at World Online when we moved from PHP to Python, but from what I understand it was a pretty typical change. Adrian and Simon got fed up with the pain and suffering wrought by PHP, and wanted something cleaner and -- most importantly -- something that would be easy to maintain. Python really shines here.
The main reason we ended up building our own framework was that we didn't know we were building a framework. We just wanted to "build cool shit" and, over time, we built tools to help us do that. It wasn't until we started showing it off that we realized we had something that could be used by other people.
This, by the way, is one of the reasons I think Django turned out so great. If you sit down one day and say, "I'm going to develop a framework!" you're almost certainly going to become an Architecture Astronaut, and if you ever actually finish the thing'll be so over designed nobody will want to use it. If, on the other hand, you simply try to solve real-world problems in a clean, obvious way, you'll eventually end up with a great tool.
Look at Rails, TurboGears, even PHP; they all started as simple libraries written by frustrated programmers just trying to get the job done.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Shabda:&lt;/strong&gt; What are the overarching goals of Django? Again to make this more interesting, Here is a &lt;a href="http://www.linkedin.com/in/jacobian"&gt;quote from you&lt;/a&gt;. "My work as a core developer of Django focuses on giving anyone -- even (especially) non-programmers -- the tools to create dynamic, content-driven websites." Should not that be the job of something like &lt;a href="http://wordpress.org/"&gt;Wordpress&lt;/a&gt;, while Django should aim to give "programmers, but not non-programmers -- the tools to create dynamic, content-driven websites."&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Jacob:&lt;/strong&gt; Wordpress is great if you want to publish a blog, but what if you want a website to track a book collection, or sell tickets to concerts, or organize a local farmer's market? There's a great deal that Wordpress (and other single-purpose tools) can do, but the amazing thing about the web is just how wide-open the possibilities are. There's a whole world of possibilities out there, and the end-goal is to help anyone self-publish anything they can dream up.
One of the most fascinating aspects of the history of communication is how intertwined literacy is with social controls. For most of the history of humankind, literacy was strictly available to the elite. The Web created the greatest democratization of publishing ability in history, and has almost immediately turned into a battleground between traditional, centralized publishing and decentralized democratic publishing.
As a programmer, we don't personally play much of a role in this sea change, but I do see the lowering of the barrier to self-publishing as something we ought to continuously think about.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Shabda:&lt;/strong&gt; If Django's goal is "and the end-goal is to help anyone self-publish ", does not that mean Django is trying to fill the niche of an Extensible CMS like &lt;a href="http://drupal.org/"&gt;Drupal&lt;/a&gt;, as compared to filling the gap left by PHP? Are non programmers really using Django, or are they using apps built with Django?&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Jacob:&lt;/strong&gt; No, you're right that Django's lower-level than something like Drupal. Django's not trying to be a CMS but to be a tool you could use to build your own CMS. It's easier to design your own content models than to shoehorn your publishing into a CMS limited by the ideas of its developers.
There are indeed quite a few non-programmers using Django, though in the long run I think the interesting trend is that more and more computer users are learning a little bit of programming -- enough to develop a site with Django, say.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Shabda:&lt;/strong&gt; (Since I ask this to everyone!) What is one thing about Django which you absolutely love, and one thing which you think Django should do differently?&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Jacob:&lt;/strong&gt; I only get to choose one thing I love?
I think my favorite bit of Django is the &lt;a href="http://www.djangoproject.com/documentation/url_dispatch/"&gt;URLconf&lt;/a&gt; system. I love that Django forces me to think about URL design as part of my application instead of some byproduct; I've always hated web tools that try to someone pretend that you're writing a desktop app. I'll admit to obsession over my URL design from time-to-time, but I really enjoy clean, semantic URLs.
As for something we should do differently: the assumption that you'll only use a &lt;a href="http://code.djangoproject.com/wiki/MultipleDatabaseSupport"&gt;single database&lt;/a&gt; is a bad one, and needs to be fixed. Unfortunately, it's an assumption that we made really early on, which means that fixing it is going to be tricky. There's some smart people working on it right now so I've got high hopes, but I wish we'd not made that assumption to begin with.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Shabda:&lt;/strong&gt; Django started as a in house project and was later open sourced. At your
current startup your major job is with Django itself. The Django book which
you wrote was released under a permissive license. How difficult is it to
convince people outside the hacker culture of the business value of open
source? What are the best ways to do this? How difficult was doing this at
World online?&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Jacob:&lt;/strong&gt;
These days, thankfully, the business value of Open Source is pretty
well-established. There really hasn't been a lot of "convincing"
necessary. For example, Apress didn't just agree to release the Django
Book under a permissive license: they actively encouraged it. You'd
have to ask them if it was "worth it" in terms of sales, but I'm sure
that being the first Google hit for "django book" didn't hurt!
Releasing Django at World Online is actually an interesting story. We
decided at the 2005 PyCon that we should Open Source some of our
software, and started building a business case for doing so. We
prepared a series of arguments -- open source will increase our
visibility and lead to easier sales and easier hiring, open source
will improve the quality of our software, etc. -- and took them to our
management. All of those things turnned out to be true, by the way,
but o our surprise, the argument that was the most effective was
actually a "moral" one. We talked about how Open Source had helped our
business (Apache, Linux, Python, etc.) and argued that it was time to
"give back" to the community. The World Company has always been a
company that's tried to be a conscientious part of our local community
here in Lawrence, and they really jumped at the chance to participate
in the global Open Source community.
I like to tell this story, by the way, because it really makes me
hopeful that this "hacker culture" is in fact compatible with business
culture. Fact is that most businesses &lt;em&gt;are&lt;/em&gt; in fact concerned with
doing the "right thing" -- they just often don't know what that is
when it comes to technology. Of course the business case for Open
Source needs to be there, too -- and it is -- but I think there are a
lot of companies that'll jump on the chance to "give back."&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Shabda:&lt;/strong&gt; Before we close would you like to share any tips with us?
&lt;strong&gt;Jacob:&lt;/strong&gt; If you don't read the &lt;a href="http://www.djangoproject.com/community/"&gt;Django community aggregator&lt;/a&gt; you really should: there are some incredibly smart people blogging about Django and you'll learn something new from all of them.&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;This was the interview of &lt;a href="http://www.jacobian.org/"&gt;Jacob Kaplan-Moss&lt;/a&gt;. We have a few more Django interviews coming, before we close this series of Django interviews, so &lt;a href="http://42topics.com/blog/feed/"&gt;stay tuned&lt;/a&gt;.&lt;/p&gt;</description><guid>http://agiliq.com/blog/2008/05/an-interview-with-jacob-kaplan-moss-creator-of-dja/</guid></item><item><title>An interview with Michael Trier</title><link>http://agiliq.com/blog/2008/05/an-interview-with-michael-trier/</link><description>&lt;p&gt;&lt;img src="http://uswaretech.com/blog/wp-content/uploads/2008/05/mtrier-small.jpg" alt="" title="mtrier-small" width="154" height="205" class="right frame" /&gt;
&lt;a href="http://blog.michaeltrier.com/"&gt;Michael Trier&lt;/a&gt; is  a long time Django user and evangelist. He has worked with a number of technologies including Rails and .net. His insights on marketing Django to traditionally &lt;em&gt;Enterprisy&lt;/em&gt; areas were extremely informative. He produces &lt;acronym title="This Week in Django"&gt;TWiD&lt;/acronym&gt;, along with &lt;a href="http://oebfare.com/"&gt;Brian Rosner&lt;/a&gt; which is great to keep abreast of the latest happenings in the Django community. He graciously agreed to be interviewed by the &lt;a href="http://42topics.com/blog/"&gt;42topics blog&lt;/a&gt;.&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;&lt;strong&gt;Shabda:&lt;/strong&gt;  Would you tell a little about yourself, how did you get started with Django, what other projects have you used or are associated with?&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Michael:&lt;/strong&gt; Well, I've been programming ever since I can remember, probably around 11 years old.  I grew up in Silicon Valley, and that whole story is a pretty interesting one.  I did the usual thing of starting out with languages like ASM, C, C++ , Pascal.  Moved on to things like Delphi, VB, and most recently I spent quite a bit of time with Ruby, Rails, and within the past year and a half dabbling with Django.
I came to Django for a particular reason.  I was focussed on building a high content push type of site and it just seemed like Django was a much better fit for that than Rails.  Obviously I could have done it with either language, but I believe in using the right tool for the job.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Shabda:&lt;/strong&gt; You are using Django for your next venture. What are the specific areas where using Django been a better way to develop for you, compared to any other choice you might have made, say Rails?&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Michael:&lt;/strong&gt; I hate to bring up the scaling issue, but that was certainly something I was seeing as a problem with Rails.  The type of site I'm building I hope to see some pretty high traffic (don't we all).  So that was one thing.  The other thing was that it seems like if you're doing a large content driven site, Django just makes that very easy.  Additionally, as most people say, one big win for Django is the built in Admin.  It has allowed me to focus on the front end of the site, while giving the other people involved a way to immediately start working on the content part.  Right away this helps us see where we may need to enhance functionality or perhaps we've built in too much flexibility.
That kind of feedback comes back to us quickly and so that is invaluable.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Shabda:&lt;/strong&gt; How do you compare Rails to Django? In what areas is Django better than Rails (Apart from scaling/efficiency)? What does Django still need to learn from Rails?&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Michael:&lt;/strong&gt; That's a good question and not something I've given a lot of thought to, but off the top of my head I would say that with something like the Admin, Django definitely wins over Rails.  Now within the Rails community there are a lot of interesting &lt;a href="http://code.trebex.net/auto-admin"&gt;third-party&lt;/a&gt; plugins that have attempted to mimic the Django admin, but up until now those that I've looked at have fallen short.  It's a huge effort as we've seen with the amount of work being put into the &lt;a href="http://code.djangoproject.com/wiki/NewformsAdminBranch"&gt;NewForms-Admin rewrite&lt;/a&gt;.
I also think the middleware stuff in Django is very nicely done, although it could use a bit more options in terms of request / response ordering of the middleware items.  I also think Django templates are just perfect.  I really can't see how to enhance on those at all.
As far as Rails is concerned, there's a lot of nice features in rails that Django could learn from, and most of it just has to do with the maturity of the two projects.
Rails caching takes caching one step further.  Rails has model level validations which are very nice and quite frankly the right way to do it, in my opinion.
&lt;a href="http://ar.rubyonrails.com/"&gt;ActiveRecord&lt;/a&gt;, Rails' ORM, has things like aggregation support, and supports a lot of flexibility in how you are able to filter the dependency relationships between your models with things like &lt;code&gt;has_many :through&lt;/code&gt; (basically intermediate models).
I also like the &lt;code&gt;before_filter&lt;/code&gt; and &lt;code&gt;after_filter&lt;/code&gt; type of stuff in rails.  It makes it real easy to invalidate cache or do other things in an event driven way.
Oh one thing back on the Django side, I think NewForms are done really well.  It's an elegant solution.  And it is interesting because in the .net world I'm starting to see a copy of that through things like &lt;a href="http://quickstarts.asp.net/Futures/dynamicdatacontrols/default.aspx"&gt;dynamic data controls&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Shabda:&lt;/strong&gt; One specific area which I believe Django can learn from Rails is marketing. What would you say to this? With 1.0 release coming soon, how can Django start to market itself better.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Michael:&lt;/strong&gt; I would agree with you on this.  I think the impending 1.0 release will definitely do a lot on its own to market the product.  There are also at least 3 more books coming out in the next several months.  The &lt;a href="http://code.google.com/appengine/"&gt;Google App Engine&lt;/a&gt; announcement that heavily featured the name of Django has also helped to bring it focus.
But there's another element that I don't know if you can fabricate and that is that &lt;a href="http://loudthinking.com"&gt;DHH&lt;/a&gt; is a charismatic individual.
In terms of real things that can be done are obviously things like more screencasts just featuring the product.  It's interesting to note that consistently the number 1 screencast on iShowU is the Django one that features a simple tutorial on Django.  Although a lot of people have no interest in screencasts, there are a lot of people that do.  We all learn in different ways.
I also think that on the djangoproject.com weblog we can do a much better job of regular blogging on what is going on within the community.
There are times when you look at the &lt;a href="http://www.djangoproject.com/weblog/"&gt;weblog&lt;/a&gt; and it's 2 or 3 months old.  From the face of the website you would think that nothing is going.  The last release is over a year old.  Meanwhile those of us that are in the community every day, we see that tons of stuff is happening.  This needs to be communicated better.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Shabda:&lt;/strong&gt; Talking of GAE, what effect do you see of it on Django? How can Django make the GAE-Django integration painless, or even if this should be done, and what efforts the Django community should expend on this instead of say focusing the efforts on 1.0 release?&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Michael:&lt;/strong&gt; I think GAE helps Django, but only a little bit.  It helps it from the standpoint of name recognition and will cause a lot of people to say to themselves, "what's this Django thing all about."  I think GAE really helps Python in a real way.
In terms of making the integration painless, that's going to be a very difficult task.  I have a taste of that with the django-sqlalchemy project I'm working on, and I'm just mapping a relational model to another relational model.  With GAE it's quite different.  That said, Google folks are working on on a project to do "some" &lt;a href="http://code.google.com/p/google-app-engine-django/"&gt;mapping&lt;/a&gt; of Django to GAE.  I think over time it will expand in its focus.  I think if they are willing they are the best people to do the work.  I'd rather see Django focus on getting to that 1.0 point.
As far as GAE itself is concerned, I'm kind of on the fence on the real value there.  I know that people like &lt;a href="http://jaiku.com/"&gt;Jaiku&lt;/a&gt; are porting their stuff over to it, and Kevin Rose said that it would have been a great platform for something like Digg. Personally, I'm not really convinced of that, but it's still early so we'll all have to wait and see what comes of it.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Shabda:&lt;/strong&gt; Your TWiD has been a great help for people to keep track of all the happenings in the community. Would you like to share some interesting tidbits you have learned with TWiD, and point to the more interesting ones?&lt;/p&gt;
&lt;p&gt;&lt;img src="http://uswaretech.com/blog/wp-content/uploads/2008/05/twid_small.png" alt="" title="twid_small" width="150" height="150" class="right" /&gt;
&lt;strong&gt;Michael:&lt;/strong&gt; Thank you, I'm glad that people find it helpful.  I think one of the interesting things is the amount of work that goes into it.   A lot of people are surprised because neither Brian nor I are very professional, so when we're on the mic it sounds like we're just sitting there talking about whatever.  The reality is that it takes quite a bit of work in finding the stuff we want to discuss, attempting to understand enough about the topics to at least sound somewhat intelligent on them, and then there is the recording and post-production.
As far as actual topics the &lt;a href="http://blog.michaeltrier.com/2008/4/22/this-week-in-django-19-2008-04-20"&gt;two&lt;/a&gt; &lt;a href="http://blog.michaeltrier.com/2008/4/28/this-week-in-django-20-2008-04-27"&gt;recent&lt;/a&gt; episodes on Internationalisation have been a great learning experience for me personally.  Going into it, I really didn't even know enough about it to know what questions to ask. Thankfully &lt;a href="http://pointy-stick.com/blog/"&gt;Malcolm Tredinnick&lt;/a&gt; put the whole thing together.  He's been a huge help to the show.
Another show that was fascinating for me was the one on &lt;a href="http://code.djangoproject.com/wiki/GeoDjango"&gt;GeoDjango&lt;/a&gt; with &lt;a href="http://djangopeople.net/wensing/"&gt;Matthew Wensing&lt;/a&gt;.  It's a fascinating topic and I hope to put together more shows on that subject.
I think a lot of people like the interviews, and we do too, but we also don't want to make the show just interviews every week.  So we try to split it up.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Shabda:&lt;/strong&gt; Would you tell a little about the venture you are working on?&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Michael:&lt;/strong&gt; Sure.  The project is a hyper-local media site.  We're working on  providing an online place for a mix of general media type of content (stories, events, etc...) with citizen journalism types of offerings.  A lot of people are working in this space, trying to figure out how you bring the big media type of stuff down to a local level.
We then want to mix some of that with interesting datasets, a la &lt;a href="http://everyblock.com/"&gt;EveryBlock&lt;/a&gt;, as well as provide some level of social interaction.  The cool thing is that once we release we're going to make the entire thing available on a New BSD license.
Frankly, initially it's not going to be that interesting.  A lot of what we'll provide in the way of Classifieds, Marketplace, Aggregators, stories, etc.. will be similar to the types of offerings that you see in things like &lt;a href="http://www.ellingtoncms.com/"&gt;Ellington&lt;/a&gt; or just about any newspaper's online presence these days.  Down the road I hope that we can expand it into something quite useful.
The framework we'll be releasing is called ArEyah.  So expect to see something from me on that in the next several months.  Timeframes are tough to nail down at this point because this is a side project in addition to some of the other things I'm involved in.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Shabda:&lt;/strong&gt; For many people, such as me, the question is what business advantage remains for you after you are releasing all your secret sauce under an open license. For example even EveryBlock will have to &lt;a href="http://www.everyblock.com/about/faq/"&gt;release all their source&lt;/a&gt; under an open license, after the end of the &lt;a href="http://www.knightfoundation.org/"&gt;Knight Grant&lt;/a&gt; expiry period. What would you say to this? What do you hope to achieve with releasing the project under a BSD license?&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Michael:&lt;/strong&gt; That's really a good question.  For me it was two-fold.  First I wanted to take the "intellectual value" of it off the table.  In other words, I did not want to be in a position with my partners where I had an extremely unfair advantage.  Secondly I really think this is something that could benefit communities everywhere; of course that remains to be seen.  If that is the case, then I think a lot of individuals would get involved and make it a better product for the benefit of all.
As far as competitive advantage, I really see that being in the execution.  In comes down to how well we serve our community.  If we are not doing a good job of it then someone else should be able to come along and beat us out there.  There were certainly be some things that are specific to the community that we're targeting that don't have a place in the general framework.  Those things will be our own and they will be highly tailored for our use, in order to serve a specific need we have here.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Shabda:&lt;/strong&gt; We see a lot of comparison going on between Django and ROR, or Django and Turbogears. But we do not see enough comparison between Django and other traditionally 'Entrprisy' frameworks. Say Java based frameworks like Struts+Hibername or Asp.net. As you have worked with .net, how would you compare Django with these frameworks. What can Django do to make itself popular in the areas dominated by these frameworks?&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Michael:&lt;/strong&gt; The differences have less to do with feature set comparisons.  A lot of what I do every day for corporate clients could be done much more quickly and actually often more robustly with something like Django.  So it's not a thing where you can say feature x is in .net but not in Django.  That said like any framework / language there are edge case types of things where you might say "Java is the right tool for this job."
What it really comes down to is the corporate culture.  .NET and Java own those corporate cultures.  There are real reasons why it makes good business sense to build your corporate infrastructure on Microsoft products.  You can pick up the phone and get three .NET developers tomorrow.  Regardless of whether your company is based in Louisville, Kentucky or White Plains, New York.
In the case with Microsoft, much more than in the Java world, they provide a singular full-stack solution.  No one, in the executive sense, needs to make any more decisions about which reporting tool, which database backend, or which IDE they are going to decide to use.  Often that alone is motivation enough.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Shabda:&lt;/strong&gt; Your last post on your blog was about the benefits of DVCS as compared to Centralized systems. What are the compelling benefits of DVCS over, say, SVN. In particular how can moving to a DVCS help Django?&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Michael:&lt;/strong&gt; Well I'm somewhat new to the DVCS world, as are a lot of people, so I'm no expert on the subject.  To me though the benefits of a DVCS are at more of a personal level.  I have seen tremendous personal benefit in being able to commit while sitting in a coffee shop, or being able to branch code locally and then merge that back in.
As far as benefit to a centralized project like Django, I guess it remains to be seen.  I've been watching the shift of Rails to Git with great interest.
So I guess in summary, I just don't know enough at this point to say that it would be beneficial. The shift is probably more psychological. I think, for a lot of projects, it would be just another way to have a centralized repository.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Shabda:&lt;/strong&gt; You and Brian Rosner are working on &lt;a href="http://code.google.com/p/django-sqlalchemy/"&gt;django-sqlalchemy&lt;/a&gt;. How would a &lt;a href="http://www.sqlalchemy.org/"&gt;sqlalchemy&lt;/a&gt; based ORM be better than the current implementation? What is the status of this project?&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Michael:&lt;/strong&gt; Yes, Brian and I are probably the primary committers, but we have several other individuals that have pitched in on the project.  I like to think about the benefits in two separate areas.  First, there's the approach where you just plug django-sqlalchemy in and continue to use Django with its filter syntax, etc...
In that case the benefits you gain are not benefits at the ORM level (because you're still using Django's syntax, which doesn't support things like aggregation).  The benefits instead are things provided as a result of having SQLAlchemy as the backend.  So this would be things like multi-database backends, &lt;a href="http://www.sqlalchemy.org/docs/04/sqlalchemy_orm_shard.html"&gt;sharding&lt;/a&gt;, additional database support like DB2 or Firebird.
The second approach is where you actually need things like aggregation or more complex queries, without resorting to raw sql.  In that case we expose SQLAclhemy's ORM right on your models.  So the full power of SQLAlchemey gets exposed and available for you to use whenever you need.
So I could technically have 90% of my ORM code just using Django's syntax but then realize that I need to do something a little outside of its capabilities.  In that situation I might chose to just use the exposed properties to get what I need.
Finally there's one more thing related to this that we still do not have clear at this point, but will come down the road, and that's actually adding different functionality at the model level.  This might be things like Intermediate Model support being made available through django-sqlalchemy.
As far as status of the project, it has been moving along very well.  We have a few more filters to implement and a handful of management commands, plus lots more testing.  One of the things I've done in the past week is to code up a test application using django-sqlalchemy to see in a "real-world" sense where some of the problems are.  That has been really helpful.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Shabda:&lt;/strong&gt; So if the extra features added by SQLachemy is not needed, then this aims to be backwards compatible with current Django syntax?&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Michael:&lt;/strong&gt; Yes, our aim is that you could plug it in and run all your stuff just as is.  In other words with django-sqlalchemy as your backend db (that's how it gets exposed) we should be able to pass all of Django's test.  Once we're able to do that we tag it 1.0 and get some people hammering on it.
We do have one big hurdle that I have not discussed.  Currently we are using multiple inheritance to modify the Django classes.  That doesn't work for the contrib apps or third-party apps because that would require a change to their code base.
We took this approach originally just because we wanted to focus on the mapping issues first and prove the concept.
The eventual plan is to use some class replacement techniques to inject our stuff right into the Django models at evaluation time.  That will make it work across the board.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Shabda:&lt;/strong&gt; Before we leave. Would you like to share a tip, or hard to find information about Django with our readers?&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Michael:&lt;/strong&gt; Not really a code tip, because we do those each week on TWiD, but more of an approach tip.  The generic views stuff is extremely powerful, and quite often I see a lot of new users doing stuff in views that could easily be done with a generic view, or with a wrapped generic view.  James Bennett has a &lt;a href="http://www.b-list.org/weblog/2006/nov/16/django-tips-get-most-out-generic-views/"&gt;great post&lt;/a&gt; on this, and I suggest everyone check it out.  I think often, especially for people that are new to the community, the power of it is overlooked.
Finally one more thing, spend some time in &lt;a href="irc://irc.freenode.com/"&gt;IRC&lt;/a&gt;. IRC is a great way to get an education in Django very quickly.  Reading the questions and the responses has been invaluable to me in learning how to use Django more effectively. It's a great community.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Shabda:&lt;/strong&gt; Thanks a ton for this great interview. It was extremely  informative and interesting.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Michael:&lt;/strong&gt; Thank you.&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;This was the interview of Michael Trier. This week I am not going to any more interview, but stay tuned for next week, we have even more Django interviews coming.&lt;/p&gt;
&lt;p&gt;And of course, the &lt;a href="http://42topics.com/"&gt;42topics&lt;/a&gt; is live now. And we have a &lt;a href="http://42topics.com/django/"&gt;Django&lt;/a&gt; section. (&lt;a href="http://42topics.com/blog/how-42topics-works/"&gt;How 42topics works&lt;/a&gt;?)
So join now, and lets get rolling.&lt;/p&gt;</description><guid>http://agiliq.com/blog/2008/05/an-interview-with-michael-trier/</guid></item><item><title>Popularizing Django -- Or Reusable apps considered harmful.</title><link>http://agiliq.com/blog/2008/05/popularizing-django-or-reusable-apps-considered-ha/</link><description>&lt;p&gt;For all its technical merits, Django is still a very &lt;a href="http://google.com/trends?q=php%2C+django%2C+"&gt;niche technology&lt;/a&gt;. It is my belief that the thing which is holding Django back the most, is due to one of its strengths.&lt;/p&gt;
&lt;p&gt;Making reusable apps is easy and simple in Django. In Django this is the &lt;a href="http://www.b-list.org/weblog/2007/mar/27/reusable-django-apps/"&gt;correct&lt;/a&gt; way to do things. You take a few apps, mix them together in your project, and deploy to start your site.&lt;/p&gt;
&lt;p&gt;Compare the installation steps of Wordpress and an imaginary blog software better than Wordpress called Djangopress.&lt;/p&gt;
&lt;h4&gt;Wordpress&lt;/h4&gt;
&lt;ol&gt;
&lt;li&gt;FTP wordpress to webserver.&lt;/li&gt;
&lt;li&gt;Point browser to site.com/blog&lt;/li&gt;
&lt;li&gt;Next-Next-Next done.&lt;/li&gt;
&lt;/ol&gt;
&lt;h4&gt;Djangopress&lt;/h4&gt;
&lt;ol&gt;
&lt;li&gt;Svn checkout Djangopress&lt;/li&gt;
&lt;li&gt;Svn checkout &lt;a href="http://code.google.com/p/django-registration/"&gt;django-registration&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Svn checkout other Django apps Djangopress depends on. Maybe &lt;a href="http://code.google.com/p/django-mptt/"&gt;django-mptt&lt;/a&gt;, &lt;a href="http://code.google.com/p/django-threadedcomments/"&gt;django-threadedcomments&lt;/a&gt; or a few others.&lt;/li&gt;
&lt;li&gt;Edit your settings.py to add all these apps to &lt;code&gt;INSTALLED_APPS&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Add database settings, and other changes if needed.&lt;/li&gt;
&lt;li&gt;Telnet to your server and do &lt;code&gt;syncdb&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Create templates. Done.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;This does not take into account the extra hoops Apache makes  you jump through, compared to using a PHP app.&lt;/p&gt;
&lt;h3&gt;How I got started with web programming.&lt;/h3&gt;
&lt;p&gt;I wanted to run a forum. &lt;a href="http://www.phpbb.com/"&gt;PhpBB&lt;/a&gt; was free, and seemed most widely used. Installed it, and wanted to tinker with it, so learnt Php. If there was a different forum software, which was technically superior, but which asked me to write templates for it before I could start a forum, guess which one I would have chosen?&lt;/p&gt;
&lt;h3&gt;So how to popularize Django.&lt;/h3&gt;
&lt;p&gt;In my &lt;a href="http://42topics.com/blog/2008/04/interview-with-james-bennett-django-release-manager/"&gt;interview of James Bennett&lt;/a&gt;, I asked what is Django's killer app. And he said there need not be a Killer app for Django, reusable apps will do. I guess I will have to disagree. Even internet needed a &lt;a href="http://en.wikipedia.org/wiki/Webmail"&gt;killer app&lt;/a&gt; to get breakthrough popularity. Let's see what a Killer app gives you.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;It fills a big niche, so people are forced to learn your language/framework.&lt;/li&gt;
&lt;li&gt;It forces the Hosting company to support your language/framework.&lt;/li&gt;
&lt;li&gt;If a large number of places use it, it gives your framework name recognition.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;So to popularize Django, I propose setting up DjangoPackagedApps.com to distribute packaged Django apps, to complement reusable Django apps. A packaged Django app, must have these properties.
1. All dependencies must be included.
2. Beautiful templates must be included out of the box.
3. Users must not need to modify anything in settings.py apart from the database settings.&lt;/p&gt;
&lt;p&gt;And installing the PackagedApp must be no more than the number of steps needed in Wordpress.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Svn checkout/FTP DjangoPackagedApp&lt;/li&gt;
&lt;li&gt;Only thing to edit in settings.py is database settings.&lt;/li&gt;
&lt;li&gt;Do syncdb. done.&lt;/li&gt;
&lt;/ol&gt;
&lt;hr /&gt;
&lt;p&gt;Do yo use &lt;a href="http://42topics.com/Django/"&gt;Django&lt;/a&gt;? Do you &lt;a href="http://42topics.com/programming/"&gt;program&lt;/a&gt;? Find things which YOU will love reading at &lt;a href="http://42topics.com/register/"&gt;42topics.com&lt;/a&gt;.&lt;/p&gt;</description><guid>http://agiliq.com/blog/2008/05/popularizing-django-or-reusable-apps-considered-ha/</guid></item><item><title>An interview with Russell Keith-Magee - Django core contributor</title><link>http://agiliq.com/blog/2008/05/an-interview-with-russell-keith-magee-django-core-/</link><description>&lt;p&gt;&lt;img src="http://uswaretech.com/blog/wp-content/uploads/2008/05/russellm.jpg" alt="" title="russellm" width="100" height="69" class="right frame" /&gt;
&lt;a href="http://djangopeople.net/freakboy3742/"&gt;Russell Keith-Magee&lt;/a&gt; is a longtime core contributor to Django. He has worked extensively with the Django testing and serialization components.  He is
currently working on &lt;a href="http://code.google.com/p/django-evolution/"&gt;django-evolution&lt;/a&gt;, the ability to do schema evolution from Django, an often requested feature, and is mentoring a GSOC proposal to add
&lt;a href="http://groups.google.com/group/django-developers/browse_thread/thread/749ebaf0fa80f807"&gt;aggregate queries&lt;/a&gt; support to Django ORM. He is currently a Senior R&amp;amp;D Software Engineer at &lt;a href="http://plugger.com.au"&gt;plugger.com.au&lt;/a&gt;. He graciously agreed to an email interview with the &lt;a href="http://42topics.com/blog/"&gt;42topics blog&lt;/a&gt;.&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;&lt;strong&gt;Shabda:&lt;/strong&gt; Would you tell a little about yourself? How did you get started with
Django? What areas of Django have you contributed to?&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Russell:&lt;/strong&gt; I'm a thirty-one year old, father of one, living in the most isolated
capital city in the world - Perth, Western Australia.
Strangely, for all my involvement in Django, my background has almost
nothing to do with the web. I studied Physics as an undergraduate, and
studied neural networks for my PhD. My first job was with a startup in
the defence industry developing simulation frameworks. Over time,
mostly as a result of my association with Django, I've become more
involved in building web services.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Shabda:&lt;/strong&gt; How did you get started with
Django? What areas of Django have you contributed to?&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Russell:&lt;/strong&gt; I've always had a bunch of little pet projects that I've fiddled with
in my spare time. Over time, these projects have migrated over a range
of languages until I found (and fell in love with) Python. Around the
time of Web 1.0, I started looking at various web frameworks (PHP,
&lt;a href="http://www.zope.org/WhatIsZope"&gt;Zope&lt;/a&gt;, etc), but I never really managed to get mental traction - they
were either so complex that it was hard to work out where to start, or
they provided a bunch of tools but didn't really make it obvious how
the pieces all fitted together. Plus, the documentation for these
frameworks was up to the common open source standard - an even mix of
the awful, the incomprehensible and the non-existent.
Around mid 2005, the buzz about Ruby on Rails started to grow, so I
took a look. I could see that it had promise - it was an interesting
new way of looking at solving web problems - but again it suffered
from the documentation problem. One day, I found a blog entry
referring to Django, and finally all the pieces fell into place. The
documentation was excellent, the simple stuff was painfully simple,
and there was a clear separation of concerns - there is the URL module
which routes requests, an ORM to access the database, etc.
At the time, the pet project I was using to test new frameworks was a
time/task tracking system. After working through the tutorials, I
tried implementing a task tracker, and quickly realized that Django
didn't have support for aggregate functions. I made a few suggestions,
which were universally rejected (in retrospect, for very good
reasons), so I went digging in the code to try and come up with some
better ideas.
In the process, I ended up spending a lot of time in the query system,
which put me in a position to submit patches for a few small bugs in
queries. Once I had found my feet, I tackled some larger enhancements.
One of my first big contributions was modifying the filter syntax so
that queries could span reverse relations; that is, if Book has a
foreign key on Author, I modified the syntax to allow Author queries
to ask about their related books. Of course, between the &lt;a href="http://code.djangoproject.com/wiki/RemovingTheMagic"&gt;Magic Removal&lt;/a&gt;
changes and &lt;a href="http://pointy-stick.com/blog/"&gt;Malcolm's&lt;/a&gt; &lt;a href="http://code.djangoproject.com/wiki/QuerysetRefactorBranch"&gt;Queryset refactor&lt;/a&gt;, most of this code has now
been thrown to the wind, but at the time it was a big improvement.
&lt;a href="http://www.holovaty.com/"&gt;Adrian&lt;/a&gt; noticed the contributions I was making, and offered to give me
commit access and make me a core developer.
Not long after I joined as a core developer, the Magic Removal branch
started, which consumed pretty much all my efforts for about six
months. This involved more changes to the query system, but also with
the way models were defined and instantiated. Following that, I
developed the &lt;a href="http://www.djangoproject.com/documentation/testing/"&gt;test framework&lt;/a&gt;, which also involved working with the
&lt;a href="http://www.djangoproject.com/documentation/serialization/"&gt;serialization framework&lt;/a&gt;. I did some work on &lt;a href="http://code.djangoproject.com/wiki/NewformsAdminBranch"&gt;newforms-admin&lt;/a&gt; in the
early days, including developing the new Media definition framework
and a refactor of form input fields for files.
I have also spent some time on side projects that aren't directly
targeting the Django trunk, but might be integrated one day. The most
notable of these is &lt;a href="http://code.google.com/p/django-evolution/"&gt;Django Evolution&lt;/a&gt; - an implementation of schema
evolution for Django.
I've been a little bit quiet over the last few months; I've just
changed jobs, which is consuming a lot of my time, and I've had a few
bouts of illness which have slowed my progress. I have also been
helping out &lt;a href="http://b-list.com/"&gt;James Bennett&lt;/a&gt; by acting as Technical Reviewer for his
upcoming book "&lt;a href="http://www.apress.com/book/view/9781590599969"&gt;Practical Django Projects&lt;/a&gt;"; there won't be much to show
for this until the book is published, but when it comes out, you're
all in for a treat - it's going to be a great resource.
I'm hoping to get back into the swing of things in the next few
months. One of the first new tasks will be a very old issue - I'm
mentoring a student (Nicolas Lara) in a &lt;a href="http://code.google.com/soc/2008/django/appinfo.html?csaid=6207B3094B97F424"&gt;GSOC project&lt;/a&gt; to implement
aggregates in the query system. So - after almost 3 years, my original
itch may actually get scratched.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Shabda:&lt;/strong&gt; Have you worked with
other competing frameworks, say &lt;a href="http://www.rubyonrails.org/"&gt;Ruby On Rails&lt;/a&gt;, &lt;a href="http://turbogears.org/"&gt;Turbogears&lt;/a&gt; etc?&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Russell:&lt;/strong&gt;
I've looked briefly at a lot of other web frameworks. In the early
days I looked at Zope and PHP while gaining a foothold in the web
world. Since joining the Django project, I occasionally look at what
the other frameworks - in particular, Ruby on Rails and TurboGears -
are doing. It's occasionally helpful to see how other people are (or
aren't) solving various problems, borrowing the good ideas where
possible.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Shabda:&lt;/strong&gt; What other
software/applications have you worked with. (Both OSS and otherwise)?&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Russell:&lt;/strong&gt; A little bit of everything. I used Linux as a personal computing
platform back in the glory days of &lt;a href="http://www.slackware.com/"&gt;Slackware&lt;/a&gt; and &lt;a href="http://en.wikipedia.org/wiki/Yggdrasil_Linux"&gt;Yggdrasil&lt;/a&gt;. I was
compiling KDE and GNOME before they were even v1.0, and I've toyed
around with writing for both frameworks. I've used Windows in a
commercial environment, and I've gotten to know the eccentricities of
every version of Microsoft Visual Studio from v6 to 2008 in far too
much detail. I've written Java, both server side and client side.
I've spent a lot of time with a simulation protocol called &lt;acronym title="High
Level Architecture"&gt;HLA&lt;/acronym&gt;. One of the more notable products of that work was
securing some funding and commercial support for an &lt;a href="http://porticoproject.org"&gt;open source
implementation of the HLA protocol&lt;/a&gt;.
I'm a huge fan of Linux, especially on the server side. However, I
attribute most of my recent productivity to being a Mac Switcher. I
found that once I made the switch, I spent a lot less time messing
around with compiling the latest, slightly less buggy version of some
esoteric utility, and a lot more time building useful code. It's
possibly a little '&lt;a href="http://en.wikipedia.org/wiki/Post_hoc_ergo_propter_hoc"&gt;post hoc ergo propter hoc&lt;/a&gt;', but my Mac switch
correlates almost exactly with being accepted as a Django core
developer. Regardless or the causation, give me a MacBook Pro, a copy
of TextMate and a good net connection and I'll be a very happy man for
a long time.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Shabda:&lt;/strong&gt; You have worked with a number of web frameworks. What made you choose
Django over them? What are the strong points of Django compared to say ROR?
Compared to Turbogears? What can Django learn from these other frameworks?&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Russell:&lt;/strong&gt; I haven't worked extensively with any other web framework. I've had
the occasional poke around - mostly to see how the other guys do
things. To my eyes, at a technical level the various modern web
frameworks have a lot more in common than they have differences. All
of this generation of web frameworks are about providing a clear layer
between the database and the user, proving a simple mechanism for
mapping web requests to functions that serve those requests, and
providing a clean way to render content for the responses.
Sure, there differences in language of implementation. There are some
philosophical differences like whether templates should allow
executable code. There are also some feature differences. However,
these are all minor in the grand scheme of things. The philosophical
differences haven't stopped anyone from building web applications in
any of the frameworks. Given enough time and resources, any feature
could be implemented in any framework. Language choice is also largely
irrelevant. I've used a bit of Ruby, and while it has some interesting
features as a language, the difference between Python and Ruby is a
lot less than the difference between, say, Python and C++.
What this leaves is the stuff outside the technical realm - resources,
documentation, and the community. This is the reason I choice Django
in the first place, and I still think that they are areas of strength
- I certainly don't regret my original decision.
I remember when I first found the Django website - I very quickly got
the impression that it was built by a group of people that really
cared about what they were building, and how it was perceived. The
website and other resources weren't just rapid constructions or
reflections of this week's design fad - they were designed with care.
The same went for the documentation - it wasn't just a bunch of
documents autogenerated from source code comments or a sprawling wiki
- they were custom written by someone who knew how to write, and more
importantly, knew how to edit. As a result, Django's tutorials and
documentation made getting started an almost painless process - both
as a user, and as a developer. The attitude of the community is also
important; Adrian and Jacob have established a very civil community
and the community as a whole tries to keep it that way.
I think the biggest lessons Django can learn from other frameworks is
in how to market itself. Because we're still pre-v1.0, we haven't
really been aggressive about marketing ourselves. Some of the other
frameworks have been selling themselves for a long time, so we are in
a position to learn from their experience.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Shabda:&lt;/strong&gt; One of the most requested features with Django is schema-evolution, which
you are working on. What are the design goals for &lt;a href="http://code.google.com/p/django-evolution/"&gt;django-evolution&lt;/a&gt;? How
production ready is this?&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Russell:&lt;/strong&gt; At the moment, Django Evolution handles the simple cases
(add/delete/rename simple field) fairly well. There are some bugs in
the more complex cases, particularly those involving foreign keys and
many-to-many fields. It tends to work quite well for SQLite and
Postgres; MySQL tends to be more problematic. At this time, I'd
classify it as "production ready for capable developer". As long as
your schema evolution needs aren't too advanced and you're willing to
do a bit of hand holding and carefully check the SQL that is produced,
you can use Django Evolution right now. If you're not as confident
with raw SQL, you might want to wait a while.
Obviously, the long term goal is to make it "production ready for
everyone", and support every possible change that you can make to a
Django model. Completely aside from fixing bugs and supporting other
databases, one of the big open issues is populating data into new
columns. At present, we have some simple mechanisms to put in default
data, but these are somewhat limited. Longer term, we're aiming to be
able to populate a new column with data from existing columns. This
will require providing a subquery as initial data, and my hope is that
the new Queryset Refactor features will make this sort of thing much
easier.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Shabda:&lt;/strong&gt; I asked this to Malcolm as well, but he was unwilling to make a
prediction. So let me ask this slightly differently. What problems would you
like Django to tackle after 1.0? What big features would you be most
interested in having in Django, after it hits 1.0?&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Russell:&lt;/strong&gt; My efforts in prognostication have a nasty habit of going badly
wrong... but here goes:
One of the recent shifts in in the Django project as a whole has been
the move to allow user extension as much as possible. The ability to
have user-defined field types, database backends, and management
commands are all examples of the push to move Django development into
the community as much as possible. I would be very happy to see the
majority of Django v2.0 features be a merge of established
community-based projects into the trunk, rather than projects tightly
integrated with Django internals.
That said, some changes can't be done as extensions. One such
reoccurring feature request is for multi-database support. It isn't
something I have a huge need for myself, but it is a reoccurring
request on the Django users mailing list, so it would be good to be
able to support it.
Support for aggregation functions (sum, average, etc) in the ORM is a
feature I have a use for, and I'd like to see - especially since the
lack of aggregation functions is the reason I got involved with Django
in the first place. I'm currently mentoring a GSOC project to
implement this capability, but I expect that this won't be complete
until post v1.0.
I would also expect that the resources around the community will get
some attention. There is plenty of room for new tutorials. There are
also a few contrib services that need much better documentation (in
some cases, &lt;em&gt;any&lt;/em&gt; documentation). Given that v1.0 is a point of API
stability, it also makes a good time to add lots of new tutorials and
other documentation. Formalization and documentation of some of
Django's more notable internals (like the _meta model class and the
various extension mechanisms) would also be nice to have.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Shabda:&lt;/strong&gt;  You have worked in many different areas of Django. What suggestion would
you give to somebody who is just looking to start contributing to Django?
Are there some areas, where the learning curve is flatter, and people can
make meaningful contribution more easily?&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Russell:&lt;/strong&gt; My suggestion would be "don't be timid - jump in". Even the most
complex parts of Django - like the query system - are relatively
straightforward once you've spent a bit of time walking through them.
If someone is looking to contribute to Django, my suggestion would be
to do the same thing I did when I was starting out - pick a Django
component with a bunch of bugs, pick one, write a test case for the
bug (if there isn't one already), then walk through the code until you
can fix it. Rinse and repeat, but stay in the same component.
Eventually, you'll know that component as well as anyone in the world,
and you'll be able to work on more complex bugs or contribute a
feature. Occasionally, tracking down one bug will lead you into
another component; use that as an opportunity to learn how another
part of Django works.
The other thing to keep in mind is that working on Django means more
than just code - if you want your contributions to be taken seriously,
you need to get in the habit of writing rigorous tests and
comprehensive documentation. Don't just fix the bug and then complain
that we don't commit your tickets - you need to do the whole job.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Shabda:&lt;/strong&gt; A lot of Django people come from diverse backgrounds, You have studied
Physics, Adrian studied journalism, &lt;a href="http://pointy-stick.com/blog/"&gt;Malcolm&lt;/a&gt; mathematics and &lt;a href="http://b-list.com/"&gt;James&lt;/a&gt;
philosophy. Is there something about with Django which attracts people from
diverse backgrounds (keep simple things simple ...)? Has a lack of people
with CS degree been a problem sometime, as in "We wish there was a CS guy to
discuss this problem with"?&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Russell:&lt;/strong&gt; My undergraduate degree is in Physics, but my honours and PhD program
were both in pure CS. Plus, for all their lack of CS degrees, Adrian,
Malcolm and James have certainly proven they know how to cut a line of
code, and there are plenty of people in the Django community with pure
CS backgrounds that contribute ideas and code. I don't think Django is
suffering from a lack of CS experience.
However, I do think that having a multidisciplinary background does
predispose you to a certain way of looking at the world. It has been
my experience that some people with a narrow IT/CS focus lose sight of
the fact that at the end of the day, a computer is a tool, most people
don't like them very much, and only put up with them to the extent
that they help to make their lives better. I can appreciate the
elegance of a neat algorithm as much as the next CS major, but at the
back of my mind I always have the question "How can I use this to
solve a real world problem?"
One of the reasons that I suspect Django has been a success is that it
has never lost sight of the fact that it exists to solve problems.
Internally, it does a lot of smart things, but outwardly it tries to
be as simple as possible. You download the code, and it works - you
don't need to resolve dozens of dependencies. The development server
just works. There is a simple and easily understood pipeline from
request to rendering. Django identifies that building web applications
is a problem that people need to solve, and tries to provide the
simplest possible path to let that happen.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Shabda:&lt;/strong&gt; You have worked with a defense startup, and defense industry is presumed
to be very conservative. What can Django do to market itself to market
itself to people outside web 2.0 niches, such as in large corporations or
defense related software?&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Russell:&lt;/strong&gt; There is a running joke in the Australian military that the Army's
idea of the perfect technology advancement would be a self-sharpening
grease pencil. It's not quite that bad, but the military is very
conservative. This is understandable, because lives are potentially on
the line if a technology fails. However, it does breed some
interesting limitations on new technology: in the circles I was
working, IE6 on Windows 2000 was considered to be a very modern web
platform.
The way to market to people outside of Web 2.0 niches is to stop
trying to sell Web 2.0 as if it was an answer to anything. Web 2.0 is
a technology. Web 2.0 may give you a competitive advantage. However,
your customer doesn't give a pair of fetid dingo's kidneys about your
competitive advantage. The way to sell your Web 2.0 idea is to forget
all about how cool the technology is, or how great it is that you can
do this as a RESTful web service. Instead, focus on how your solution
solves a specific problem of your customer in a way that your customer
is comfortable with.
A person in industry has a problem. They need a solution. They don't
particularly care if the solution is implemented using an alien slave
hiding in a cardboard box connected to the server using electric
spaghetti - as long as the solution is cheap, reliable, solves their
problem, and doesn't require them to fundamentally change the way they
do business. If you can convince your customer that your product meets
these criteria, you'll have a long and profitable career in the
military-industrial complex - regardless of whether you use Web 2.0 or
not.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Shabda:&lt;/strong&gt; What is one thing about
Django which you absolutely love, and one thing which you think Django
should do differently?&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Russell:&lt;/strong&gt; On a technical level: I think the decision to keep logic out of
templates is 100% correct. Keeping logic out of templates forces the
separation between content and presentation, and simplifies the
interface for the design team, who often will not be gung-ho
programmers. I think this is one of the best decisions that Django has
made - I know there are many in the world that claim that Django's
templates are it's biggest weakness, but I simply don't agree. I take
some solace from the fact that Google has tacitly agreed with this
position by providing Django's templating engine inside their
&lt;a href="http://code.google.com/appengine/"&gt;App Engine&lt;/a&gt;.
One area that I think Django could do better is in error handling -
especially in the way that exceptions get caught and rethrown. There
are a number of ways that import errors or dangling named URL
references can be misreported in stack traces or 500 pages; given that
both of these are relatively common errors, it would be nice to
provide better handling.
On a community level: I love the general disposition of the Django
community. It's polite and professional, and appreciates the value of
good design.
If I had to pick a flaw, it's probably the way that the core
developers (myself included) sometimes let the community down in the
way we communicate overall project direction. When plans are made
(however informally), they aren't always communicated effectively to
the community. It also isn't always clear (beyond the simple fact that
we're busy) why specific tickets with bug fixes don't get committed to
trunk in a timely fashion.
Even I get bitten by this sometimes - being based in Perth, Western
Australia, the cost of travel prevents me from attending PyCon or the
Sprints in person. As a result, I don't get to participate in the
in-person discussions - I sometimes have to read between the lines of
blog posts and mailing list messages to work out what the plans are,
sometimes confirming details using our secret core developer BatPhone.
This is certainly an area where we could do better. Constructive
suggestions are always welcome.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Shabda:&lt;/strong&gt; Frameworks like Turbogears and Zope take a "best of breed" approach, and
tie together a lot of existing components to build the full framework. In
comparison, Django takes an integrated approach, and most of Django's
components are Django specific. For this reason, many people have accused
Django of having a &lt;acronym title="not invented here"&gt;NIH&lt;/acronym&gt;.
&lt;a href="http://www.b-list.org/weblog/2006/oct/21/django-and-nih/"&gt;syndrome&lt;/a&gt;.
What are the pros and cons of both these approaches? Why did Django rebuild
most of its components?&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Russell:&lt;/strong&gt; Saying that Django rebuilt most of its components is one way of
looking at it. The other way to look at it is to say that Django
identified a core set of functions that need to be tightly integrated,
and need to meet some specific design goals, and built tools that met
those requirements. In some cases, it's not even fair to say that
components were rebuilt. Remember, Django went public in mid 2005, but
existed as an in-house project at the &lt;a href="http://www2.ljworld.com/"&gt;Journal-World&lt;/a&gt; for some time
before that. For some of these components, Django's implementation
predates the 'existing component'.
Those that throw the NIH argument at Django are also ignoring two
important points. Firstly, Django already uses a number of prebuilt
components from elsewhere - the signal dispatcher, the JSON
serializer, and any number of other components are taken from existing
projects. We also have dependencies on external software - most
notably in database backends, but also in serialization and markup
engines.
Secondly, there is the presumption that plumbing together external
projects requires no effort. This is patently false - you only have to
look at the places that Django does rely on external projects to see
why. The MySQLdb 1.2.2 prerelease bindings had all sorts of problems
that require special handling; similar workarounds are required for
unicode handling in recent versions of Markdown. Each version of these
external components can potentially require different handling,
sometimes in subtly incompatible ways. Once you introduce multiple
interacting components, you introduce the problem of incompatibility
between versions of those tools. Integration like this isn't easy.
The Django approach guarantees that everything works out of the box,
and there is only one core configuration to document and test. It
reduces the barrier to entry: making the first act of a new user a
decision about which slightly different template engine will best meet
their needs isn't the best way to make a good impression. It also
focuses the efforts of the community in testing, documentation,
tutorials and advice. If improvements are required, the entire
community is in a position to provide an opinion, not just the subset
of the community that works with that component option. In a
Balkanized world, there will always be a tendency for the question
"How do I do X using tool Y" to be answered "don't use tool Y, use Q
instead".
Building the components from scratch also guarantees that all the
components fit - and I don't just mean that they satisfy their mutual
interfaces. There is also the issue that the core components should
all 'taste' the same - that they follow similar design philosophies,
apply similar assumptions, and so on. This sort of consistency is an
invaluable resource, as it forms a kind of implicit documentation:
once you have learned one part of the system, you automatically know
how other parts of the system work. You don't need to relearn the
rules for each component.
One notable (and frequently made) argument against this approach is
that you lose flexibility. While this is theoretically true, I don't
think it matters much in practice. For all the supposed inadequacies
of the Django template engine, I challenge anyone to present a problem
that can only be solved by using a different templating engine. On top
of that - there's absolutely nothing preventing you from using your
own template engine, or your own database backend, or any other
component if you don't like Django's offerings. If you don't believe
me, go look at Google App Engine.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Shabda:&lt;/strong&gt; What are the focus areas Django testing framework? What utilities does
this add too unittest or doctests? How does this fit in with browser based
tools like &lt;a href="http://selenium.openqa.org/"&gt;Selenium&lt;/a&gt;?&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Russell:&lt;/strong&gt; Like most things in Django, the test framework aims to be as simple as
possible, but no simpler. It provides an environment in which tests
can be run, it provides the facilities for finding and invoking test
cases, and provides a few helpful web-specific assertions that can be
used during testing. Base Python unittests and doctests get a dummy
database to work with, plus a dummy mail server; the Django TestCase
extends unittest.TestCase to provide fixture loading and a dummy web
client that can be used to programatically poke views.
So far, the Django testing tools have concentrated on testing Django
views as if they were ordinary Python methods - after all, that's what
they are. Selenium takes things another step, allowing for tests of
how a web browser will behave when given the output of a view. I tend
to think that testing the view itself is a more rigorous test, as it
allows for direct inspection of view output. However, Selenium does
have a place, especially when dealing with Javascript or other dynamic
on-page interactions. Adding support for Selenium to Django is on the
to-do list - it just requires someone to do the work.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Shabda:&lt;/strong&gt; Thanks for the interview Russell.&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;This was the interview of Russell Keith-Magee, a longtime Django core contributor based in Perth, Australia. Next we interview Michael Trier, a longtime Django user and evangelist.
Michael's &lt;em&gt;This Week in Django&lt;/em&gt; has been a great resource for the Django community, and we discuss Django, and how best to market Django. So stay tuned.&lt;/p&gt;
&lt;p&gt;Oh and yes, &lt;a href="http://42topics.com/"&gt;42topics.com&lt;/a&gt; is live now! (&lt;a href="http://42topics.com/blog/what-is-42topics/"&gt;How are we different&lt;/a&gt;?) &lt;a href="http://www.42topics.com/django/"&gt;And we have a Django section&lt;/a&gt;. So &lt;a href="http://42topics.com/register/"&gt;regsiter&lt;/a&gt; let's get rolling!&lt;/p&gt;</description><guid>http://agiliq.com/blog/2008/05/an-interview-with-russell-keith-magee-django-core-/</guid></item><item><title>Interview with James Bennett - Django release manager</title><link>http://agiliq.com/blog/2008/04/interview-with-james-bennett-django-release-manage/</link><description>&lt;p&gt;&lt;img src="http://uswaretech.com/blog/wp-content/uploads/2008/04/james_photo-20080210.jpg" alt="" title="james_photo-20080210" width="250" height="188" class="frame right" /&gt;
&lt;a href="http://www.b-list.org/about/"&gt;James Bennett&lt;/a&gt; is the release manager of Django, and a long time contributor. He works on &lt;a href="http://www.ellingtoncms.com/"&gt;Ellington&lt;/a&gt;, a &lt;acronym title="content management system"&gt;CMS&lt;/acronym&gt; designed for news organizations. His book, &lt;a href="http://www.amazon.com/Practical-Django-Projects-Pratical/dp/1590599969"&gt;Practical Django Projects&lt;/a&gt;, is being published by Apress, and is scheduled to hit bookshelves in June 2008. He graciously agreed to be interviewed at the 42topics.com blog. His blog, The B-List, can be found &lt;a href="http://www.b-list.org/"&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Shabda&lt;/strong&gt;: Would you tell something about yourself, how did you get started with Django, and what other OSS projects are you involved with?&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;James&lt;/strong&gt;: I got into Django fairly soon after the initial public release; I'd been doing PHP and Perl work (mostly &lt;a href="http://textpattern.com/"&gt;Textpattern&lt;/a&gt; on the PHP side, &lt;a href="http://scoop.kuro5hin.org/"&gt;Scoop&lt;/a&gt; on the Perl side), and I was working on teaching myself Ruby and Rails because it looked interesting. But I'd always liked Python; it was just that there weren't a whole lot of good options for Python web development at that point. You could do &lt;a href="http://www.zope.org/"&gt;Zope&lt;/a&gt;, or you could do &lt;a href="http://twistedmatrix.com/trac/"&gt;Twisted&lt;/a&gt;, but they both had pretty steep learning curves when compared to the type of work I was doing, so it just wasn't worth it.
Django changed that; I think I did the &lt;a href="http://www.djangoproject.com/documentation/tutorial01/"&gt;tutorial&lt;/a&gt; the day it was released, and I just fell in love.
These days most of my open-source time is devoted to Django, and to various &lt;a href="http://code.google.com/u/ubernostrum/"&gt;Django-based apps&lt;/a&gt; I've written and released. Back in the day I used to do the occasional bit of PHP hacking, and I wrote some plugins for blogging engines, but none of that stuff's maintained anymore.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Shabda&lt;/strong&gt;: What are your responsibilities as the release manager of Django? Who are the other core contributors of Django, and what are their current areas of focus?&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;James&lt;/strong&gt;: My responsibility is largely bureaucracy. Within the project, I keep an eye on the various branches and their progress, try to stay on top of active/problem areas in the ticket tracker, and maintain a list of things that have to happen before 1.0.
Outside the project itself, I also stay in touch with people who are distributing Django -- Linux distros which package it, etc. -- and watch their Django-related bug reports. When there's a security fix, I also send out an advance notice to them that we're going to roll a release, and do the initial disclosure so they have some lead time to respond to that.
Outside of that, I also contribute to the documentation, as well as the occasional code patch, and I maintain the 0.91-bugfixes branch, which provides legacy support and security updates for some of the really ancient Django installs out there (our policy is to support the current release and two prior releases with security updates, which means 0.91, 0.95 and 0.96 right now).
The rest of the core team is just people everybody knows if they watch the developers' list or the Trac timeline: &lt;a href="http://www.holovaty.com/"&gt;Adrian&lt;/a&gt; and &lt;a href="http://www.jacobian.org/"&gt;Jacob&lt;/a&gt; are the lead guys, obviously. Then there's &lt;a href="http://www.pointy-stick.com/blog/"&gt;Malcolm&lt;/a&gt;, who you interviewed the other day, and who's carved out a pretty big niche for himself: he did the bulk of the Unicode work and he's doing queryset-refactor, he does a lot of maintenance on the i18n system, and he somehow still finds time to have a day job. I don't know how he does that.
Then there's &lt;a href="http://djangopeople.net/freakboy3742/"&gt;Russell Keith-Magee&lt;/a&gt;, (russelm in Trac), who's contributed all sorts of useful stuff. He's the go-to guy for testing and serialization, and just an all-around brilliant guy who fixes things left and right.
&lt;a href="http://gdub.wordpress.com/"&gt;Gary Wilson&lt;/a&gt; and &lt;a href="http://www.linkedin.com/in/jkocherhans"&gt;Joseph Kocherhans&lt;/a&gt; are also both big names you'll recognize from commit messages; Joseph used to work at the next desk over at World Online, but now he's up in Chicago with Adrian, working on &lt;a href="http://www.everyblock.com/"&gt;EveryBlock&lt;/a&gt;. He's done a lot of the grunt work on newforms and on laying groundwork for newforms-admin.
Ian Kelly and Matt Boersma keep our &lt;a href="http://www.djangoproject.com/documentation/databases/#oracle-notes"&gt;Oracle support&lt;/a&gt; working, and do an amazing job of helping to track down and solve obscure problems with that.
And rounding out the core commit bits are Simon Willison and Luke Plant, who aren't as active these days but can still be seen popping up every so often.
Out on the branches, we've had a lot of work done on newforms-admin lately by Brian Rosner, who's been stepping up and helping to really get that sorted out, and there's been a lot of unsung UI work by Christian Metts, who's a designer at World Online but also a not-bad JavaScript programmer and can flaunt some Python when he feels like it.
And then there's the "gis" branch, &lt;a href="http://code.djangoproject.com/wiki/GeoDjango"&gt;GeoDjango&lt;/a&gt;, which is adding support for GIS -- spatial querying -- to the Django &lt;acronym title="Object-relational mapping"&gt;ORM&lt;/acronym&gt;.
Justin Bronn and Jeremy Dunck really kick-started that, Justin gave a nice demo of some of their work at PyCon this year.
And recently we've also been giving commit access to some of the translators, so they don't have to go through as much bureaucracy to submit updated translation files; that's sped some things up on the i18n front, because we're blessed with a large number of people who are willing to pitch in and do that work.
Oh, and I can't forget Wilson Miner; he doesn't flaunt it that often, but he's the guy who originally designed the Django admin, and he's been known to make the occasional tweak to fix CSS stuff.
(hope I didn't forget anybody there)&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Shabda&lt;/strong&gt;: Would GeoDjango be sometime merged with the trunk, or is it forever going to be a parallel branch to trunk?&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;James&lt;/strong&gt;: The goal is that the &lt;acronym title=" geographic information systems"&gt;GIS&lt;/acronym&gt; branch will merge, sometime after queryset-refactor lands, and it's going to provide an application -- django.contrib.gis -- that you can use to enable spatial queries for your models. There's a pretty good writeup on the wiki page of how that works, and they've been tracking queryset-refactor because it helps make some of the custom query construction easier.
I don't know for certain if it'll hit trunk before Django 1.0, but it will not be a branch forever; they've put in a ton of work on that, and I'm looking forward to getting to use it :)&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Shabda&lt;/strong&gt;: Once Django hits 1.0, would 0.91 be end of lifed, but support for .96 and .95 continue?&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;James&lt;/strong&gt;: Like I said, the policy is we provide security fixes for the current release plus the previous two, so 0.91 would sort of fall off there after Django 1.0. But there are a lot of legacy installs out there that are perfectly happy for now, and I wouldn't be surprised to see people unofficially continuing to submit patches and keep that maintained for as long as there are people who want to use 0.91.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Shabda&lt;/strong&gt;: A little about you. You have majored in philosophy. I can think of one other, &lt;a href="http://www.paulgraham.com/articles.html"&gt;Paul Graham&lt;/a&gt;. Would you say, what you learnt from philosophy help with programming?&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;James&lt;/strong&gt;: Well, I wouldn't say there's anything specific necessarily. But I think there's a big place for people with liberal-arts backgrounds to come to programming, and I think philosophy's a good path to do that.
If you look at a typical philosophy program, you're doing a lot of logic, a lot of critical analysis, a lot of abstract reasoning.
You have to get comfortable sooner or later with all sorts of formalisms that don't necessarily have any practical meaning, and that's very similar in a lot of ways to programming :)
And when you get right down to it, as programmers, about 90% of what we're paid to do is think: our job is to take a problem, analyze it, break it down into pieces and solve them.
And that's not terribly different from what you spend four years doing in a philosophy program.
I've actually joked about that a bit with some of my former professors, that I still get to argue as much as when I was doing philosophy, but the programming pays a lot better.
I do think, though, that there's a big need for that sort of thing; we don't really teach critical thinking anymore, and while it's a vital skill to have no matter what you do for a living, it's absolutely crucial to programming. So if you can get a good liberal-arts background where you've been taught how to look at things and pick them apart and analyze them, you can definitely do well as a programmer. Though it'd also be a good idea to take at least a few elective math courses...&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Shabda&lt;/strong&gt;: You have been working on Ellington, how is Ellington &lt;acronym title="content management system"&gt;CMS&lt;/acronym&gt; different from, say, a customized version of Drupal?&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;James&lt;/strong&gt;: Well, they have some things in common: both are modular &lt;acronym title="content management system"&gt;CMS&lt;/acronym&gt;-style products, both are meant to be extensible.
But Ellington is really targeted from the ground up at news operations. There's all sorts of specialized stuff in there that's really optimized for the way a newsroom works, most of it culled from our experience as a newspaper, and of working with other papers.
So where with Drupal you'd really have to do a lot of customization because nobody's really done this kind of "news all the way through" version of Drupal, with Ellington it's there out of the box, and you hit the ground running.
I think we also have a very unique position because we are a news company, we've got a bunch of newspapers, some periodicals, TV news, etc.
And we work with those folks every day, we see how they do stuff, we hear about it when they run into problems, and so we're in a good spot to see just what a newsroom staff really needs out of their online platform.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Shabda&lt;/strong&gt;: Wordpress is PHP's killer app, arguably Basecamp is &lt;acronym title="Ruby on Rails"&gt;ROR&lt;/acronym&gt;'s. What would you say Django's killer app is?&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;James&lt;/strong&gt;: Honestly I don't know right now; I think the thing that Django wins on is that there doesn't have to be the One Big App that everybody uses, instead there's this huge blooming ecosystem of applications.
In a way, it's like asking what the "killer library" of the Python stdlib is; the killer feature is that you've got all that stuff available.
Though there are definitely some cool Django apps out there right now, and a lot more on the way. I think there's a different mentality, though, because in general Python people seem to keep their heads down and just get stuff done. So it may be you don't hear about some project until maybe they decide to do an open-space talk at PyCon or OSCON, and then you just get blown away.
There was a guy at PyCon who came up and showed me an app he's been developing, and I won't spoil it and give away what it is, but it made my jaw drop.
He'd taken something that's a really common software niche that's been dominated by these abominable products because it's not really a sexy thing to be doing, and just absolutely nailed it. Guy's probably gonna make millions.
But I don't know if there is a general-purpose "killer app" for Django right now, and I'm not really sure I want there to be one; people can see that sort of thing and think "oh, that's all it does". They look at, say, Ellington, and think "oh, this is only good for a newspaper-style &lt;acronym title="content management system"&gt;CMS&lt;/acronym&gt;", or they see Rails and Basecamp and think "oh, this is no good for me, I'm not doing a Web 2.0 thing". So in a way I'm kind of glad we don't have a "killer app" hanging over us and pigeonholing Django.
Though I should definitely give a shout out to &lt;a href="http://code.google.com/p/reviewboard/"&gt;Review Board&lt;/a&gt;; of the public Django apps I've seen, it's probably the coolest, and again takes something that's not usually sexy in terms of software and really nails it.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Shabda&lt;/strong&gt;: As you said, "Python people seem to keep their heads down and just get stuff done", do you think Django needs to a better job marketing itself. For example, I have pitched Django to a fair number of people, and I always have to start with with "Django what?", as compared to say &lt;acronym title="Ruby on Rails"&gt;ROR&lt;/acronym&gt;, or PHP which seems to have a good brand recall.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;James&lt;/strong&gt;: Well, to some extent Django hasn't done a whole lot of explicit marketing because we're not at 1.0 yet, and I expect that after 1.0 it'll both be a lot easier to do marketing and that there will be more of it going on.
But at the same time, Django's doing pretty well as it is; Google's doing their &lt;a href="http://code.google.com/appengine/"&gt;App Engine&lt;/a&gt; stuff with Django bundled, there are startups using it to build the next big thing, and it's even been quietly sneaking its way into some huge corporations.
Plus it seems like every time I turn around there's another book coming out.
I saw one yesterday at the bookstore downtown; I hadn't heard about it until that moment, but I think that makes five or six books that'll be out by the end of this year.
So I think that'll help. &lt;a href="http://www.digital-web.com/articles/intro_to_django_helping_perfectionists_with_deadlines/"&gt;Digital Web magazine&lt;/a&gt; did a feature article on Django just recently, and I did an &lt;a href="http://www.sitepoint.com/article/build-to-do-list-30-minutes"&gt;article for Sitepoint&lt;/a&gt; a while back as well.
I like to view this as the phase where we build up momentum until eventually Django is an unstoppable juggernaut and everybody's listening to gypsy jazz music ;).&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Shabda&lt;/strong&gt;: Everyone is pretty excited about your &lt;a href="http://www.amazon.com/Practical-Django-Projects-Pratical/dp/1590599969"&gt;coming book&lt;/a&gt;. When can we have it in book stores? Would you give a brief overviews of what's in it?&lt;/p&gt;
&lt;p&gt;&lt;img src="http://uswaretech.com/blog/wp-content/uploads/2008/04/practical_django_proj.jpg" alt="" title="practical_django_proj" width="240" height="240" class="right" /&gt;
&lt;strong&gt;James&lt;/strong&gt;: The book will, I think (and hope) be shipping around the end of June.
It's very much a hands-on introduction to Django: walking through building three applications, picking up progressively more advanced bits of Django as you go, and seeing some best practices in action.
So you start out with just simple stuff, using the contrib apps and learning the basics of getting Django running. Then you do some simple customizations of admin templates, then start building some models and views, then on into building full-on applications.
There's not room to cover every single thing you can do with Django, but I think it handles a pretty good spectrum of techniques from basics up to some advanced things that let you poke around and really get a feel for how stuff works.
And of course, you get periodic bouts of me up on my soapbox yelling at people about how to write reusable applications, because that's &lt;a href="http://www.b-list.org/weblog/2007/mar/27/reusable-django-apps/"&gt;what I do&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Shabda&lt;/strong&gt;: You talk a little about App Engine in &lt;a href="http://www.b-list.org/weblog/2008/apr/08/batteries-sold-separately/"&gt;Batteries sold separately&lt;/a&gt;. What effect do you see of App Engine on python hosting ecosystem, on Python web applications, and on Django?&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;James&lt;/strong&gt;: I honestly don't know what to expect from App Engine. It's a very different kind of thing from what anybody outside Google is used to, and it'll probably be a while before it's really shaken out and we get an idea of the impact it'll have. I fully expect that Google's going to start supporting other languages, so there won't be this effect where you'll always have to use Python to use App Engine. And the way they've sandboxed it is going to make it feel weird to Python people, I think. And that's on top of getting used to the fact that you're not using an RDBMS; I've been watching the blog flamewars about that, and that seems to be the big takeaway.
If I had to make a prediction now, I'd say that App Engine will bring some people to Python, but probably not in hordes, and that its big long-term effect is going to be to point out to a lot of folks that they're not really using the "&lt;acronym title="relational"&gt;R&lt;/acronym&gt;" in "&lt;acronym title="Relational database management system"&gt;RDBMS&lt;/acronym&gt;", and so maybe it's OK to think about their applications in a different way. And that's not Python-specific at all.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Shabda&lt;/strong&gt;: What were the focus areas of the &lt;a href="http://code.djangoproject.com/wiki/NewformsAdminBranch"&gt;newforms-admin&lt;/a&gt; branch. How far have they been achieved. About when would the newforms-admin branch be merged? How backwards incompatible is this going to be?&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;James&lt;/strong&gt;: Well, there are a couple goals running parallel.
The first thing, obviously, is that with the &lt;a href="http://www.djangoproject.com/documentation/forms/"&gt;oldforms&lt;/a&gt; package deprecated we've got to get stuff migrated to &lt;a href="http://www.djangoproject.com/documentation/newforms/"&gt;newforms&lt;/a&gt;, and the admin's got to make that jump.
And because the admin does a lot of tricky and complex stuff with forms, it's also been a fertile proving ground for designing some advanced newforms features that'll find their way back into trunk and make it easier to do that tricky stuff on your own.
Another big thing is cleaning out the coupling issue where you declare a class inside a model to activate the admin interface; there's no reason for that to happen, so instead there's a class you'll subclass and override stuff on to customize the behavior, and then you'll register a model to have the admin interface you've set up that way.
Finally, there's been a lot of stuff abstracted in newforms-admin; while I don't think it's really an official design goal, there's been a lot of opportunity to provide hooks where people can go in and customize stuff. I looked at the code a couple months ago, and it was about 95% of the way to being able to run completely without django.contrib.auth, for example, because there are enough hooks where you can override something and replace defaults to make it use something else.
And that's a huge deal, because it means you could do stuff like run the admin on HTTP auth, or run it in a corporate environment against an &lt;acronym title="Lightweight Directory Access Protocol"&gt;LDAP&lt;/acronym&gt; database, and you barely have to touch anything; you can already do an auth backend that handles most of the work, then you tweak a few things for the admin and you're good to go with no hacking directly on Django code.
Plus, a lot of people will be happy to see that the methods you can go in and override all get the HttpRequest object as an argument, so even though it's bad workflow a lot of the time you'll be able to have the admin do stuff like automatically fill in a foreign key with the current user.
And along the way there've been huge numbers of bug fixes; there's a lot of stuff that's always just been really fragile in the admin, like edit_inline, and newforms-admin is a good opportunity to just yank out all the things that made them troublesome and do it right.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Shabda&lt;/strong&gt;: Time for a meme. What is the one think you absolutely love about Django, and one thing which Django should have done differently?&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;James&lt;/strong&gt;: I love &lt;a href="http://code.djangoproject.com/browser/django/trunk/django/contrib/localflavor"&gt;contrib.localflavor&lt;/a&gt;, and I want people to go look at it and adore it and use it. There's so much useful stuff in there, you can validate checksums on Scandinavian social-security numbers, you can get lists of all the state in Brazil, it's just this great gigantic resource for localizing your apps, and it kicks so much ass.
Something to do differently... I'd probably rewrite the tutorial to not do the apps-inside-projects thing. That trips a lot of people up because they come away thinking they have to do it that way, and so they really miss out on the benefits of being able to write an app once and just use it over and over and over.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Shabda&lt;/strong&gt;: Before we leave, would you like to give a quick tip, or hard to find information about Django to our readers?&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;James&lt;/strong&gt;: The best tip I can give is not to be afraid to look at &lt;a href="http://code.djangoproject.com/browser/django/trunk/django/"&gt;code&lt;/a&gt;. We do our best to document all the useful stuff, but that's a pretty huge area to cover, so there are always going to be neat little things hidden away that you either won't see unless you read the code, or won't see until some date in the far future when somebody gets time to document it.
Plus, if you find something cool you can write up a little tutorial and post it, and then people will start reading your blog. That's pretty much what happened to me, where my blog was for a long time just me writing up these little articles to remind myself of stuff I'd learned.
And especially if you're learning Python as you go, reading a significant piece of code like Django can really help to improve your understanding of the language. There's really nothing better than that for assimilating the way a language works, and I think Django's around the right size -- it's small enough you can carry a solid understanding of it around in your head, but it's big enough that there's lots of stuff, and lots of different kinds of stuff, that you can look at and learn from.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Shabda&lt;/strong&gt;: Thanks a ton for this interview, and for sharing these useful information.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;James&lt;/strong&gt;: Sure.&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;This was James Bennett's interview. I plan to be interviewing a few more leaders from Django community, so if you would like me to ask any question, write them in the comments.&lt;/p&gt;</description><guid>http://agiliq.com/blog/2008/04/interview-with-james-bennett-django-release-manage/</guid></item><item><title>An interview with Malcolm Tredinnick - Django core contributor</title><link>http://agiliq.com/blog/2008/04/an-interview-with-malcolm-tredinnick-django-core-c/</link><description>&lt;p&gt;&lt;img class="right frame" src="http://uswaretech.com/blog/wp-content/uploads/2008/04/malcolm_headshot.png" /&gt;&lt;a href="http://www.pointy-stick.com/"&gt;Malcolm Tredinnick&lt;/a&gt; is a core contributor to Django, and was the driving force behind the &lt;a href="http://code.djangoproject.com/wiki/QuerysetRefactorBranch"&gt;Queryset-refactor&lt;/a&gt; branch of Django, which adds important capabilities such as model inheritance. He has a long association with OSS, and contributed significantly to GNOME and Django. He graciously agreed to be interviewed at 42topics blog. Malcolm's blog, Defying Classification, can be read &lt;a href="http://www.pointy-stick.com/blog/"&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Shabda&lt;/strong&gt;: Would you tell a few things about yourself, how did you get involved with OSS and Gnome, and with Django?&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Malcolm&lt;/strong&gt;: Here are some recollections I've written about: &lt;a href="http://www.pointy-stick.com/blog/2006/07/03/time-already/"&gt;1&lt;/a&gt; and &lt;a href="http://www.pointy-stick.com/blog/2007/08/18/10-years-gnome/"&gt;2&lt;/a&gt;
Short version; started using Linux in university as a poor undergrad; kept using it since then (started back in 1993).
Started using GNOME in 1999 (after trying a very early version of Qt and what became KDE), started contributing to GNOME about 12 months later (mid-2000).
Started using Django in October 2005, I guess (a few months after it was open sourced) and haven't stopped. Started contributing patches more or less immediately and was given commit privileges about March of 2006, from memory.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Shabda&lt;/strong&gt;: So what is one thing in Django which you absolutely love, and one thing which you think Django should have done differently?&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Malcolm&lt;/strong&gt;: I guess Django's separation of responsibilities is something that has always been attractive to me. It's very easy to keep the cross-application business logic and the persistent storage logic and the state control and the visual presentation separate.
I guess the piece that probably routinely annoys me the most is a slight inconsistency in the template tags: we often mix up how to use a literal string in template tags (sometimes it's in quotes, sometimes not), which makes it very hard to later make that tag also take a template variable.
As somebody who handles bug reports a lot, something like that ends up taking up a lot of time in my life, which could probably be better spent elsewhere. Still, it's almost impossible to change now, so that's the way life goes.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Shabda&lt;/strong&gt;: &lt;a href="http://code.djangoproject.com/wiki/QuerysetRefactorBranch"&gt;Queryset-refactor&lt;/a&gt; is almost done, what would were the major overarching goals for this branch?&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Malcolm&lt;/strong&gt;: A number of things...
1. Clean things up internally, so that future extensions are easier. A lot of the existing (trunk) query construction grew from something much smaller. It all mostly worked, but it was getting pretty hard to manage. Some bugs were almost impossible to fix in the trunk form too, which was the real motivation.
2. Organise things so that I could add model inheritance, which was the main thing that started me looking deeply at all that. This has been accomplished.
3. Make it easier to add backends like Oracle and MS SQL Server that don't support, say, limit and offset in SQL. That meant providing a more object-based query construction so that they can tweak things before creating the SQL string.
In the process, we've made it a lot easier for people to extend this for backends and to add functionality to existing backends.
For example, adding new lookup types is now possible (not particularly easy, but possible). And the &lt;a href="http://code.djangoproject.com/wiki/GeoDjango"&gt;geo-django&lt;/a&gt; branch can do their stuff without having to patch the query construction code any longer.
(Justin Bronn, the geo-django maintainer has been tracking qs-rf very closely, so we know that geo-django works nicely with qs-rf).
I guess they're the main points. The first one -- a better/different internal organisation -- was the main one and was really the bulk of the work. Getting everything to mostly work was relatively easy. Getting it all to work perfectly took a lot longer. :-)&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Shabda&lt;/strong&gt;: So would this make, say, writing a backend for non relational DBs like Bigtable easier. &lt;a href="http://blog.michaeltrier.com/"&gt;Michael Trier&lt;/a&gt; was working on a &lt;a href="http://gitorious.org/projects/django-sqlalchemy/"&gt;Sqlachemy based ORM&lt;/a&gt; for Django, how would this be affected by qs-rf merge?&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Malcolm&lt;/strong&gt;: Well, that's really two questions. So, one at a time...
Whether it would make a non-relation backend easier,... yes. The QuerySet class passes all the work of talking to the backend, whatever it is, off to a class called Query. Writing a different sort of backend would require writing a new Query class that knew how to take the function calls QuerySet makes and turn them into the right return types.
Mostly, QuerySet does not poke at the internals of Query: it uses "public" methods only. This is deliberate. It means that writing something like a Query class for a different sort of backend (RDF store, or LDAP or whatever) might very well be possible.
As for something like SQLAlchemy, I gather it's made things easier. I know Michael and Brian have been writing their code against the qs-rf code and it seems to be working.
However, I haven't looked at their code, so I'm not sure if they're using the QuerySet/Query split very much or not. I gather they're doing it slightly differently from how I might have done based on somethings they mentioned when I was talking to them yesterday -- apparently a recent qs-rf commit "broke" their approach to something and that was a little surprising to me. But it wasn't a showstopper apparently, so I'm not too worried.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Shabda&lt;/strong&gt;: As you said, a commit sort of "broke" their approach. How backwards comaptible is qs-rf. Is it mostly backwards compatible, but some corner cases will break, or would any thing which worked previously, but does not now should be reported as a bug?&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Malcolm&lt;/strong&gt;: It's almost 100% backwards compatible. The thing I "broke" (and I'm using quotes, because it wasn't really a breakage, just a change) was a very internal thing. Obviously if you're writing something like a new storage backend, you need to dive into the internal API of the ORM a bit and that's what the django-sqlalchemy stuff is doing...
For normal user code, there should be very few changes required. There's a list on the wiki page for &lt;a href="http://code.djangoproject.com/wiki/QuerysetRefactorBranch"&gt;the branch&lt;/a&gt; but they are mostly things that won't affect normal code.
Only if you are doing something very "tricky" or slightly unsupported will changes be required.
Of course, some people will see slightly different results in complex querysets because we have fixed a lot of bugs (over 60 that were reported to Trac plus some that never got that far) and some of those fixes change the results that were returned.
So some people may be relying on currently incorrect behavior, but I doubt that's going to be too troublesome.
Also, I've tried to make the error reporting a lot clearer so that when somebody does try to do something undefined, it should hopefully give an error message (e.g. introducing an infinite ordering loop in models)&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Shabda&lt;/strong&gt;: Speaking of Bigtable, Google's &lt;a href="http://code.google.com/appengine/"&gt;App Engine&lt;/a&gt; seemed to be sort of a letdown from the initial hype. What are your opinions about the effect of App Engine on Django?&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Malcolm&lt;/strong&gt;: Well, I think the letdown came from people letting their expectations get ahead of their brains a bit. Google didn't really seem to over-hype it or misrepresent it.
Obviously when Google releases something, everybody gets excited. But you have to at least take the time to look at what was released.
For a particular class of applications, I think App Engine is probably ideal. It gives cheap hosting, great reliability and access to some Google's storage stuff.
For example, if you have something that presents a read-only view onto a large bunch of data, App Engine would be very appropriate. Okay, you have to do data extraction from multiple models manually, since there's no joining, but that's not too hard to work around and people will write little helper functions for those cases.
Remember that a lot of very successful, very popular websites are basically read-only: a lot of newspaper sites, things like &lt;a href="http://www.everyblock.com/"&gt;EveryBlock&lt;/a&gt; (and, formerly, Chicago Crime) -- all those sorts of sites. Even news.google.com.
There's a great deal of information that wants to be "presented" to people. Not everything requires form entry and comments and the like and even those are possible on App Engine if you need them.
So I'm kind of glad the initial reaction phase has settled down a bit and people are starting to think about what is possible, rather than focusing on what isn't possible. Some interesting things will come out of App Engine, I suspect. We just don't know what they are yet because people are still writing them.
As far as how it affects Django, that's probably both good and bad.
If people view App Engine as being representative of everything Django, it's not going to be too handy. However, I doubt that will be the prevailing opinion. People realise that Google have used portions of Django to implement portions of the App Engine experience. And those pieces of Django are quite handy. The URL dispatching, the general data flow, the templates -- all will be nice for people to use.
It's also getting a few people interested in the internals of Django as they try to work out whether they can move the extra bits that are 'missing' from App Engine into the fold.
In addition, we've also already received some direct positive benefits: some of the Google team, particularly Guido van Rossum, have been filing a few bugs against Django as they did the initial App Engine development. So there are a few bug fixes in things like newforms and the templating component that are a direct result of App Engine development inside Google.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Shabda&lt;/strong&gt;: There is &lt;a href="http://code.google.com/p/google-app-engine-django/"&gt;app-engine-django&lt;/a&gt;, which is trying to bridge the impedance mismatch between Django ORM, and App Engine ORM. Is there any effort to bridge this from Django side by making Django ORM play nice with Appengine. If such a request comes in what would Django's response be?&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Malcolm&lt;/strong&gt;: &lt;em&gt;shrug&lt;/em&gt;. I have no idea.
I think this is an ideal opportunity for some people to write stuff like django-appengine and work out what might be needed and come up with a concrete list of things that might be needed. Predicting the future is hard enough to be mostly futile and it's not really worth speculating.
Right now, the core Django developers are fully focused on getting Django 1.0 released. That's where our time is going. How other people spend their time is up to them and it's definitely not for me to judge whether it's worthwhile or not.
People need to experiment. It's the way new software products are developed. So anybody who's interested and working on this should be encouraged. That's how open source development has always worked and I think it works quite well.
I guess I could hazard a guess that any intrusive changes just to support some App Engine style thing probably aren't interesting prior to Django 1.0, since they're not necessary to get that out of the door. But that's as much of a prediction as I'm willing to make and anybody who actually attaches any value to that prediction is probably being foolish. I'm wrong more often than I'm right. :)&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Shabda&lt;/strong&gt;: Well this gets asked a lot on the mailing lists, qs-rf is almost done, Newforms admin should be done soon, so when can we expect Django 1.0, and what new goodies will this bring?&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Malcolm&lt;/strong&gt;: &lt;em&gt;heh&lt;/em&gt;
Well, the real answer is "as soon as possible".
Notice that this is a big step up from "when it's ready", which is the normal answer here. Hopefully people appreciate that the maintainers want to get 1.0 out the door as much as anybody else. It's just that release 1.0 when it's not at a point we're happy with won't be useful in the future.
More concretely, we have a few major things to do between now and 1.0 and they're all getting pretty close.
Then there's a period of stabilizing and random bug squashing and triage to make sure we haven't missed anything big.
The idea (and driving goal) is that whatever we release as 1.0 should remain backwards-compatible on an API level until, say, 2.0. So we need to get all the big infrastructure changes in before 1.0.
That isn't the same as saying 1.0 will be bug free or any pipe dream like that, because it won't be. But fixing bugs is an ongoing job and as long as we can feel comfortable that we can fix existing bugs without having to make major breakages, we can feel happy about 1.0.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Shabda&lt;/strong&gt;: This has happened to me a few times, I am trying to pitch Django to a client, and then I mention Django has not hit 1.0 and we would be developing their site against a subversion checkout, and boom, I am against a brick wall. I am guessing this happens to a lot of people. Any suggestions on overcoming client's reluctance on this point.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Malcolm&lt;/strong&gt;: Well, this is the hard problem, of course. There are at least three issues here.
Firstly, it's well known that in a lot of corporate situations, they only want to go with "released" versions, whatever that means. The fact that released versions are often a disaster (e.g. Microsoft Vista) seems to be forgotten, but that's the way things go. However, it shouldn't be the ultimate driving force in this equation. It's one consideration only and having the software released faster just to meet some immovable, often-times unsupportable policy isn't the answer.
The second aspect is to realise that there are a lot of successful sites built on Django 0.96 and even Django 0.91. So it's not impossible to stick with the last release.
Now, of course ,that tends to show up the problem with the first point, since 0.96 has some bugs that have subsequently been fixed, so sticking to a release handicaps you there.
However, if we did more frequent releases, that adds a lot of burden to the release process. For example, distributions (Debian, Suse, Fedora, etc), now have a bigger problem in choosing the right version to ship since they also want some stability. Security releases either become harder (we have to patch more versions) or else we have to "end of life" earlier releases more frequently, which harms those people using those releases (again, it reduces stability for the userbase).
The third point is somewhat related to that: in order to make sure that a release can be relied upon, we sometimes need to make sure that we do all the necessary preliminary work so that we don't immediately break any code that relies on this new release.
That is exactly the situation we're in now. We release 0.96 as a sort of "stability point" for people to rely on. Almost immediately, we then started to introduce a bunch of necessary changes to things that will require code to be ported when people upgrade. When this round of churning has finished, we'll make the next release. That happens to be 1.0 in this case.
If we released, say 0.97 at some point in the past few months, people would have a similar but slightly different sort of marketing problem: now they have 0.96 code that has to be ported if they want to move to 0.97. But it's also just "more work" on some level, since they'll have to do even more porting when 1.0 comes out. So we aren't helping developers by providing them with a lot of stability.
It's fairly well understood by most experienced developers that this is a tough path to walk. With open source software it's even harder, since everybody is a volunteer and we have a largely unknown userbase to satisfy.
Sometimes that difference is forgotten by people who argue that "no company ever works like this". A corporation can set release deadlines and in exchange for everybody having to work to those deadlines, those people get paid. It's called a salary. Open Source software doesn't work like that.
I'm sure that once Django reaches 1.0 or perhaps a little later, we'll slip into time-based releases so that things go a bit more smoothly. At the moment that simply isn't practical because of all the changes we need to make.
Every project goes through that phase. Before Linux had time-based releases, they had to get an amount of features in and a certain stability level reached. Ditto for GNOME (which only started doing time-based releases at 2.0 and there was a long gap between 1.4 and 2.0 precisely because we needed to be able to guarantee that at 2.0). Ditto for KDE and Ubuntu and ...
So, yeah ,it's slightly tough times for everybody at the moment. Partly Django is a victim of its own success here: everybody wants to use it and we're trying to keep up.
Hopefully people realise that ultimately that's a good thing. It's an investment in the future in the sense that we'll still be here in a year, two years, five years... because of this great use.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Shabda&lt;/strong&gt;: What are the future plans for Django. Django has most of the things which I want in a framework, (&lt;a href="http://xkcd.com/413/"&gt;import soul&lt;/a&gt;), and we would hate to have Django suffer from &lt;a href="http://headrush.typepad.com/creating_passionate_users/2005/06/featuritis_vs_t.html"&gt;featuritis&lt;/a&gt;. After 1.0 what are the areas Django wants to tackle?&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Malcolm&lt;/strong&gt;: Again, this is asking for a predication and I don't do those.
Partly because I don't know and am not really in a position to say, in any case. (I'm just a contributor). Partly because having too many goals too far ahead of time is possibly going to restrict people.
Django runs on its contributors. A lot of the ideas that are implemented are initially suggested and often developed in quite some detail by people other than the core developers. It might not always seem that way, because you sometimes have to see the common thread in a bunch of requests before you notice the lurking feature requirement ,but it's true.
So what happens post 1.0 is going to depend a lot on how people use Django, on what people offer in the way of code and, particularly, what good ideas are suggested.
Who could have predicted Google AppEngine when Django 0.96 was released? What other things like that will appear as a result of Django 1.0? Who knows?
Of course, there are some things that we could probably say will be worked on (successfully or not is another question entirely). Multi-database support seems to be popular and one day somebody might do it; maybe there'll be more front-end developments -- e.g. somebody like you who keeps wanting more Ajax support will actually develop something that provides this support everybody seems to want but hasn't ever specified. :-)
We can sort of see a few things coming up again and again, so I guess they'll be worked on. But it's really going to be up to the people who write the code, who come up with the ideas, who write the websites that use Django, who try to teach Django to others. And right now, I have no idea what direction that will go in.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Shabda&lt;/strong&gt;: Before we close, would you like to share a handy tip which you use a lot, but does not get used so much otherwise?&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Malcolm&lt;/strong&gt;: People possibly overlook both the &lt;code&gt;{% debug %}&lt;/code&gt; template tag (best to use it as &lt;code&gt;&amp;lt;pre&amp;gt;{% debug %}&amp;lt;/pre&amp;gt;&lt;/code&gt; in a template) and the debug context processor &lt;a href="http://www.djangoproject.com/documentation/settings/#template-context-processors"&gt;django.core.context_processors.media&lt;/a&gt;.
Both of those are very useful for trying to see what's going on when you're passing information between a view function and a template.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Shabda&lt;/strong&gt;: Thanks Malcolm. It was great talking to you.&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;I plan to interview Leaders from Django community, in coming few weeks, so if you would like me to ask any specific questions, put them in comments, and I will ask them when I interview.&lt;/p&gt;</description><guid>http://agiliq.com/blog/2008/04/an-interview-with-malcolm-tredinnick-django-core-c/</guid></item><item><title>Five Things I Hate About Django.</title><link>http://agiliq.com/blog/2008/04/five-things-i-hate-about-django/</link><description>&lt;p&gt;The &lt;a href="http://www.jacobian.org/writing/2007/mar/04/hate-python/"&gt;five&lt;/a&gt; &lt;a href="http://ivory.idyll.org/blog/mar-07/five-things-I-hate-about-python"&gt;things&lt;/a&gt; &lt;a href="http://use.perl.org/~brian_d_foy/journal/32556?from=rss"&gt;I hate&lt;/a&gt; &lt;a href="http://adam.gomaa.us/blog/five-things-i-hate-about-django/"&gt;about *&lt;/a&gt; meme seems have died down, and memes, should not be allowed to die.&lt;/p&gt;
&lt;p&gt;Of course I love Django, and have bet very heavily on it. But we do not know a topic, until we know it warts, so here you go. The listing is in no particular order, so sorry no numbering.&lt;/p&gt;
&lt;h3&gt;Ajax with Django is hard:&lt;/h3&gt;
&lt;p&gt;Most of the Django Community has decided that bundling Javascript helpers with a python framework is bad idea. Though I can understand the reasoning, (argued &lt;a href="http://www.b-list.org/weblog/2006/jul/02/django-and-ajax/"&gt;here&lt;/a&gt; and &lt;a href="http://feh.holsman.net/articles/2006/07/04/what-should-your-framework-do-for-you"&gt;rebuttal&lt;/a&gt;), that Javascript is so basic that you can not be expected to not know it, I can not agree with it. SQL is as basic as Javascript, and yet we have ORM for abstracting away the common and the tedious.&lt;/p&gt;
&lt;p&gt;Of Course, with &lt;a href="http://djangoapi.matee.net/django.utils.simplejson-module.html"&gt;simplejson&lt;/a&gt;, and a &lt;a href="http://jquery.com"&gt;good Javascript library&lt;/a&gt;, you can build Ajax apps fast and with only a minimal amout of fuss. And yet switching between Python and Javascript, twice every hour is a huge time drain. Eg. I put commas after the last element in Python arrays, with JS this would work in FF, but fail with weird errors in IE.&lt;/p&gt;
&lt;h3&gt;Lack of &lt;a href="http://martinfowler.com/eaaCatalog/identityMap.html"&gt;identity map&lt;/a&gt;:&lt;/h3&gt;
&lt;p&gt;If you get the same row from the DB twice using Model.objects.get, you will get two different objects. Apart from the performance problems of two DB queries, when only one should have done, when you update one of them, the other does not get updated, and you will have &lt;em&gt;interesting&lt;/em&gt; things happening in your application. And if you update both of them, you might write two inconsistent changes to the DB.&lt;/p&gt;
&lt;p&gt;Look at this code for example.&lt;/p&gt;
&lt;pre lang="python"&gt;
See this code
In [2]: from django.contrib.auth.models import User
In [3]: usr1 = User.objects.create_user('ram', 'demo@demo.com', 'demo')
In [4]: usr2 = User.objects.get(username='ram')
In [5]: usr3 = User.objects.get(username='ram')
In [6]: user2 == user3
---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
...
In [7]: usr2 == usr3
Out[7]: True
In [8]: usr3.username = 'not_ram'
In [9]: usr3.save()
In [10]: usr2.username
Out[10]: u'ram'
In [11]: us3.username
---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
...
In [12]: usr3.username
Out[12]: 'not_ram'
In [13]: usr2 == usr3
Out[13]: True
&lt;/pre&gt;

&lt;h3&gt;Whether Sessions are browser length/persistent are set sitewide:&lt;/h3&gt;
&lt;p&gt;You can set whether you want sessions to be browser length/persistent using &lt;code&gt;SESSION_EXPIRE_AT_BROWSER_CLOSE&lt;/code&gt; in &lt;code&gt;settings.py&lt;/code&gt;. But you can not set them per user, &lt;a href="http://code.djangoproject.com/wiki/CookBookDualSessionMiddleware"&gt;without mucking with django internal&lt;/a&gt;. This might seem a minor annoyance, yet this is something which you need to do for every app, as the remember me, function will not work without this.&lt;/p&gt;
&lt;h3&gt;Newforms is very limited:&lt;/h3&gt;
&lt;p&gt;Let us say you want the Form to contain a varible number of fields. How can you define the &lt;code&gt;NewForms&lt;/code&gt; class to do your biddings.&lt;/p&gt;
&lt;pre lang="python"&gt;
from django import newforms as forms
class MyForm(forms.Form):
    foo = froms.CharField()
    bar = froms.CharField()
&lt;/pre&gt;

&lt;p&gt;This can only create a form with a fixed number of fields. While there are ways to generate forms with variable number of fields, (generate the Form class programatically), they are not easy or well documented. (Remind me to write such tutorial sometime.)&lt;/p&gt;
&lt;p&gt;Bonus question: How can you generate a form with same form elements multiple (and variable number) times, ala what happens with &lt;code&gt;edit_inline&lt;/code&gt;?&lt;/p&gt;
&lt;h3&gt;Settings mixes application configuration which should be public and passwords, which should be private:&lt;/h3&gt;
&lt;p&gt;If I am distributing an app &lt;code&gt;MIDDLEWARE_CLASSES&lt;/code&gt; is something which I would assume users would not (generally) modify. Similarly, in most of the cases, &lt;code&gt;INSTALLED_APPS&lt;/code&gt;, would also be something which users would not change, (unless you are distributing standalone_apps). This means, I want to source control &lt;code&gt;settings.py&lt;/code&gt;. But &lt;code&gt;settings.py&lt;/code&gt; also contain my DB setiings, and &lt;code&gt;SECRET_KEY&lt;/code&gt;, which means, I cannot source control &lt;code&gt;settings.py&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;And while we are at it, can we refactor &lt;code&gt;settings.py&lt;/code&gt;, so it works without&lt;/p&gt;
&lt;pre lang="python"&gt;
os.environ['DJANGO_SETTINGS_MODULE'] = 'settings'
&lt;/pre&gt;

&lt;h3&gt;Bonus:&lt;/h3&gt;
&lt;p&gt;Two things which used to bug me but no more.
1. You cannot extend Models - Well now you can if you use queryset-refactor, or &lt;a href="http://groups.google.com/group/django-users/browse_thread/thread/6a275999abab2e66"&gt;soon&lt;/a&gt; can if you are on trunc.
2. Url configuration using regexes. - &lt;a href="http://regex.info/blog/2006-09-15/247"&gt;Now they have two problems.&lt;/a&gt; joke notwithstanding, mapping URLs to views is one problem where regexes fit the problem beautifully. With less that 50 lines of code, you can manage a large number of views, and Url patterns.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://42topics.com/blog/feed/"&gt;Now stay tuned for Five things I love about Django&lt;/a&gt;&lt;/p&gt;</description><guid>http://agiliq.com/blog/2008/04/five-things-i-hate-about-django/</guid></item><item><title>New tutorial - Building a search engine with Appengine and Yahoo</title><link>http://agiliq.com/blog/2008/04/new-tutorial-building-a-search-engine-with-appengi/</link><description>&lt;p&gt;I wrote a &lt;a href="http://www.42topics.com/dumps/appengine-search/doc.html"&gt;new tutorial&lt;/a&gt; on building a search engine using Appengine, and Yahoo Search API &lt;a href="http://www.42topics.com/dumps/appengine-search/doc.html"&gt;here&lt;/a&gt;. This uses pure Appengine API, and not Django, and is a tutorial on how to use Appengine without Django.&lt;/p&gt;</description><guid>http://agiliq.com/blog/2008/04/new-tutorial-building-a-search-engine-with-appengi/</guid></item><item><title>Two Django+Appengine Tutorials</title><link>http://agiliq.com/blog/2008/04/two-djangoappengine-tutorials/</link><description>&lt;p&gt;I have posted two Tutorials for Using Django with Appengine.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="http://www.42topics.com/dumps/django/docs.html"&gt;For people who do not know Django&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.42topics.com/dumps/appengine/doc.html"&gt;For people who already know Django&lt;/a&gt;  see &lt;a href="http://blogango.appspot.com/"&gt;what we build in this tutorial&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;And here a few good links about the topic.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="http://www.b-list.org/weblog/2008/apr/08/batteries-sold-separately/"&gt;James Bennet&lt;/a&gt; tells exactly why Appengine and Django are not so good together.&lt;/li&gt;
&lt;li&gt;&lt;a href="http://blog.ianbicking.org/2008/04/09/app-engine-commodity-vs-proprietary/"&gt;Ian Bicking&lt;/a&gt; has an interesting take on how Appengine can change the economics of Python hosting.&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.joyeur.com/2008/04/08/let-my-people-have-root"&gt;The guys at Joyent&lt;/a&gt; reading my mind on why I or you can not deploy any production site on Appengine. (Hint. you mean I can never move away, without writing half my code?)&lt;/li&gt;
&lt;/ul&gt;</description><guid>http://agiliq.com/blog/2008/04/two-djangoappengine-tutorials/</guid></item><item><title>Using Appengine with Django, why it is pretty much unusable</title><link>http://agiliq.com/blog/2008/04/using-appengine-with-django-why-it-is-pretty-much-/</link><description>&lt;p&gt;We are hard at work building &lt;a href="http://www.42topics.com/"&gt;42topics.com&lt;/a&gt;, and are looking at the best places to deploy this. So when I heard about Appengine, with out of box Django support(gasp!) I was delighted. After using it for a day, &lt;a href="http://www.42topics.com/dumps/appengine/doc.html"&gt;and posting a tutorial&lt;/a&gt;, I am so disappointed.&lt;/p&gt;
&lt;h3&gt;Peeves in no particular order.&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Appengine is a very constrained environment, so out goes any chance to run background jobs.&lt;/li&gt;
&lt;li&gt;The ORM-API is very similar to Django, but yet the Django API is much better. &lt;code&gt;modelobj.filter('attr =', value1).filter('attr2 =', value2)&lt;/code&gt; or &lt;code&gt;modelobj.filter(attr = value1, attr2 = value2)&lt;/code&gt;. Putting entity level operations on &lt;code&gt;modelobj.manager&lt;/code&gt; is much cleaner that making them classmethods, as argued &lt;a href="http://www.b-list.org/weblog/2008/feb/25/managers/"&gt;here&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Very half baked documentation. Releasing without sufficient testing on windows. If you follow the &lt;em&gt;Getting started&lt;/em&gt; guide, and are on windows, I hope you like &lt;a href="http://groups.google.com/group/google-appengine/search?q=unbalanced+parenthesis&amp;amp;"&gt;debugging regexes&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;NO JOINS? Ok so I can use obj.master to simlute this. Umm can I get GROUP BY? What about UNION? Admittedly Bigtable is not relational, but are you telling me Google built all their search without a way to simulate GROUP BY.&lt;/li&gt;
&lt;li&gt;PDB does not work on dev server. With Django's dev server, I put breakpoints with PDB all the time, and it works perfectly. With Appengine devserver, pdb will give you BDBQuit exceptions. I hope you enjoy debugging by reading logfiles.&lt;/li&gt;
&lt;li&gt;Modules used by &lt;a href="http://www.google.com/search?q=django+%22from+imp+import%22+site%3Acode.djangoproject.com&amp;amp;sourceid=navclient-ff&amp;amp;ie=UTF-8&amp;amp;rlz=1B3GGGL_enIN217IN217"&gt;django&lt;/a&gt; are &lt;a href="http://code.google.com/appengine/docs/python/purepython.html"&gt;empty&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;You can not start a dbshell on the dev server. (And django-admin framework does not work). When I am coding, I write the data insertion views first, and then the other views. Whether the Insert views are working or not can be checked immediately, from the db shell, or from admin. Here until I write the other views, I can not check on my create view.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The other flaws I can live with, but a dbshell not working and pdb breakpoints raising exceptions make this unusable for me. I guess I will stick with Django on a normal web host, and look at EC2, when we really need to scale.&lt;/p&gt;</description><guid>http://agiliq.com/blog/2008/04/using-appengine-with-django-why-it-is-pretty-much-/</guid></item><item><title>Google Appengine - First Impressions</title><link>http://agiliq.com/blog/2008/04/google-appengine-first-impressions/</link><description>&lt;p&gt;Google launched their EC2 competitor, Appengine yesterday, and all hell broke loose. And in about 24 hours, &lt;a href="http://groups.google.com/group/google-appengine/browse_thread/thread/c5bf4ab38d93910d"&gt;the 10,000 accounts were used up&lt;/a&gt;. Currently it is tied to only working with python, and Django 0.96.1 works out of the box.
&amp;lt;!- - more - -&amp;gt;&lt;/p&gt;
&lt;h3&gt;The Good&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Python powered. Django works out of the box.&lt;/li&gt;
&lt;li&gt;No sysadmining chores.&lt;/li&gt;
&lt;li&gt;Promise of infinite scalability with no configuration. (Ah!)&lt;/li&gt;
&lt;li&gt;Free for now.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;The Bad&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Python powered, if you want to use ruby/java/php, sorry you are out of luck.&lt;/li&gt;
&lt;li&gt;Your code is tied to Google. You might be able to reuse most of your code, but the DB/ORM sepcific code, ah you are out of luck. And if you are building database backed websites, well most of your most complex code talk to ORM.&lt;/li&gt;
&lt;li&gt;Too magical. &lt;em&gt;Explicit is better than implicit&lt;/em&gt;. On the dev server I do not know where my data is stored. If I change the data model, the changed models are available immediately. But well, how do you do it?&lt;/li&gt;
&lt;li&gt;Free for now, and no way to pay for when your usage out grows the free quota limits.&lt;/li&gt;
&lt;/ul&gt;</description><guid>http://agiliq.com/blog/2008/04/google-appengine-first-impressions/</guid></item></channel></rss>