<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">

 <title>Dave Dash</title>
 <link href="http://davedash.com/tag/django/atom.xml" rel="self"/>
 <link href="http://davedash.com/tag/django"/>
 <updated>2012-04-07T22:42:44-07:00</updated>
 <id>http://davedash.com/</id>
 <author>
   <name>Dave Dash</name>
   <email>dd+atom1@davedash.com</email>
 </author>

 
 <entry>
   <title>Plus Addressing</title>
   <link href="http://davedash.com/2012/04/07/plus-addressing/"/>
   <updated>2012-04-07T00:00:00-07:00</updated>
   <id>http://davedash.com/2012/04/07/plus-addressing</id>
   <content type="html">&lt;p&gt;One of my biggest pet peeves is registration forms that don't accept &quot;plus&quot;
addresses, e.g. &lt;code&gt;myname+whatever@mysite.com&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;I've been using plus addressing for years, and before that,
&lt;a href=&quot;/2008/10/12/google-apps-in-search-of-a-worthy-email-system/&quot;&gt;&quot;minus&quot; addressing&lt;/a&gt;.  Since GMail handles my &lt;code&gt;@davedash.com&lt;/code&gt; email
addresses I am forced to use the &quot;plus&quot; style if I want to easily create
multiple addresses on a whim.&lt;/p&gt;

&lt;p&gt;I use this style of addressing to keep track of who might be spamming me
(JC Penny for example).  I might sign up with &lt;code&gt;myname+facebook@mysite.com&lt;/code&gt; for
Facebook, &lt;code&gt;myname+pinterest@mysite.com&lt;/code&gt; for Pinterest, etc.  Unfortunately this
wasn't working when I signed up for Pinterest.  My wife and a few of my friends
were quick to tell me about this:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/static/images/2012/04/07/pin-screenshot.jpg&quot; alt=&quot;pinterest registration screenshot&quot; /&gt;&lt;/p&gt;

&lt;p&gt;So when I joined Pinterest, I immediately filed a bug, and then after talking
to a few people, decided to fix it.  The fix was remarkably simple.&lt;/p&gt;

&lt;p&gt;There's usually two causes for this problem.  1. People use the wrong
validation for their emails.  Namely one that says &lt;code&gt;+&lt;/code&gt; is bad.  Luckily most
web frameworks, like Django, get this right.  2. They use the email address as
some sort of parameter in a URL.  For example:
&lt;code&gt;http://mysite.com/newsletter/unsubscribe?email=myname+whatever@mysite.com&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;The wrong validation&lt;/h2&gt;

&lt;p&gt;If you're using the wrong validation, fix it.  There's no excuse for anybody
seeing &quot;sorry please use a valid&quot; email address when their email is perfectly
valid.  Django has a &lt;a href=&quot;https://github.com/django/django/blob/master/django/core/validators.py#L88&quot;&gt;regular expression which you can use&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;The URL issue&lt;/h2&gt;

&lt;p&gt;The URL issue is an issue of URL encoding.  In our example
(&lt;code&gt;http://mysite.com/newsletter/unsubscribe?email=myname+whatever@mysite.com&lt;/code&gt;):&lt;/p&gt;

&lt;p&gt;The email variable gets decoded as:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;myname whatever@mysite.com
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Clearly that &lt;em&gt;is&lt;/em&gt; invalid.  On a URL bar, the &lt;code&gt;+&lt;/code&gt; is interpreted as a space.
The solution is to encode your email address.  For Pinterest, this is all we
needed to do.  JavaScript has a handy &lt;code&gt;encodeURIComponent&lt;/code&gt; to change this.  If
you are using an &lt;code&gt;ajax&lt;/code&gt; call from jQuery, you can simply pass the data an
object:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;{'email': 'myname whatever@mysite.com'}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This will get encoded properly.&lt;/p&gt;

&lt;h2&gt;Call to Action&lt;/h2&gt;

&lt;p&gt;Plus addressing a minimal use case, but please... make sure that people aren't
hitting validation errors in your registration.  Each input on a registration
form is a reason to not register.  Each validation error, is a reason to give
up prematurely.  Do your users and your product a favor and don't invalidate
them unnecessarily.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/static/images/2012/04/07/pin-screenshot-fix.jpg&quot; alt=&quot;pinterest registration screenshot post-fix&quot; /&gt;&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Naming things and a recursion</title>
   <link href="http://davedash.com/2012/01/05/naming-things-and-a-recursion/"/>
   <updated>2012-01-05T00:00:00-08:00</updated>
   <id>http://davedash.com/2012/01/05/naming-things-and-a-recursion</id>
   <content type="html">&lt;p&gt;Most Mozilla webdev projects have an awful project structure, and it's
partially my fault.  I'm &lt;a href=&quot;https://github.com/mozilla/playdoh/pull/67&quot;&gt;attemtping to fix that&lt;/a&gt;, but I
cringe every time someone creates a new &lt;a href=&quot;http://playdoh.rtfd.org/&quot;&gt;playdoh&lt;/a&gt;
(Mozilla's Django template)
based project.&lt;/p&gt;

&lt;h3&gt;The typical python project&lt;/h3&gt;

&lt;p&gt;Your typical python project looks like this:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;/my_project
    someotherstuff/
    docs/
    theactualthingicareabout/
    setup.py
    LICENSE
&lt;/code&gt;&lt;/pre&gt;

&lt;h3&gt;MOZtrosity&lt;/h3&gt;

&lt;p&gt;We didn't have a good guide when we first started writing Django projects, so
we opted for something like this:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;theactualthingicareabout/
    apps/
        foo/
        bar/
    __init__.py
    urls.py
    settings.py
    LICENSE
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;In otherwords, the Django Project, which is a python module, is immediately
checked out.  If you check this out to an invalid directory, e.g. you do something like:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;git clone github.com/davedash/myawesomeproject.git will.not.work\!
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Bad things will happen.&lt;/p&gt;

&lt;h3&gt;So?&lt;/h3&gt;

&lt;p&gt;To some people this seems like an easy thing to work-a-round, but when it takes
three of my excellent coworkers a week to diagnose an issue, where this ended
up being the root cause...  well it becomes a higher priority issue.&lt;/p&gt;

&lt;p&gt;So here's what happened this week, when we tried to deploy
&lt;a href=&quot;https://github.com/mozilla/lumbergh/&quot;&gt;the new careers site&lt;/a&gt; to a VM hardware.&lt;/p&gt;

&lt;p&gt;Our ops team sensibly checked out the project like so:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;git clone https://github.com/mozilla/lumbergh.git careers
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;They did everything right.  Sure, they were creative and chose &lt;code&gt;careers&lt;/code&gt; over
the default &lt;code&gt;lumbergh&lt;/code&gt;, but they knew the shortcomings of our system and picked
a name that would resolve as a valid python package.&lt;/p&gt;

&lt;p&gt;Unfortunately we'd hit some &lt;em&gt;recursion error&lt;/em&gt; anytime we tried to hit a URL.
So we knew there was an issue with the URL resolver, but we couldn't figure it
out.&lt;/p&gt;

&lt;p&gt;Here's what the project layout looked like:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;careers/ # I could be called anything, but they chose careers
    __init__.py
    apps/
        careers/  # I'm going to cause problems,
                  # but neither devs nor ops will suspect a thing! mwahaha
            __init__.py
            models.py
            urls.py
            views.py
    settings.py
    urls.py
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;other files.&lt;/p&gt;

&lt;p&gt;We configure our &lt;code&gt;apps/&lt;/code&gt; directory to be part of our &lt;code&gt;PYTHON_PATH&lt;/code&gt; so we can
do things like &lt;code&gt;from careers import views&lt;/code&gt;... you can probably see where this
is going.&lt;/p&gt;

&lt;p&gt;Here's the main &lt;code&gt;urls.py&lt;/code&gt; &lt;a href=&quot;https://github.com/mozilla/lumbergh/blob/master/urls.py&quot;&gt;1&lt;/a&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;...
urlpatterns = patterns('',
    (r'', include('careers.urls')),
)
...
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The main &lt;code&gt;urls.py&lt;/code&gt; includes &lt;code&gt;careers.urls&lt;/code&gt; which if you look at the above
project layout, resolves to two different python packages:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;careers/urls.py&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;careers/apps/careers/urls.py&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;Python chose the first, and therefore &lt;code&gt;urls.py&lt;/code&gt; kept calling upon itself.&lt;/p&gt;

&lt;h3&gt;So what did we learn?&lt;/h3&gt;

&lt;p&gt;Do better.&lt;/p&gt;

&lt;p&gt;First of all, we need a better project layout. This will continue to cause
problems for even the brightest developers.&lt;/p&gt;

&lt;p&gt;Secondly, if you don't do this at least name apps carefully.
Django's app model can be a bit much for
non third party apps.  Sometimes there's one app which spans the entire
project, and it's tempting to call it the same name as the project
(e.g. &lt;code&gt;careers&lt;/code&gt;), but sometimes a lamer more generic name like &lt;code&gt;common&lt;/code&gt; is
better.&lt;/p&gt;

&lt;p&gt;But really, the second point is moot if we just clean up.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Choosing a New Web Stack</title>
   <link href="http://davedash.com/2011/10/09/choosing-a-new-web-stack/"/>
   <updated>2011-10-09T00:00:00-07:00</updated>
   <id>http://davedash.com/2011/10/09/choosing-a-new-web-stack</id>
   <content type="html">&lt;p&gt;I like building web sites, a lot.  Usually every few years I need to re-
evaluate the stack I use for a side-project.  Joshua's
&lt;a href=&quot;http://stackparts.com/&quot;&gt;Stack Parts&lt;/a&gt; site is handy for this.&lt;/p&gt;

&lt;p&gt;At Mozilla Webdev we stick to reeds + mysql + elasticsearch + celery + rabbitmq
+ memcache + git + virtualenv + python + django + jinja2 + modwsgi + commander
+ puppet + apache + less + jquery as our go-to stack.  It's tried and true and
it's been working and been evolving for two years.&lt;/p&gt;

&lt;p&gt;So I'm at re-evaluation time.  The first element of the stack I needed to
decide upon was the web framework.  I initially thought I'd use Django, and
maybe alternate a few supporting libraries just to color my experience.  But
Flask caught my attention.&lt;/p&gt;

&lt;p&gt;Flask is from Pocoo who have given me great things like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;lodgeit&lt;/li&gt;
&lt;li&gt;Werkzeug&lt;/li&gt;
&lt;li&gt;Jinja2&lt;/li&gt;
&lt;li&gt;Sphinx&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;It was a microframework, which meant that it didn't contain as many things as
Django, but at the same time, I didn't use that much of Django.&lt;/p&gt;

&lt;p&gt;Flask was a nice way to stay mostly in my comfort-zone, and in some ways, focus
me on just writing an app, and not working in a framework.  Since it's python,
if I start to miss Django, I can probably rewrite my code without too much
effort.&lt;/p&gt;

&lt;p&gt;Overall I'm excited, and I just got past, &quot;Hello World.&quot;&lt;/p&gt;

&lt;p&gt;I'm not sure what my stack will look like, I'm imagining it will evolve into:&lt;/p&gt;

&lt;p&gt;postgresql + memcache + git + flask + jinja2 + gunicorn + fabric + puppet +
nginx + less + backbonejs + jquery&lt;/p&gt;

&lt;p&gt;This will give me a chance to learn more about things I'm interested in, and
utilize what I think might be better options along the stack.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>DjangoCon Testing Tutorial</title>
   <link href="http://davedash.com/2011/08/10/djangocon-testing-tutorial/"/>
   <updated>2011-08-10T00:00:00-07:00</updated>
   <id>http://davedash.com/2011/08/10/djangocon-testing-tutorial</id>
   <content type="html">&lt;div class=&quot;side&quot;&gt;
   &lt;img src=&quot;/static/images/2011/08/10/djangocon.png&quot;
        width=&quot;287&quot; height=&quot;184&quot;
        alt=&quot;DjangoCon 2011&quot; /&gt;
&lt;/div&gt;


&lt;p&gt;If you want to learn all you can about testing anything in your Django App, see
&lt;a href=&quot;http://djangocon.us/schedule/presentations/30/&quot;&gt;my tutorial&lt;/a&gt; at &lt;a href=&quot;http://djangocon.us/&quot;&gt;DjangoCon&lt;/a&gt;.
It's on September 5th, it'll be 3 hours
long and so far with seven sign ups it will be very hands-on.&lt;/p&gt;

&lt;p&gt;Here's what I think I will cover, but I may change this depending on what the
audience wants:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Testing issues

&lt;ul&gt;
&lt;li&gt;ask people to fill out etherpad with issues they've run into&lt;/li&gt;
&lt;li&gt;ask someone to rank them in order of complexity&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;List an outline of topics

&lt;ul&gt;
&lt;li&gt;post them on etherpad&lt;/li&gt;
&lt;li&gt;have people + them if they are interested&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Testing overview

&lt;ul&gt;
&lt;li&gt;We started in late 2009 early 2010&lt;/li&gt;
&lt;li&gt;Our largest project has 2500 tests&lt;/li&gt;
&lt;li&gt;Our next largest has 1100&lt;/li&gt;
&lt;li&gt;We have pretty good coverage&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;How testing works    in Django

&lt;ul&gt;
&lt;li&gt;I'm not 100% sure on this&lt;/li&gt;
&lt;li&gt;Test runner setups up a new database&lt;/li&gt;
&lt;li&gt;Test runner finds and runs tests&lt;/li&gt;
&lt;li&gt;Tests run class setup&lt;/li&gt;
&lt;li&gt;Test runs each test in a test case

&lt;ul&gt;
&lt;li&gt;Load fixtures&lt;/li&gt;
&lt;li&gt;Tests run setup&lt;/li&gt;
&lt;li&gt;Tests runs the test&lt;/li&gt;
&lt;li&gt;Tests runs teardown&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Tests run class Teardown&lt;/li&gt;
&lt;li&gt;You get an F if you're bad and a . if your not.&lt;/li&gt;
&lt;li&gt;Now that you know it, you can hack it.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;How we've hacked testing

&lt;ul&gt;
&lt;li&gt;2500 tests is a lot&lt;/li&gt;
&lt;li&gt;We no longer recreate the database when you run the test suite&lt;/li&gt;
&lt;li&gt;In each test case we just load the fixtures once.&lt;/li&gt;
&lt;li&gt;We rearrange the tests so things with the same fixture set run together&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Testing tools that we use at Mozilla

&lt;ul&gt;
&lt;li&gt;nose/django_nose&lt;/li&gt;
&lt;li&gt;nose plugins

&lt;ul&gt;
&lt;li&gt;nicedots&lt;/li&gt;
&lt;li&gt;progressive&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;coverage

&lt;ul&gt;
&lt;li&gt;git + whatchangedpy&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Testing everything, no excuses

&lt;ul&gt;
&lt;li&gt;100% Coverage isn't important&lt;/li&gt;
&lt;li&gt;80% is nice&lt;/li&gt;
&lt;li&gt;Good coverage on tricky things is important&lt;/li&gt;
&lt;li&gt;Some coverage on everything is important&lt;/li&gt;
&lt;li&gt;External&lt;/li&gt;
&lt;li&gt;If you start depending on APIs, Search or different tools you need to be able to test for them.&lt;/li&gt;
&lt;li&gt;Writing these test cases will take less time than this tutorial&lt;/li&gt;
&lt;li&gt;It will save you so much headache in the future.&lt;/li&gt;
&lt;li&gt;The same headaches you save yourself by writing &quot;normal&quot; tests&lt;/li&gt;
&lt;li&gt;Mock easy things

&lt;ul&gt;
&lt;li&gt;use a decorator on any test/view that might use redis&lt;/li&gt;
&lt;li&gt;if redis isn't setup, use the mock client&lt;/li&gt;
&lt;li&gt;mock client doesn't support everything,

&lt;ul&gt;
&lt;li&gt;just what I need to get my tests running -&lt;/li&gt;
&lt;li&gt;feel free to extend it if you use it&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Testing Redis&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Setup/Teardown for complicated tools

&lt;ul&gt;
&lt;li&gt;Good for search and APIs&lt;/li&gt;
&lt;li&gt;Raise SkipTest (nose) if the developer doesn't want to run these tests&lt;/li&gt;
&lt;li&gt;Non realtime tools

&lt;ul&gt;
&lt;li&gt;Testing Sphinx search&lt;/li&gt;
&lt;li&gt;SetupClass

&lt;ul&gt;
&lt;li&gt;load fixtures&lt;/li&gt;
&lt;li&gt;run indexer&lt;/li&gt;
&lt;li&gt;run server&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Sphinx server now available for all tests in your test case&lt;/li&gt;
&lt;li&gt;Teardown

&lt;ul&gt;
&lt;li&gt;stop server&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Real time tools

&lt;ul&gt;
&lt;li&gt;Nicer, data can be added in post_save signals or elsewhere in your app&lt;/li&gt;
&lt;li&gt;Testing LDAP

&lt;ul&gt;
&lt;li&gt;Setup

&lt;ul&gt;
&lt;li&gt;Remove LDAP files&lt;/li&gt;
&lt;li&gt;Load an ldif&lt;/li&gt;
&lt;li&gt;Start slapd&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Your code can now touch LDAP&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Testing ElasticSearch

&lt;ul&gt;
&lt;li&gt;We leave ES running all the time.&lt;/li&gt;
&lt;li&gt;Setup

&lt;ul&gt;
&lt;li&gt;Checks for ES support or SkipTest&lt;/li&gt;
&lt;li&gt;Deletes index&lt;/li&gt;
&lt;li&gt;Creates index&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;You can now read/write to ES&lt;/li&gt;
&lt;li&gt;Teardown

&lt;ul&gt;
&lt;li&gt;Delete's index&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Fixtures

&lt;ul&gt;
&lt;li&gt;Fixture Magic&lt;/li&gt;
&lt;li&gt;Model Maker&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;pitfalls

&lt;ul&gt;
&lt;li&gt;dates&lt;/li&gt;
&lt;li&gt;using PDB&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;

</content>
 </entry>
 
 <entry>
   <title>How we slug at Mozilla</title>
   <link href="http://davedash.com/2011/03/24/how-we-slug-at-mozilla/"/>
   <updated>2011-03-24T00:00:00-07:00</updated>
   <id>http://davedash.com/2011/03/24/how-we-slug-at-mozilla</id>
   <content type="html">&lt;p&gt;One problem we find with slug generators, is they do an awful job with unicode.
For a string like this: &lt;code&gt;Bän...g (bang)&lt;/code&gt; you get something like
&lt;code&gt;bng---g--bang-&lt;/code&gt; or at best &lt;code&gt;bang-bang&lt;/code&gt;.  But it's 2011, urls can have
unicode... here's what we really want: &lt;code&gt;bäng-bang&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;In some cases transliteration might be acceptable.  But if we look at Django's
approach it fails at Russian.  Here's a comparison with ours for the Russian
phrase &quot;Быстрее и лучше!&quot; (&quot;Faster and better!&quot;):&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;&amp;gt;&amp;gt;&amp;gt; from django.template.defaultfilters import slugify as djslugify
&amp;gt;&amp;gt;&amp;gt; from slugify import slugify
&amp;gt;&amp;gt;&amp;gt; str = u'Быстрее и лучше!'
&amp;gt;&amp;gt;&amp;gt; print djslugify(str)

&amp;gt;&amp;gt;&amp;gt; print slugify(str)
быстрее-и-лучше
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;So as you can see, the built-in Django &lt;code&gt;slugify&lt;/code&gt; could be disastrous.  So take
a look at &lt;a href=&quot;https://github.com/mozilla/unicode-slugify&quot;&gt;ours&lt;/a&gt;.  If you have some more test cases, please fork it.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Testing Redis in Django</title>
   <link href="http://davedash.com/2010/12/07/testing-redis-in-django/"/>
   <updated>2010-12-07T00:00:00-08:00</updated>
   <id>http://davedash.com/2010/12/07/testing-redis-in-django</id>
   <content type="html">&lt;p&gt;For the &lt;a href=&quot;http://addons.mozilla.org/en-US/firefox/&quot;&gt;Firefox Add-ons&lt;/a&gt; we've been using &lt;a href=&quot;http://code.google.com/p/redis/&quot;&gt;redis&lt;/a&gt; here and there mostly
for cache, but lately for a few things we'd love to persist.&lt;/p&gt;

&lt;p&gt;Unfortunately relying on redis does mean we need to be able to test it.  Since
redis touches some of our core components of the site, we can't just raise a
&lt;code&gt;SkipTest&lt;/code&gt; like we would for Sphinx search related tests.  I also don't want to
rely on our developers to have redis installed in order to run the
test-suite.&lt;/p&gt;

&lt;p&gt;So I built a simple &lt;a href=&quot;https://github.com/mozilla/nuggets/blob/master/redisutils.py#L47&quot;&gt;Mock Redis client&lt;/a&gt;.  It's part of our
&lt;code&gt;redisutils.py&lt;/code&gt; that handles connections to redis.  If a test's &lt;code&gt;setUp&lt;/code&gt; method
calls &lt;code&gt;mock_redis&lt;/code&gt; you'll get this phony object that can do a few minimal
redis-like operations.&lt;/p&gt;

&lt;p&gt;It works great for our specific cases, but feel free to fork it and make it
better.&lt;/p&gt;

&lt;p&gt;Note: This &lt;code&gt;MockRedis&lt;/code&gt; is specifically designed to work with &lt;a href=&quot;http://www.djangoproject.com/&quot;&gt;django&lt;/a&gt;.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Faceted Search on Input</title>
   <link href="http://davedash.com/2010/10/29/faceted-search-on-input/"/>
   <updated>2010-10-29T00:00:00-07:00</updated>
   <id>http://davedash.com/2010/10/29/faceted-search-on-input</id>
   <content type="html">&lt;p&gt;So one trick with &lt;a href=&quot;http://sphinxsearch.com/&quot;&gt;Sphinx search&lt;/a&gt; is &lt;a href=&quot;http://en.wikipedia.org/wiki/Faceted_search&quot;&gt;faceted search&lt;/a&gt;.  It's somewhat
crudely implemented, by batching queries together, but does the job well.  In
the case of &lt;a href=&quot;http://input.mozilla.com/&quot;&gt;Firefox Input&lt;/a&gt; it can reduce quite a bit of queries (our
search result pages take one batched sphinx query, and one database query now
instead of 5 database queries).&lt;/p&gt;

&lt;div class=&quot;side&quot;&gt;
&lt;a href=&quot;http://www.flickr.com/photos/davedash/5126379671/&quot;
   title=&quot;Add-on Search Results for shopping :: Add-ons for Firefox&quot;&gt;
   &lt;img src=&quot;http://farm5.static.flickr.com/4041/5126379671_33b3e472d5_m.jpg&quot;
    width=&quot;240&quot; height=&quot;172&quot; alt=&quot;Add-on Search Results for shopping&quot; /&gt;&lt;/a&gt;
&lt;/div&gt;


&lt;p&gt;Faceted search is search with filters to help narrow down a result set.  I'll
give you three examples.  &lt;a href=&quot;http://addons.mozilla.org/&quot;&gt;Firefox Add-ons&lt;/a&gt; which I wrote,
&lt;a href=&quot;http://www.sittercity.com/search-sitters.html?ct=101&amp;amp;zip=95126&quot;&gt;Sitter City&lt;/a&gt; which gives you a lot of ways on narrowing down on the perfect
baby sitter and &lt;a href=&quot;http://ebay.com/&quot;&gt;ebay&lt;/a&gt; which lets your narrow down on auction items.&lt;/p&gt;

&lt;p&gt;For &lt;a href=&quot;http://input.mozilla.com/&quot;&gt;Input&lt;/a&gt; we ask for the following when we do a search:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;How many opinions match the term for which we are searching taking into
account any preferences we have already specified (feeling, locale, operating
system, date range, etc).&lt;/li&gt;
&lt;li&gt;How many opinions show a positive sentiment, and how many show a negative
sentiment?&lt;/li&gt;
&lt;li&gt;What is the breakdown of languages for the opinion results.  (I.e. how many
are en-US, de, fr, etc).&lt;/li&gt;
&lt;li&gt;How many people are on Mac, Linux or Windows.&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;We can batch these four queries into a single Sphinx request.&lt;/p&gt;

&lt;p&gt;Here's &lt;a href=&quot;http://github.com/davedash/reporter/commit/348018&quot;&gt;our implementation&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Having done this twice, I do recognize that there is a lot of room for making
the code a bit more reusable.  But overall it runs fairly well.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Trimming Whitespace in Django Forms</title>
   <link href="http://davedash.com/2010/08/18/trimming-whitespace-in-django-forms/"/>
   <updated>2010-08-18T00:00:00-07:00</updated>
   <id>http://davedash.com/2010/08/18/trimming-whitespace-in-django-forms</id>
   <content type="html">&lt;p&gt;I've been using frameworks for a number of years.  So I expect a lot of things
to happen &quot;for free&quot; in Django.  One is whitespace removal.  In &lt;a href=&quot;http://delicious.com/&quot;&gt;Delicious&lt;/a&gt;
we had a lot of data in our database with leading and trailing whitespace.  On
the frontend we moved to symfony (actually ysymfony) and that prevented a lot
of this.&lt;/p&gt;

&lt;p&gt;So I was quite surprised that &lt;a href=&quot;http://code.djangoproject.com/ticket/6362&quot;&gt;this is not the case with Django&lt;/a&gt;.  So I
decided we could solve this at the form level, and released a
&lt;a href=&quot;http://github.com/mozilla/happyforms&quot;&gt;ridiculously simple library&lt;/a&gt;.  After some googling, I found that I was
&lt;a href=&quot;http://www.peterbe.com/plog/automatically-strip-whitespace-in-django-forms&quot;&gt;not the first to do this&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Feel free to use this, fork it, submit pull requests, etc.  I suspect in the
future we'll handle other global form filtering - like stripping high order
Unicode since MySQL is often not a fan.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>The Perils of One Giant Fixture</title>
   <link href="http://davedash.com/2010/08/12/the-perils-of-one-giant-fixture/"/>
   <updated>2010-08-12T00:00:00-07:00</updated>
   <id>http://davedash.com/2010/08/12/the-perils-of-one-giant-fixture</id>
   <content type="html">&lt;p&gt;&lt;img src=&quot;/static/images/2010/08/12/time.jpg&quot; alt=&quot;Timing&quot; /&gt;&lt;/p&gt;

&lt;p&gt;A while back, I thought it would be good to consolidate all the data used in
testing the django-layer of &lt;a href=&quot;https://addons.mozilla.org/&quot;&gt;AMO&lt;/a&gt; into a single data fixture.
Unfortunately we have 600 tests, which were now loading and unloading large
amounts of data each time the test would run.  This made our tests take 20
minutes.&lt;/p&gt;

&lt;p&gt;I decided to cut this down quite a bit, by using smaller fixture files.  Each
fixture file attempts to be a singular primary object (e.g. an Addon or a
Collection or a User) and its associated supporting objects.  It's far from
perfect, but it's achieved tests that run in under 10 minutes.&lt;/p&gt;

&lt;p&gt;The other side effect is tests will be simpler.  They'll only include the
addons needed to generate an effect, and if something can't be done easily with
the fixtures in place, we can always alter the data during the test.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Your objects, and all their friends</title>
   <link href="http://davedash.com/2010/06/25/your-objects%2C-and-all-their-friends/"/>
   <updated>2010-06-25T00:00:00-07:00</updated>
   <id>http://davedash.com/2010/06/25/your-objects,-and-all-their-friends</id>
   <content type="html">&lt;p&gt;This is complicated.&lt;/p&gt;

&lt;p&gt;In my ever-evolving quest to &lt;a href=&quot;/2010/03/05/django-fixture-magic-testing-issues-with-real-data/&quot;&gt;get data out of the AMO database&lt;/a&gt; for tests, I
found myself not just extracting a single object, but a list of complicated
requirements in order to fully replicate behavior in production in a testing
environment.&lt;/p&gt;

&lt;p&gt;For &lt;a href=&quot;https://addons.mozilla.org/en-US/firefox/&quot;&gt;AMO&lt;/a&gt; we can use &lt;a href=&quot;http://pypi.python.org/pypi/django-fixture-magic&quot;&gt;fixture magic&lt;/a&gt; to dump a single add-on and all of
it's &lt;em&gt;database&lt;/em&gt; dependencies so that it will insert safely into a
test-database.  But we need more than just valid data.  We need some supporting
data.  For an add-on to be browsable and searchable it needs to have a valid
version and the version needs to have a valid file.&lt;/p&gt;

&lt;p&gt;In our app we can check for these things by using this:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;my_addon.current_version.files.all()[0]
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Of course we need to check that &lt;code&gt;my_addon.current_version&lt;/code&gt; exists and that
&lt;code&gt;files.all()&lt;/code&gt; has at least one object.  This ends up being a lot of work if you
just know the &lt;code&gt;id&lt;/code&gt; of the add-on object.&lt;/p&gt;

&lt;p&gt;So what I want is something simple, like:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;./manage.py custom_dump addon 3615
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;And it should get me everything I need to test add-on 3615, including a Version
object and any files associated with the version.&lt;/p&gt;

&lt;p&gt;Turns out this &lt;em&gt;just works&lt;/em&gt;.  It works if you define the following settings:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;python&quot;&gt;&lt;span class=&quot;c&quot;&gt;## Fixture Magic&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;CUSTOM_DUMPS&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;s&quot;&gt;&amp;#39;addon&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;  &lt;span class=&quot;c&quot;&gt;# ./manage.py custom_dump addon id&lt;/span&gt;
        &lt;span class=&quot;s&quot;&gt;&amp;#39;primary&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;#39;addons.addon&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;  &lt;span class=&quot;c&quot;&gt;# This is our reference model.&lt;/span&gt;
        &lt;span class=&quot;s&quot;&gt;&amp;#39;dependents&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;  &lt;span class=&quot;c&quot;&gt;# These are items we wish to dump.&lt;/span&gt;
            &lt;span class=&quot;c&quot;&gt;# Magic turns this into current_version.files.all()[0].&lt;/span&gt;
            &lt;span class=&quot;s&quot;&gt;&amp;#39;current_version.files.all.0&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;
        &lt;span class=&quot;s&quot;&gt;&amp;#39;order&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;#39;app1.model1&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;#39;app2.model2&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,),&lt;/span&gt;  &lt;span class=&quot;c&quot;&gt;# stuff gets sorted&lt;/span&gt;
        &lt;span class=&quot;s&quot;&gt;&amp;#39;excludes&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;s&quot;&gt;&amp;#39;app1.model1&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;#39;fields&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;#39;to&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;#39;hide&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,),&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;Using this we're able to find out that &lt;code&gt;addon&lt;/code&gt; means an &lt;code&gt;addons.addon&lt;/code&gt; object
and that you want the &lt;code&gt;addon&lt;/code&gt; object with an id of &lt;code&gt;3615&lt;/code&gt;.  From there we'll
try looking for dependent objects.  Using some black magic we can turn:
&lt;code&gt;current_version.files.all.0&lt;/code&gt; into
&lt;code&gt;addon.objects.get(pk=3615).current_version.files.all()[0]&lt;/code&gt;.  This gives us a
file.&lt;/p&gt;

&lt;p&gt;If we mimic our &lt;code&gt;dump_object&lt;/code&gt; command we can get the &lt;code&gt;file&lt;/code&gt; into the database
and everything that the file needs to be valid.  This in turn gives us enough
data (usually) to begin testing a single &lt;code&gt;addon&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;So have fun with this, if you're database is remotely complicated, this can
save you some time replicating it during testing.&lt;/p&gt;

&lt;p&gt;Also note, that you can re-order models and exclude certain fields.  This can
make your fixtures very easy to load.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Test Driven Confidence</title>
   <link href="http://davedash.com/2010/04/20/test-driven-confidence/"/>
   <updated>2010-04-20T00:00:00-07:00</updated>
   <id>http://davedash.com/2010/04/20/test-driven-confidence</id>
   <content type="html">&lt;p&gt;If you're already testing your web applications, you can skip this post.&lt;/p&gt;

&lt;p&gt;One of the bugs I am working for &lt;a href=&quot;https://addons.mozilla.org/&quot;&gt;AMO&lt;/a&gt; on involves porting a small, but moderately complicated checkbox from our PHP site and rewriting it for Django.&lt;/p&gt;

&lt;p&gt;I decided to look at the existing implementation and found it to not work correctly at all.  This was frustrating, especially since I verified that my own code worked, and that QA verified that it worked as well.&lt;/p&gt;

&lt;p&gt;This is frustrating on many levels.  Chances are some minor assumption I made changed, and thus broke this functionality.  Discovering regressions is never fun, and fixing them is can be long and tedious if you can't automatically verify that everything is working correctly.&lt;/p&gt;

&lt;p&gt;Lucky for me, coming up with tests is easy, you just do what you would do to verify the code satisfies the requirements and then code it.  Sometimes the tests can take longer than writing the actual code, but ultimately you can ship with confidence.  You can be confident that your feature won't break in the future without immediate notice, and you can be confident that your new code won't break anything else.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Making our tests run thrice as fast</title>
   <link href="http://davedash.com/2010/03/16/making-our-tests-run-thrice-as-fast/"/>
   <updated>2010-03-16T00:00:00-07:00</updated>
   <id>http://davedash.com/2010/03/16/making-our-tests-run-thrice-as-fast</id>
   <content type="html">&lt;p&gt;I've written a faster version of &lt;a href=&quot;http://github.com/jbalogh/test-utils/blob/c4c31905a95e59dcc8919c1030b23848ad7fbca6/test_utils/__init__.py#L57&quot;&gt;TransactionTestCase&lt;/a&gt; and packaged it with &lt;a href=&quot;http://github.com/jbalogh/test-utils&quot;&gt;test_utils&lt;/a&gt;.  It's mysql specific since it relies on &lt;code&gt;SET FOREIGN_KEY_CHECKS=0&lt;/code&gt; to flush the database.&lt;/p&gt;

&lt;p&gt;The long story...&lt;/p&gt;

&lt;!-- more--&gt;


&lt;h3&gt;Why speed matters&lt;/h3&gt;

&lt;p&gt;We're closing in on 300 tests for &lt;a href=&quot;http://github.com/jbalogh/zamboni/&quot;&gt;Zamboni&lt;/a&gt;.  As of yesterday, to run our entire test suite it would have taken approximately 5 minutes.  If you run tests before code-reviews, during a code-review, and before you push to master - you've spent about 15 minutes doing tests for a single feature or bug-fix.  We have about 5 developers, so this cycle happens many times in a work day.  In that time many sandwiches can be made and consumed.&lt;/p&gt;

&lt;p&gt;Even shortcuts, like running a subset of tests will only go so far, and ultimately we do want to validate that all our tests pass for any code-change.&lt;/p&gt;

&lt;h3&gt;Testing Sphinx search with &lt;code&gt;TransactionTestCase&lt;/code&gt;&lt;/h3&gt;

&lt;p&gt;Django recently sped up testing by running tests in a transaction.  However, this means that data never gets committed to the database and therefore external tools, like the Sphinx indexer, will never see any of that data.  So we resort to &lt;code&gt;TransactionTestCase&lt;/code&gt; which &lt;em&gt;will&lt;/em&gt; commit the data.&lt;/p&gt;

&lt;p&gt;Unfortunately &lt;code&gt;TransactionTestCase&lt;/code&gt; is painfully slow.  The accepted practice is to only use &lt;code&gt;TestCase&lt;/code&gt; if you want your tests to be fast.  So, I decided to complain to &lt;a href=&quot;http://blog.ianbicking.org/&quot;&gt;one of our new hires&lt;/a&gt; and he and I decided to tinker in mysql to figure out what was slow.  We discovered the following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;delete from [table] is slow&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;truncate [table] is slow&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;... unless you &lt;code&gt;SET FOREIGN_KEY_CHECKS=0&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;So we decided we should do our own tear down.  After some tinkering with &lt;code&gt;cProfiler&lt;/code&gt; I discovered that &lt;code&gt;TransactionTestCase&lt;/code&gt; does a (slow) database &lt;code&gt;flush&lt;/code&gt; on setup for a test case.  This wouldn't do.&lt;/p&gt;

&lt;h3&gt;Making our own &lt;code&gt;TransactionTestCase&lt;/code&gt;&lt;/h3&gt;

&lt;p&gt;I decided to make our own &lt;code&gt;TransactionTestCase&lt;/code&gt; and it would just run &lt;code&gt;SET FOREIGN_KEY_CHECKS=0&lt;/code&gt; and &lt;code&gt;TRUNCATE&lt;/code&gt; on each table at tear down time.  It would also not do a &lt;code&gt;flush&lt;/code&gt; on set up.&lt;/p&gt;

&lt;p&gt;We write our tests with the idea that they clean up after themselves.  Rather than having them cleanup after the last test.  This is a requirement for us since &lt;code&gt;django-nose&lt;/code&gt; doesn't reorder tests (nor should it) and a standard &lt;code&gt;django.test.TestCase&lt;/code&gt; assumes a clean database.&lt;/p&gt;

&lt;p&gt;Looking at a single test &lt;code&gt;test_sphinx_indexer&lt;/code&gt;, using &lt;code&gt;django.test.TransactionTestCase&lt;/code&gt; took ~30 seconds.  Using our new &lt;code&gt;TransactionTestCase&lt;/code&gt; it takes ~4 seconds!&lt;/p&gt;

&lt;h3&gt;Fast tests are good&lt;/h3&gt;

&lt;p&gt;We can now run our 275 tests in ~100 seconds versus the ~300 seconds it used to take.  Furthermore, skipping our sphinx tests (which are the only tests that use &lt;code&gt;TransactionTestCase&lt;/code&gt;) only saves us ~10seconds.  That's not a lot of overhead for better coverage.&lt;/p&gt;

&lt;p&gt;This took me the better part of a day, but solving this now, means we're going to more often than not run our sphinx tests all the time rather than skip them.  Our QA team will assure you that search is probably the most regression prone part of our site, so running these tests are vital to quality.&lt;/p&gt;

&lt;p&gt;If you need to use &lt;code&gt;TransactionTestCase&lt;/code&gt; in mysql, &lt;a href=&quot;http://github.com/jbalogh/test-utils&quot;&gt;give ours a try&lt;/a&gt;.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>&lambda;^2: safely doing class based views in Django</title>
   <link href="http://davedash.com/2010/03/09/2-safely-doing-class-based-views-in-django/"/>
   <updated>2010-03-09T00:00:00-08:00</updated>
   <id>http://davedash.com/2010/03/09/2-safely-doing-class-based-views-in-django</id>
   <content type="html">&lt;p&gt;When I started rewriting the API for &lt;a href=&quot;https://addons.mozilla.org/&quot;&gt;addons.mozilla.org&lt;/a&gt;, my views were mostly the same: get some data and render it as either JSON or XML.  I also wanted all my API methods to take an &lt;code&gt;api_version&lt;/code&gt; parameter, so I decided class based views would be best.  This way my classes could just inherit from a base class.&lt;/p&gt;

&lt;p&gt;To do this I had to implement a &lt;a href=&quot;http://github.com/davedash/zamboni/blob/b5a147820840e66b542691e7239f15eccdebeec9/apps/api/views.py#L39&quot;&gt;&lt;code&gt;__call__&lt;/code&gt; method&lt;/a&gt;.  This works fine, except I wanted to store things into the class -- after all the whole point of my use of classes was to keep the code a bit more compact, and cleaner.  So, why pass the api_version around everywhere?  Unfortunately thread-safety comes to play, and you need a separate instance of your class for each request.&lt;/p&gt;

&lt;!--more--&gt;


&lt;h3&gt;&amp;lambda;&lt;/h3&gt;

&lt;p&gt;Django's &lt;code&gt;urlpatterns&lt;/code&gt; expects a callable object.  So you can't give it an instance of &lt;code&gt;AddonDetailView()&lt;/code&gt;.  But you could give it a callable that creates an instance of &lt;code&gt;AddonDetailView()&lt;/code&gt; and passes it &lt;code&gt;*args&lt;/code&gt; and &lt;code&gt;**kwargs&lt;/code&gt;.  Luckily python has &lt;code&gt;lambda&lt;/code&gt; functions.  You can &lt;a href=&quot;http://github.com/davedash/zamboni/blob/b5a147820840e66b542691e7239f15eccdebeec9/apps/api/urls.py#L10&quot;&gt;note how we solved that in our &lt;code&gt;urlpatterns&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;&amp;lambda; &amp;lambda;&lt;/h3&gt;

&lt;p&gt;But wrapping all your urls with &lt;code&gt;lambda&lt;/code&gt; is tedious and remembering to pass &lt;code&gt;*args&lt;/code&gt; and &lt;code&gt;**kwargs&lt;/code&gt; is error prone.&lt;/p&gt;

&lt;p&gt;So let's make a &lt;code&gt;lambda&lt;/code&gt; function that returns... a &lt;code&gt;lambda&lt;/code&gt; function that &lt;a href=&quot;http://github.com/davedash/zamboni/blob/609ec5467dd6db6a6647f375e95abced5203a1b2/apps/api/urls.py#L9&quot;&gt;turns an instance of our class into a callable&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;We can now return to coding and not think about thread safety.&lt;/p&gt;

&lt;p&gt;&amp;lambda;&amp;lambda;&amp;lambda;&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>django-fixture-magic: Testing issues with real data.</title>
   <link href="http://davedash.com/2010/03/05/django-fixture-magic-testing-issues-with-real-data/"/>
   <updated>2010-03-05T00:00:00-08:00</updated>
   <id>http://davedash.com/2010/03/05/django-fixture-magic-testing-issues-with-real-data</id>
   <content type="html">&lt;p&gt;I just released &lt;a href=&quot;http://github.com/davedash/django-fixture-magic&quot;&gt;Fixture Magic&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;When dealing with legacy data, you'll run into all kinds of edge cases.  Perhaps, an object might not display correctly unless it has the right parameters, or if it has null parameters it might not display at all.  So when testing &lt;a href=&quot;http://djangoproject.com/&quot;&gt;Django&lt;/a&gt;, it's nice to actually use non-dummy data.&lt;/p&gt;

&lt;p&gt;Luckily Django has a way of pulling real data out of your database using &lt;code&gt;django.core.serializers&lt;/code&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;from addons.models import Addon
a = Addon.objects.get(id=3615)
from django.core.serializers import serialize
jsonize = lambda a: serialize(&quot;json&quot;, a, indent=4)
jsonize([a])
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This solution runs well in a Django shell and can be lots of fun for the whole family... until things get complicated.&lt;/p&gt;

&lt;!--more--&gt;


&lt;h3&gt;Serializing alone isn't enough.&lt;/h3&gt;

&lt;p&gt;Serializing a fixture with foreign keys means you'll have an un-loadable fixture unless you serialize the dependent fixtures.  Even for one or two foreign keys, this can be a pain.  For &lt;a href=&quot;http://addons.mozilla.org/&quot;&gt;addons.mozilla.org&lt;/a&gt;, we have a spidery-web of dependencies: &lt;code&gt;File&lt;/code&gt;s need a &lt;code&gt;Version&lt;/code&gt; which needs an &lt;code&gt;Addon&lt;/code&gt; which need &lt;code&gt;Translation&lt;/code&gt;s.&lt;/p&gt;

&lt;p&gt;Thus begat the &lt;code&gt;dump_object&lt;/code&gt; management command.  Give it an app, model name and a &lt;code&gt;pk&lt;/code&gt; and it will give you not only a serialized JSON of that object, but all the objects that it requires.&lt;/p&gt;

&lt;p&gt;Example:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;./manage.py dump_object files.file 64874 64876 &amp;gt; my_new_fixture.json
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This looks for the &lt;code&gt;File&lt;/code&gt; model in the &lt;code&gt;files&lt;/code&gt; app and pulls out of the database &lt;code&gt;File&lt;/code&gt;s instances with &lt;code&gt;pk&lt;/code&gt;s of &lt;code&gt;64874&lt;/code&gt; and &lt;code&gt;64876&lt;/code&gt;.  It then recursively searches for any required objects.&lt;/p&gt;

&lt;h3&gt;Too much serial&lt;/h3&gt;

&lt;p&gt;If you create a lot of fixtures, you'll eventually have overlapping serialized objects.  In &lt;code&gt;addons.mozilla.org&lt;/code&gt; we have &lt;code&gt;Addon&lt;/code&gt;s, &lt;code&gt;Version&lt;/code&gt;s (which depend on &lt;code&gt;Addon&lt;/code&gt;s) and &lt;code&gt;AddonCategory&lt;/code&gt;s (which depend on &lt;code&gt;Addon&lt;/code&gt;s and &lt;code&gt;Category&lt;/code&gt;s).  If we wanted to get serialize a specific &lt;code&gt;Addon&lt;/code&gt;, it's dependent &lt;code&gt;Version&lt;/code&gt;s and &lt;code&gt;AddonCategory&lt;/code&gt;s it makes sense to start with &lt;code&gt;dump_object&lt;/code&gt;ing the related &lt;code&gt;Version&lt;/code&gt; and then &lt;code&gt;dump_objecting&lt;/code&gt; the &lt;code&gt;AddonCategory&lt;/code&gt;.  Both &lt;code&gt;dump_object&lt;/code&gt; commands will fetch the &lt;code&gt;Addon&lt;/code&gt; in question, resulting in duplicated data.&lt;/p&gt;

&lt;p&gt;To combat this we can use &lt;code&gt;merge_fixtures&lt;/code&gt; to dedupe our fixtures:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;./manage.py dump_object versions.version 64874 &amp;gt; 1.json
./manage.py dump_object categories.addoncategory &amp;gt; 2.json
./manage.py merge_json 1.json 2.json &amp;gt; happy_fixture.json
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This should make creating test data slightly less painful.  So &lt;a href=&quot;http://github.com/davedash/django-fixture-magic&quot;&gt;give it a try&lt;/a&gt;.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Retrieving elements in a specific order in Django and mySQL</title>
   <link href="http://davedash.com/2010/02/11/retrieving-elements-in-a-specific-order-in-django-and-mysql/"/>
   <updated>2010-02-11T00:00:00-08:00</updated>
   <id>http://davedash.com/2010/02/11/retrieving-elements-in-a-specific-order-in-django-and-mysql</id>
   <content type="html">&lt;p&gt;If you have a list of ordered ids and you want to turn them into an ordered result set you can use &lt;code&gt;FIELD()&lt;/code&gt; in mysql:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;SELECT * FROM addons
ORDER BY FIELD(id, 3, 5, 9, 1);
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This is a handy trick if you use an external search engine which gives you an ordered list of ids and you want to pull out entire row sets.&lt;/p&gt;

&lt;p&gt;We do this in &lt;a href=&quot;http://github.com/jbalogh/zamboni&quot;&gt;addons.mozilla.org&lt;/a&gt; using the Django ORM like so:&lt;/p&gt;

&lt;script src=&quot;http://gist.github.com/301162.js&quot;&gt;&lt;/script&gt;


&lt;p&gt;&lt;a href=&quot;http://github.com/jbalogh/zamboni/commit/a0166108e8a62f386b4310cab0ceb3502575d520#L1R219&quot;&gt;The code in action&lt;/a&gt;.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Django: Model Inheritance or Related Tables wrt AMO</title>
   <link href="http://davedash.com/2009/12/15/django-model-inheritance-or-related-tables-wrt-amo/"/>
   <updated>2009-12-15T00:00:00-08:00</updated>
   <id>http://davedash.com/2009/12/15/django-model-inheritance-or-related-tables-wrt-amo</id>
   <content type="html">&lt;p&gt;When I attended DjangoCon this year, I lamented that our flagship web property was difficult to test, and not fun to develop.  I figured DjangoCon was a way to placate me, and Django might mean something for some of the smaller projects at Mozilla.  However, Wil Clouser, our lead web developer, &lt;a href=&quot;http://micropipes.com/blog/2009/11/17/amo-development-changes-in-2010/&quot;&gt;announced development changes&lt;/a&gt; for &lt;a href=&quot;http://addons.mozilla.org&quot;&gt;addons.mozilla.org&lt;/a&gt; (AMO) that says we'll be moving to Django.&lt;/p&gt;

&lt;p&gt;Wil was open to Django and knew that's what we in the dev team wanted.  Jeff spawned our foray into a new AMO with &lt;a href=&quot;http://github.com/jbalogh/zamboni&quot;&gt;Zamboni&lt;/a&gt;.  I've been working on some grunt-work tasks inside and outside of Django.&lt;/p&gt;

&lt;p&gt;One of those tasks is building a transparent layer in Django to keep users logged in from our PHP-based site.  That kind of problem almost immediately forces you to ask one of the most fundamental questions you ask when using any framework:&lt;/p&gt;

&lt;blockquote&gt;&lt;p&gt;How much do I change my app, in order to accommodate the framework?&lt;/p&gt;&lt;/blockquote&gt;

&lt;!--more--&gt;


&lt;p&gt;More specifically:&lt;/p&gt;

&lt;blockquote&gt;&lt;p&gt;Should I use the &lt;code&gt;django.contrib.auth&lt;/code&gt; User module, and to what extent?&lt;/p&gt;&lt;/blockquote&gt;

&lt;p&gt;The more we looked into what features of Django we might want to use, &lt;code&gt;django.contrib.auth&lt;/code&gt; was heavily tied into other things we wanted, so it made sense for us to use it.  The next question is whether we try the &lt;a href=&quot;http://scottbarnham.com/blog/2008/08/21/extending-the-django-user-model-with-inheritance/&quot;&gt;inheritance approach&lt;/a&gt; or do we treat our legacy users table as a sort of User Profile and utilize the User module using the &lt;a href=&quot;http://www.b-list.org/weblog/2007/feb/20/about-model-subclassing/&quot;&gt;related table approach&lt;/a&gt;?&lt;/p&gt;

&lt;p&gt;Using model-inheritance seems real nice, because we can pretend that our legacy user is the same thing as a &lt;code&gt;djaango.contrib.auth&lt;/code&gt; User - but this isn't true:&lt;/p&gt;

&lt;p&gt;Looking at our &lt;code&gt;users&lt;/code&gt; table more closely:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;mysql&amp;gt; explain users;
+-------------------------+---------------------+------+-----+---------------------+----------------+
| Field                   | Type                | Null | Key | Default             | Extra          |
+-------------------------+---------------------+------+-----+---------------------+----------------+
| id                      | int(11) unsigned    | NO   | PRI | NULL                | auto_increment |
| email                   | varchar(255)        | YES  | UNI | NULL                |                |
| password                | varchar(255)        | NO   |     |                     |                |
| firstname               | varchar(255)        | NO   |     |                     |                |
| lastname                | varchar(255)        | NO   |     |                     |                |
| nickname                | varchar(255)        | YES  | MUL | NULL                |                |
| bio                     | int(11) unsigned    | YES  | MUL | NULL                |                |
| emailhidden             | tinyint(1) unsigned | NO   |     | 0                   |                |
| sandboxshown            | tinyint(1) unsigned | NO   |     | 0                   |                |
| homepage                | varchar(255)        | YES  |     | NULL                |                |
| display_collections     | tinyint(1) unsigned | NO   |     | 0                   |                |
| display_collections_fav | tinyint(1) unsigned | NO   |     | 0                   |                |
| confirmationcode        | varchar(255)        | NO   |     |                     |                |
| resetcode               | varchar(255)        | NO   |     |                     |                |
| resetcode_expires       | datetime            | NO   |     | 0000-00-00 00:00:00 |                |
| notifycompat            | tinyint(1) unsigned | NO   | MUL | 1                   |                |
| notifyevents            | tinyint(1) unsigned | NO   | MUL | 1                   |                |
| deleted                 | tinyint(1)          | YES  |     | 0                   |                |
| created                 | datetime            | NO   | MUL | 0000-00-00 00:00:00 |                |
| modified                | datetime            | NO   |     | 0000-00-00 00:00:00 |                |
| notes                   | text                | YES  |     | NULL                |                |
| location                | varchar(255)        | NO   |     |                     |                |
| occupation              | varchar(255)        | NO   |     |                     |                |
| picture_type            | varchar(25)         | NO   |     |                     |                |
| averagerating           | varchar(255)        | YES  |     | NULL                |                |
+-------------------------+---------------------+------+-----+---------------------+----------------+
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;You can very easily argue that this is a profile table, which happens to have credential information thrown in.&lt;/p&gt;

&lt;p&gt;I can see overtime, I'll just struggle to keep our legacy User to act like a Django User, whereas a UserProfile is fairly standard.&lt;/p&gt;

&lt;p&gt;Had I been writing this app from scratch, I would have chosen the UserProfile route.  This is extra data which takes up a lot of space, and changes far more often than user credentials.  Changing 4M+ rows sucks, by making users our UserProfile table, any changes to that table, don't tie up the table used for sign-ins.&lt;/p&gt;

&lt;p&gt;I'm curious what other people who port their apps to Django have done.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>DjangoCon wrapup</title>
   <link href="http://davedash.com/2009/09/15/djangocon-wrapup/"/>
   <updated>2009-09-15T00:00:00-07:00</updated>
   <id>http://davedash.com/2009/09/15/djangocon-wrapup</id>
   <content type="html">&lt;p&gt;I went to &lt;a href=&quot;http://djangocon.org/&quot;&gt;DjangoCon&lt;/a&gt; this past week for work.  Django is one of my favorite frameworks.  I dropped PHP and the symfony framework to learn python and Django and I haven't looked back.  I think for Mozilla's webdev team it would be the framework of choice.  We have 100s of sites in many frameworks, but not a lot of resuability.  Django apps are built to built to be reusable.  If you build correctly you don't have to refactor, it's already done.&lt;!--more--&gt;&lt;/p&gt;

&lt;p&gt;Here's a collection of notes I collected through the conference.&lt;/p&gt;

&lt;h3&gt;Day one&lt;/h3&gt;

&lt;h4&gt;Keynote - Avi Bryant&lt;/h4&gt;

&lt;blockquote&gt;&lt;p&gt;Frameworks lock us into RDBMS = bad&lt;/p&gt;&lt;/blockquote&gt;

&lt;p&gt;This keynote mentioned the limits of modern frameworks and modern web development.  Essentially frameworks are great for getting started, but as a site grows, the framework gets replaced little by little.  Sometimes it can get in the way - such as with limitation of database choices.&lt;/p&gt;

&lt;h4&gt;UR doing it wrong - James Bennet&lt;/h4&gt;

&lt;p&gt;James outlined a few key problems that many Django developers run into:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;learning python as you go&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt; doesn't work unless you know some programming upfront&lt;/li&gt;
&lt;li&gt; do the python tutorial&lt;/li&gt;
&lt;li&gt; read python in a nutshell or dive into python&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Things you should know:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;subclasses&lt;/li&gt;
&lt;li&gt;super()&lt;/li&gt;
&lt;li&gt;slides went too fast... hopefully they'll be posted&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;All in all RTFM for python and Django :)&lt;/p&gt;

&lt;p&gt;Learn about other py packages... like twisted.  If Twisted Matrix was implemented in Ruby it would be advertised as the second coming of Christ.&lt;/p&gt;

&lt;p&gt;Bennet's Django App review smoketests:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;installable via pip, easy_install or setup.py

&lt;ul&gt;
&lt;li&gt;read distutils-guide&lt;/li&gt;
&lt;li&gt;stay away from setuptools&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;have a README&lt;/li&gt;
&lt;li&gt;INSTALL file list deps&lt;/li&gt;
&lt;li&gt;Write DOCUMENTATION

&lt;ul&gt;
&lt;li&gt;use sphinx.pocoo.org&lt;/li&gt;
&lt;li&gt;store it in your package &lt;em&gt;and&lt;/em&gt; upload package docs&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;LICENSE (most Django apps use BSD)&lt;/li&gt;
&lt;li&gt;Write unit tests&lt;/li&gt;
&lt;li&gt;django-lint - to look over code (like pep8.py)&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;pro-django is a decent book, but not written by Bennet.&lt;/p&gt;

&lt;h4&gt;Testing - Eric Holscher&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Django 1.1 encourages you to test by auto-creating tests.py.&lt;/li&gt;
&lt;li&gt;Support for:

&lt;ul&gt;
&lt;li&gt;Unittests&lt;/li&gt;
&lt;li&gt;Doctest&lt;/li&gt;
&lt;li&gt;Tests done in a db transacation&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Test Driven Documentation (TDD + DDD)&lt;/li&gt;
&lt;li&gt;Doctest

&lt;ul&gt;
&lt;li&gt;easy&lt;/li&gt;
&lt;li&gt;can't use PDB&lt;/li&gt;
&lt;li&gt;Hides certain failures&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Unittests via Django TestCase

&lt;ul&gt;
&lt;li&gt;XUnit&lt;/li&gt;
&lt;li&gt;setup/Teardown&lt;/li&gt;
&lt;li&gt;adds db fixtures&lt;/li&gt;
&lt;li&gt;assertions&lt;/li&gt;
&lt;li&gt;mail testing/inbox testing&lt;/li&gt;
&lt;li&gt;url testing&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;TestCase

&lt;ul&gt;
&lt;li&gt;Browserless Request/Response testing&lt;/li&gt;
&lt;li&gt;Similar to sfBrowser in symfony&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Google Summer of Code (for Django 1.2)

&lt;ul&gt;
&lt;li&gt;Coverage reports!&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;I need to learn PDB&lt;/li&gt;
&lt;/ul&gt;


&lt;h4&gt;Deploying Django -&lt;/h4&gt;

&lt;p&gt;Run mod_wsgi in daemon mode.&lt;/p&gt;

&lt;h3&gt;Day 2&lt;/h3&gt;

&lt;h4&gt;&lt;a href=&quot;http://blog.ianbicking.org/2009/09/10/a-new-self-definition-for-foss/&quot;&gt;Keynote - Ian Bicking&lt;/a&gt;&lt;/h4&gt;

&lt;p&gt;GNU Manifest:&lt;/p&gt;

&lt;blockquote&gt;&lt;p&gt; I consider that the golden rule requires that if I like a program I must share it with other people who like it. Software sellers want to divide the users and conquer them, making each user agree not to share with others. I refuse to break solidarity with other users in this way. I cannot in good conscience sign a nondisclosure agreement or a software license agreement. ...&lt;/p&gt;

&lt;p&gt;So that I can continue to use computers without dishonor, I have decided to put together a sufficient body of free software so that I will be able to get along without any software that is not free.&lt;/p&gt;&lt;/blockquote&gt;

&lt;ul&gt;
&lt;li&gt;GNU manifesto was the idea of sharing software amongst friends&lt;/li&gt;
&lt;li&gt;GNU has purpose - BSD, etc is just a rule - free to share&lt;/li&gt;
&lt;li&gt;Free is not just the absense of copyright&lt;/li&gt;
&lt;li&gt;Free is not a reaction to existing rules, but a golden rule&lt;/li&gt;
&lt;li&gt;Not just a fight against MS&lt;/li&gt;
&lt;li&gt;Need to find morality (the why) within the practical (the law, or what you can do)&lt;/li&gt;
&lt;li&gt;Open sourcing closed source code isn't building open source&lt;/li&gt;
&lt;li&gt;This might apply to Mozilla... as webkit has taken off more than Gecko.&lt;/li&gt;
&lt;li&gt;Open source is person to person not company to company - despite sponsorship.&lt;/li&gt;
&lt;/ul&gt;


&lt;h3&gt;Using Django in Non-standard ways - Eric Florenzano&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Django loosely coupled&lt;/li&gt;
&lt;li&gt;Replace templating with Jinja 2&lt;/li&gt;
&lt;li&gt;Copy Django methods into djangoext to easily customize Django behavior&lt;/li&gt;
&lt;li&gt;Not using django.contrib.auth

&lt;ul&gt;
&lt;li&gt;reasons: writing a fb app - no auth needed&lt;/li&gt;
&lt;li&gt;no shoehorning needed - saves time - less overhead&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;skip the orm?

&lt;ul&gt;
&lt;li&gt;legacy dbs&lt;/li&gt;
&lt;li&gt;non standard or db (or non-relational database)&lt;/li&gt;
&lt;li&gt;no database&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;wsgi middleware has some cool shit

&lt;ul&gt;
&lt;li&gt;repose.bitblt: autoscales images&lt;/li&gt;
&lt;li&gt;repose.squeeze: will concat js/css on the fly based on statistical analysis&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;non standard Django based apps

&lt;ul&gt;
&lt;li&gt;YARDBird - IRCBot framework&lt;/li&gt;
&lt;li&gt;djng micro framework&lt;/li&gt;
&lt;li&gt;Jngo- singlefile cms&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;using admin in a nonstandard way is hard/impossible coupled with ORM and auth&lt;/li&gt;
&lt;/ul&gt;


&lt;h4&gt;Real-time web and other Buzzwords - Chris Wanstrath&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;more than just getting your rss feeds faster&lt;/li&gt;
&lt;li&gt;push vs. pull&lt;/li&gt;
&lt;li&gt;1 persisting connection vs polling&lt;/li&gt;
&lt;li&gt;comet/flash-xml/or html5 web socket&lt;/li&gt;
&lt;li&gt;orbitted - open source python comet server&lt;/li&gt;
&lt;li&gt;zeddicus - does the business logic&lt;/li&gt;
&lt;li&gt;orbitted has its own js libs - its a simple port/socket thing for your server code to deal with - not request/response.&lt;/li&gt;
&lt;li&gt;all connections are persisting browser/orbitted orbitted/zeddicus&lt;/li&gt;
&lt;li&gt;You can even use orbitted to connect straight to IRC and write a client in JS&lt;/li&gt;
&lt;li&gt;Jetty also is good for comet&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;Also:
* see webhooks
* see pubsubhubub&lt;/p&gt;

&lt;h4&gt;&lt;a href=&quot;http://www.slideshare.net/nowells/djangocon-09-presentation-pluggable-applications&quot;&gt;Pluggable, Reusable Django Apps: A Use Case and Proposed Solution&lt;/a&gt; - Shawn Rider and Nowell Strite&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;PBS moved from perl to django - build a lot of reusable apps&lt;/li&gt;
&lt;li&gt;convincing your superiors

&lt;ul&gt;
&lt;li&gt;need a good story -&lt;/li&gt;
&lt;li&gt;existing base of python helped&lt;/li&gt;
&lt;li&gt;With Django easy to do things right without doing things slow&lt;/li&gt;
&lt;li&gt;be really good...&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;built a lot of apps to be very reusable, and pluggable based on requirements PBS had&lt;/li&gt;
&lt;/ul&gt;


&lt;h3&gt;Day 3&lt;/h3&gt;

&lt;h4&gt;&lt;a href=&quot;http://www.slideshare.net/twleung/djangocon-2009-keynote&quot;&gt;Keynote&lt;/a&gt; - Ted Leung - Sun&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Django jobs are a growing market&lt;/li&gt;
&lt;li&gt;Preferred by startups&lt;/li&gt;
&lt;li&gt;Bespin/wave - cool&lt;/li&gt;
&lt;li&gt;APIs are big... still&lt;/li&gt;
&lt;li&gt;Physically impossible to create purely server-side interactions that are usable enough - rely on rest/comet/ajax/etc to bridge gap&lt;/li&gt;
&lt;/ul&gt;


&lt;h4&gt;&lt;a href=&quot;http://immike.net/files/scaling_django_dc09.pdf&quot;&gt;Scaling Django&lt;/a&gt; Mike Malone&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;MM from Pownce (now sixapart)&lt;/li&gt;
&lt;li&gt;Slides started out as &quot;Building Scalable Web Applications&quot;&lt;/li&gt;
&lt;li&gt;Django didn't get in the way too much when it came to scaling&lt;/li&gt;
&lt;li&gt;Django had tons of caching support&lt;/li&gt;
&lt;li&gt;Cached objects by hand (memcached) and object ID lists&lt;/li&gt;
&lt;li&gt;Use memache for sessions too&lt;/li&gt;
&lt;li&gt;use signals to signal cache invalidation&lt;/li&gt;
&lt;li&gt;race conditions...&lt;/li&gt;
&lt;li&gt;Queue shit... gearman, rabbit mq, etc.&lt;/li&gt;
&lt;li&gt;Memecached incr/decr operators are awesome&lt;/li&gt;
&lt;li&gt;See gh/mmalone/django-caching&lt;/li&gt;
&lt;li&gt;See gh:.../django-multidb&lt;/li&gt;
&lt;li&gt;to combat slavelag use a memcache key to alternate between master or slave&lt;/li&gt;
&lt;/ul&gt;


&lt;h4&gt;&lt;a href=&quot;http://heisel.org/blog/2009/09/11/gearman/&quot;&gt;Gearman - working later&lt;/a&gt; - Chris Heisel&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Gearman - a work later alt to rabbit mq&lt;/li&gt;
&lt;li&gt;Makes the most sense for something like cesium, with a bazillion worker &lt;strike&gt;bees&lt;/strike&gt; foxes feeding off a single queue&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;Also at the con, I talked to someone about rebuilding large apps... and they took a PHP app and used URL rewriting to and a lot of PHP/Python glue code to build a seamless transitory app.  The rule is, all new functionality was done up in python while the old app was in maintenance mode.&lt;/p&gt;

&lt;p&gt;More talks &lt;a href=&quot;http://djangocon.pbworks.com/Slides&quot;&gt;here&lt;/a&gt;!&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Resolving Django dumpdata errors</title>
   <link href="http://davedash.com/2009/09/13/resolving-django-dumpdata-errors/"/>
   <updated>2009-09-13T00:00:00-07:00</updated>
   <id>http://davedash.com/2009/09/13/resolving-django-dumpdata-errors</id>
   <content type="html">&lt;p&gt;Recently I recieved this wonderful piece of news when I ran &lt;code&gt;./manage.py dumpdata&lt;/code&gt; for the first time:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;Error: Unable to serialize database: User matching query does not exist.
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;I knew this might not work out since I was dealing with a legacy database, but the resolution is quite simple.  First I had to narrow it down to which app was causing this.  Naturally I assumed it was one of the two apps I had, either &lt;code&gt;common&lt;/code&gt; or &lt;code&gt;restaurant&lt;/code&gt;.  So I ran: &lt;code&gt;./manage.py dumpdata common&lt;/code&gt; and &lt;code&gt;./manage.py dumpdata restaurant&lt;/code&gt;.  The latter had no problem whatsoever.&lt;/p&gt;

&lt;p&gt;This made sense, since my &lt;code&gt;common&lt;/code&gt; application was the only one that made any reference to a &lt;code&gt;User&lt;/code&gt;.  By looking in my &lt;code&gt;models.py&lt;/code&gt; for that application, I narrowed it down to my &lt;code&gt;Profile&lt;/code&gt; object.  Sure enough, commenting it out meant I could get my data.&lt;/p&gt;

&lt;p&gt;It ended up being a foreign key mismatch between the &lt;code&gt;profile&lt;/code&gt; and &lt;code&gt;user&lt;/code&gt; tables.  Since this is legacy data, this mismatch made sense.  A simple &lt;code&gt;SELECT id,userid FROM profile WHERE userid NOT IN (SELECT id FROM auth_user)&lt;/code&gt; gave me a list of bad profiles.  Removing them allowed me to create my Django fixtures.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Automating Django Redirects</title>
   <link href="http://davedash.com/2009/03/07/automating-django-redirects/"/>
   <updated>2009-03-07T00:00:00-08:00</updated>
   <id>http://davedash.com/2009/03/07/automating-django-redirects</id>
   <content type="html">&lt;p&gt;Django has a very &lt;a href=&quot;http://docs.djangoproject.com/en/dev/ref/contrib/redirects/&quot;&gt;simple redirects system&lt;/a&gt;.  Simple as in it's easy to understand.  If someone encounters a 404, Django Redirects catches this and does a final lookup to see if there's an entry to a new URL in the redirects table.&lt;/p&gt;

&lt;p&gt;The real win, is when your &lt;code&gt;slug&lt;/code&gt; fields change (and thus the &lt;code&gt;get_absolute_url()&lt;/code&gt; of your objects), you can simply automate the creation of a redirect:&lt;/p&gt;

&lt;div&gt;&lt;textarea name=&quot;code&quot; class=&quot;python&quot;&gt;
        if self.pk:
            old_version = MyObjectClass.objects.get(pk=self.pk)
            if old_version.stripped_title != self.stripped_title:
                Redirect(site_id=1, old_path=old_version.get_absolute_url(), new_path=self.get_absolute_url()).save()


&lt;/textarea&gt;&lt;/div&gt;


&lt;p&gt;Note you must have enabled the &lt;a href=&quot;http://docs.djangoproject.com/en/dev/ref/contrib/redirects/&quot;&gt;redirects app&lt;/a&gt; before trying this.  You also need a &lt;code&gt;get_absolute_url()&lt;/code&gt; function defined for  your &lt;code&gt;MyObjectClass&lt;/code&gt;.  This is the true value of Django Middleware.  Let those truly repetitive site-wide tasks get done in one spot.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>A stitch in Fabric saves time</title>
   <link href="http://davedash.com/2009/03/02/a-stitch-in-fabric-saves-time/"/>
   <updated>2009-03-02T00:00:00-08:00</updated>
   <id>http://davedash.com/2009/03/02/a-stitch-in-fabric-saves-time</id>
   <content type="html">&lt;p&gt;Each day as I grow as a developer I pick up better habits.  One is automating anything that I'll have to do more than once.&lt;/p&gt;

&lt;p&gt;Therefore, deploying important projects has evolved:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Edit files live on the site.&lt;/li&gt;
&lt;li&gt;FTP files from my local machine onto the live site and do tweaking as needed.&lt;/li&gt;
&lt;li&gt;Develop using a cross-platform capable framework and deploy live via rsync.&lt;/li&gt;
&lt;li&gt;One step deployment.&lt;/li&gt;
&lt;/ol&gt;


&lt;p&gt;I looked at a few methods for performing one-step deployment.  Shell scripts seemed to basic, and things like Puppet seemed to large a scale.  So I looked into Capistrano and &lt;a href=&quot;http://www.nongnu.org/fab/&quot;&gt;Fabric&lt;/a&gt;, and settled on &lt;a href=&quot;http://www.nongnu.org/fab/&quot;&gt;Fabric&lt;/a&gt;, because it was barebones and python.&lt;/p&gt;

&lt;p&gt;I'm at a stage with my project where I need to test it on an external server, so rather than uploading it and winging it I actually thought about a few things.&lt;/p&gt;

&lt;!--more--&gt;


&lt;h3&gt;The task&lt;/h3&gt;

&lt;p&gt;I was thinking the ideal situation is a single command line that I can type that will upload my files to the server.  Furthermore it should upload first to a new directory and then symlink and restart the server to do the cutover.  I can easily write another script to rollback.&lt;/p&gt;

&lt;p&gt;The way I setup my Nginx and Apache servers was they would look for the symlinks: staging, test, production to serve up the respective environments (I'm using a single host for this example).&lt;/p&gt;

&lt;h3&gt;Directory Structure&lt;/h3&gt;

&lt;p&gt;I use a very particular directory structure:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;$WWW_APPS/mysite.com/&lt;/code&gt; - is my root app deployment directory.

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;releases/&lt;/code&gt; - each code push is stored in a unique directory

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;1/&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;2/&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;...&lt;/li&gt;
&lt;li&gt;&lt;code&gt;100/&lt;/code&gt; - the directory name is the &lt;code&gt;svn&lt;/code&gt; revision, but is a series of precise &lt;code&gt;svn&lt;/code&gt; exports, not a checkout.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;staging&lt;/code&gt; - this symbolic link links to a specific revision directory that has been designated for staging purposes.  This might be the last directory in &lt;code&gt;releases/&lt;/code&gt;, e.g. &lt;code&gt;$WWW_APPS/mysite.com/releases/100/&lt;/code&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;config/&lt;/code&gt; - any config files go here (e.g. nginx or apache)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;mysite.com/&lt;/code&gt; - the actual Django project&lt;/li&gt;
&lt;li&gt;&lt;code&gt;scripts/&lt;/code&gt; - any utility scripts, mostly database model changes&lt;/li&gt;
&lt;li&gt;&lt;code&gt;site-packages/&lt;/code&gt; - any related libraries that I need, this isn't the best approach I need to investigate &lt;code&gt;virtualenv&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;static/&lt;/code&gt; - all my static assets go here&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;staging.rollback&lt;/code&gt; - the former &lt;code&gt;staging&lt;/code&gt; symlink is demoted to &lt;code&gt;staging.rollback&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;$WWW/mysite.com/&lt;/code&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;staging&lt;/code&gt; - This is where the static assets get served from according to nginx.  It's a symbolic link to &lt;code&gt;$WWW_APPS/staging/static&lt;/code&gt;.  This link does not change during deployment.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;uploads_staging/&lt;/code&gt; - This directory contains uploads (user data).  It requires manual adjustment when there are data changes (deletes, adds, updates).  For the most part it can stay unchanged from one deployment to the next.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;h3&gt;Subversion&lt;/h3&gt;

&lt;p&gt;I'm currently using subversion to maintain my code.  If you are starting a project anew, I suggest using &lt;code&gt;git&lt;/code&gt; as it is designed with branching in mind.  The script below should be adaptable for &lt;code&gt;git&lt;/code&gt; instead of &lt;code&gt;svn&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;That being said, when I deploy code, I use the revision number as the directory name for that deployment (e.g. &lt;code&gt;$WWW_APPS/mysite.com/releases/100/&lt;/code&gt; for &lt;code&gt;r100&lt;/code&gt;) .&lt;/p&gt;

&lt;p&gt;This forces me to commit my changes and not deploy code that is not checked in.&lt;/p&gt;

&lt;p&gt;Other viable alternatives would be time-stamped directories.  Anything that is unique between deployments will be sufficient.&lt;/p&gt;

&lt;h3&gt;The &lt;code&gt;fabfile.py&lt;/code&gt;&lt;/h3&gt;

&lt;p&gt;Here's the &lt;code&gt;fabfile.py&lt;/code&gt; I constructed.  It's by no means final&lt;/p&gt;

&lt;div&gt;&lt;textarea name=&quot;code&quot; class=&quot;python&quot;&gt;
def staging():
    &quot;Pushes current code to staging, hups Apache&quot;
    # get the build number    
    local('svn up mysite.com')
    
    config.svn_version   = svn_get_version()
    
    if not config.svn_version:
        abort()
    
    config.static_path   = '/var/www/static.mysite.com'
    config.svn_path      = 'http://svn.mysite.com/trunk'
    config.svn_export    = 'svn export -q -r %(svn_version)s'
    
    run('mkdir %(path)s', fail='abort')
    
    # svn export mysite.com to path 
    run('%(svn_export)s %(svn_path)s/mysite.com %(path)s/mysite.com', fail='abort')
    
    # svn export site-packages to site-packages
    run('%(svn_export)s %(svn_path)s/site-packages %(path)s/site-packages', fail='abort')
    
    # svn export mysite.com to path 
    run('%(svn_export)s %(svn_path)s/scripts %(path)s/scripts', fail='warn')
    
    # svn export configs
    run('%(svn_export)s %(svn_path)s/config %(path)s/config', fail='abort')
    
    # export /var/www/static.mysite.com/releases/%(svn_version) 
    run('%(svn_export)s %(svn_path)s/static %(path)s/static', fail='abort')
    
    # symlink to images from /var/www/static.mysite.com/staging/images/menuitems/* new release dir
    run(&quot;rm -r %(path)s/static/images/menuitems&quot;, fail=abort)
    run(&quot;ln -s %(static_path)s/menuitems_staging %(path)s/static/images/menuitems&quot;, fail=abort)

    # rotate &quot;staging&quot; symlinks
    run('rm %(releases_path)s/staging.rollback', fail='warn')
    run('mv %(releases_path)s/staging  %(releases_path)s/staging.rollback', fail='warn')

    # staging sym to new destination
    run('ln -s %(path)s %(releases_path)s/staging', fail='abort')
    
    # server is hup'd
    invoke(hup)

def rm_cur_rev():
    config.svn_version   = svn_get_version()
    run('rm -rf %(path)s', fail='abort')

def hup():
    sudo('/etc/init.d/apache2 restart')
    sudo('/etc/init.d/nginx restart')
    
    
def svn_get_version():
    from subprocess import Popen, PIPE
    output = Popen([&quot;svn&quot;, &quot;info&quot;, &quot;mysite.com&quot;], stdout=PIPE).communicate()[0]
    return output.partition('Revision: ')[2].partition('\n')[0]



config.fab_hosts = ['mysite.com']
config.fab_user = 'builder'
config.releases_path = '/var/www_apps/mysite.com'
config.path          = '%(releases_path)s/releases/$(svn_version)'


&lt;/textarea&gt;&lt;/div&gt;


&lt;h3&gt;Final Thoughts&lt;/h3&gt;

&lt;p&gt;There's room for improvement, but this is a start.  &lt;code&gt;virtualenv&lt;/code&gt; looks like another avenue I might want to explore (especially when it comes time to upgrade Django, python, MysqlDB or PIL).  This also doesn't take care of priming the server with necessary packages - again, something &lt;code&gt;virtualenv&lt;/code&gt; could make easier for me.&lt;/p&gt;

&lt;p&gt;However, this file was not too difficult to create.  I sat down, thought about the ideal solution, implemented the steps and iterated on that until the script worked.  I have pushed 19 revisions of code so far, mostly to test this process, but also to make necessary adjustments.  I've probably saved countless hours of logging in and doing things manually.&lt;/p&gt;

&lt;p&gt;How do you deploy your apps?&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Resizing Image on upload in Django</title>
   <link href="http://davedash.com/2009/02/21/resizing-image-on-upload-in-django/"/>
   <updated>2009-02-21T00:00:00-08:00</updated>
   <id>http://davedash.com/2009/02/21/resizing-image-on-upload-in-django</id>
   <content type="html">&lt;p&gt;I had trouble wrapping my head around Django ORM's handling of Images.&lt;/p&gt;

&lt;p&gt;The first hurdle was realizing that
&lt;a href=&quot;/2009/02/18/database-versus-files-for-images/&quot;&gt;there is no easy way to store images in the database&lt;/a&gt;.  I couldn't be too upset with that, it was a flawed concept at best.  I wrote a dump script to fix this, and converted my app to read from disk.  One of those &quot;good&quot; problems.&lt;/p&gt;

&lt;p&gt;When it came to uploading new content... I seemed to hit every roadblock.  So I
thought this guide might be of use for people (other than future-me).  What I
want to do is upload an image, resize it per the requirements of my app, and
save the resized image.&lt;/p&gt;

&lt;!--more--&gt;


&lt;h3&gt;The Template&lt;/h3&gt;

&lt;p&gt;The template was fairly easy, yet I forgot to specify the &lt;code&gt;enctype&lt;/code&gt; attribute.
Here's what you need:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;html&quot;&gt;&lt;span class=&quot;nt&quot;&gt;&amp;lt;h2&amp;gt;&lt;/span&gt;Upload a new photo&lt;span class=&quot;nt&quot;&gt;&amp;lt;/h2&amp;gt;&lt;/span&gt;

&lt;span class=&quot;nt&quot;&gt;&amp;lt;form&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;action=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;&amp;quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;method=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;POST&amp;quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;class=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;cmxform&amp;quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;enctype=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;multipart/form-data&amp;quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;fieldset&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;ul&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;nt&quot;&gt;&amp;lt;li&amp;gt;&lt;/span&gt;
        
        &lt;span class=&quot;nt&quot;&gt;&amp;lt;label&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;for=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;id_image&amp;quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;Photo&lt;span class=&quot;nt&quot;&gt;&amp;lt;/label&amp;gt;&lt;/span&gt;
        
      &lt;span class=&quot;nt&quot;&gt;&amp;lt;/li&amp;gt;&lt;/span&gt;

    &lt;span class=&quot;nt&quot;&gt;&amp;lt;/ul&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;/fieldset&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;input&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;type=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;submit&amp;quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;value=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;Submit&amp;quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;class=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;submit&amp;quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;/&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;/form&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;h3&gt;Resizing an image&lt;/h3&gt;

&lt;p&gt;Resizing an image was straightforward.  The Python Imaging Library is very easy
to work with, and very similar to the PHP GD Library.  There was one caveat...&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;python&quot;&gt;&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;handle_uploaded_image&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
    &lt;span class=&quot;c&quot;&gt;# resize image&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;imagefile&lt;/span&gt;  &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;StringIO&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;StringIO&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;read&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;())&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;imageImage&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Image&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;open&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;imagefile&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

    &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;width&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;height&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;imageImage&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;size&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;width&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;height&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;scale_dimensions&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;width&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;height&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;longest_side&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;240&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

    &lt;span class=&quot;n&quot;&gt;resizedImage&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;imageImage&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;resize&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;width&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;height&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;

    &lt;span class=&quot;n&quot;&gt;imagefile&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;StringIO&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;StringIO&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;resizedImage&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;save&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;imagefile&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;#39;JPEG&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;c&quot;&gt;# ...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;I'm using OS X and didn't have libjpeg installed.  The recommended way was to
install it via fink.&lt;/p&gt;

&lt;h3&gt;Generating a filename&lt;/h3&gt;

&lt;p&gt;I like using MD5 to generate filenames for images because MD5 almost guarantees
uniqueness (&quot;unique enough&quot;).&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;python&quot;&gt;   &lt;span class=&quot;o&quot;&gt;...&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;filename&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;hashlib&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;md5&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;imagefile&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;getvalue&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;())&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;hexdigest&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;#39;.jpg&amp;#39;&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;h3&gt;Saving the file via the model&lt;/h3&gt;

&lt;p&gt;The model is supposed to put the files in the right spot and populate the meta data.&lt;/p&gt;

&lt;p&gt;You can supposedly do this via:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;python&quot;&gt;   &lt;span class=&quot;o&quot;&gt;...&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;my_object&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;MyDjangoObject&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;my_object&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;photo&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;save&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;filename&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;content&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;That will also take care of &lt;code&gt;my_object.save()&lt;/code&gt;.  The trick is that content
needs to be a &lt;code&gt;django.core.files.File&lt;/code&gt; object or things will never work.
Further more, you can't use a StringIO for your &lt;code&gt;File&lt;/code&gt; object.  A true file
object is best.  Hence rewriting the &lt;code&gt;JPEG&lt;/code&gt;:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;python&quot;&gt;    &lt;span class=&quot;n&quot;&gt;imagefile&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;open&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;os&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;path&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;join&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;#39;/tmp&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;filename&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;#39;w&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;resizedImage&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;save&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;imagefile&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;#39;JPEG&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;imagefile&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;open&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;os&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;path&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;join&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;#39;/tmp&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;filename&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;#39;r&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;content&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;django&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;core&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;files&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;File&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;imagefile&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;Note: I also had to reopen the imagefile.&lt;/p&gt;

&lt;h3&gt;All together now&lt;/h3&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;python&quot;&gt;&lt;span class=&quot;nd&quot;&gt;@login_required&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;my_view&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;request&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;slug&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;item_slug&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;request&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;method&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;#39;POST&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;form&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;NewImageForm&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;request&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;POST&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;request&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;FILES&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;form&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;is_valid&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;():&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;handle_uploaded_image&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;request&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;FILES&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;#39;image&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;])&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;HttpResponseRedirect&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;elsewhere&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;form&lt;/span&gt;       &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;NewImageForm&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;render_to_response&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;somewhere&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;locals&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(),&lt;/span&gt;
                              &lt;span class=&quot;n&quot;&gt;context_instance&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;RequestContext&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;request&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;handle_uploaded_image&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
    &lt;span class=&quot;c&quot;&gt;# resize image&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;imagefile&lt;/span&gt;  &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;StringIO&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;StringIO&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;read&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;())&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;imageImage&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Image&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;open&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;imagefile&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

    &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;width&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;height&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;imageImage&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;size&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;width&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;height&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;scale_dimensions&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;width&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;height&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;longest_side&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;240&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

    &lt;span class=&quot;n&quot;&gt;resizedImage&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;imageImage&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;resize&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;width&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;height&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;

    &lt;span class=&quot;n&quot;&gt;imagefile&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;StringIO&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;StringIO&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;resizedImage&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;save&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;imagefile&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;#39;JPEG&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;filename&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;hashlib&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;md5&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;imagefile&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;getvalue&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;())&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;hexdigest&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;#39;.jpg&amp;#39;&lt;/span&gt;

    &lt;span class=&quot;c&quot;&gt;# #save to disk&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;imagefile&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;open&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;os&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;path&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;join&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;#39;/tmp&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;filename&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;#39;w&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;resizedImage&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;save&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;imagefile&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;#39;JPEG&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;imagefile&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;open&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;os&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;path&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;join&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;#39;/tmp&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;filename&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;#39;r&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;content&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;django&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;core&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;files&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;File&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;imagefile&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

    &lt;span class=&quot;n&quot;&gt;my_object&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;MyDjangoObject&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;my_object&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;photo&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;save&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;filename&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;content&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;I'm sure there's room to optimize this flow.  But this gets the job done.  I do
wish I could have used a &lt;code&gt;StringIO&lt;/code&gt; instead of an actual file to save the
image.  Writing to disk twice seems silly.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Database versus files for Images</title>
   <link href="http://davedash.com/2009/02/18/database-versus-files-for-images/"/>
   <updated>2009-02-18T00:00:00-08:00</updated>
   <id>http://davedash.com/2009/02/18/database-versus-files-for-images</id>
   <content type="html">&lt;p&gt;This is a dead topic for sure, but one of the bad web development habits I had picked up was that storing everything in a database made things easier.&lt;/p&gt;

&lt;p&gt;I actually put some effort into thinking this through.  For me it was a case of management.  I didn't want to have to worry about two data stores for application-generated data.  In otherwords, the data in the database was all generated via my web application (either by myself or others who worked on the product, or by end users).  Having to also remember that there were select files as well seemed like a disaster.&lt;/p&gt;

&lt;p&gt;Most frameworks, correctly assume you'll upload files to a filesystem.  I never fully understood this until I thought about how I'd speed things up when the time comes to speed things up.  Django forces you to think that way.&lt;/p&gt;

&lt;p&gt;Almost from the start Django encourages you to:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Upload any binary content to the filesystem with pointers in a database&lt;/li&gt;
&lt;li&gt;Have a separate server, or even machine serve static content.&lt;/li&gt;
&lt;/ol&gt;


&lt;p&gt;Furthermore in a cached environment or even an environment that utilizes a CDN, putting static content in one spot, including user-generated content, was a big win.&lt;/p&gt;

&lt;p&gt;I've been porting an app from symfony to django for some time, and I had been serving images via the database.  Immediately when I switched to the filesystem I saw a huge benefit.  Not just a drop in database connections, but overall &quot;zippiness&quot; in the site.&lt;/p&gt;

&lt;p&gt;We'll see how well this performs in the real world, but I am quite sure that I learned my lesson.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Versioning Django Models</title>
   <link href="http://davedash.com/2009/02/13/versioning-django-models/"/>
   <updated>2009-02-13T00:00:00-08:00</updated>
   <id>http://davedash.com/2009/02/13/versioning-django-models</id>
   <content type="html">&lt;p&gt;In symfony, versioning a model was not terribly difficult.  I had my own specialized brute-force way of doing this.&lt;/p&gt;

&lt;p&gt;In my experience it's been a lot easier to write python code than PHP code, so naturally I figured this would be an easy task.  It was not.  I suspect that it was not easy because I have a naive understanding of Django and my symfony knowledge was fairly well grounded.&lt;/p&gt;

&lt;p&gt;I tried looking for a generic implementation of django model versioning, but failed.  So I came up with a specific solution.&lt;/p&gt;

&lt;!--more--&gt;


&lt;h3&gt;How I think of versions&lt;/h3&gt;

&lt;p&gt;For my app I chose to use a sparse versioning system.  I'd have one interface for interacting with a model.  For example, I have a &lt;code&gt;Restaurant&lt;/code&gt; model  and a &lt;code&gt;RestaurantVersion&lt;/code&gt; model.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Restaurant&lt;/code&gt; would directly store immutable elements like &lt;code&gt;name&lt;/code&gt; or &lt;code&gt;rating&lt;/code&gt; or &lt;code&gt;approved&lt;/code&gt; and it would encapsulate versioned elements like &lt;code&gt;description&lt;/code&gt; by proxying to &lt;code&gt;RestaurantVersion&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;This means I only need to interface with one class and let the versioning happen behind the scenes.&lt;/p&gt;

&lt;h3&gt;The Django implementation of &lt;code&gt;RestaurantVersion&lt;/code&gt;&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;RestaurantVersion&lt;/code&gt; held the data that I thought might suffer from corruption, and therefore require reversion.  Therefore there's nothing surprising in this table:&lt;/p&gt;

&lt;div&gt;&lt;textarea name=&quot;code&quot; class=&quot;python&quot;&gt;
class RestaurantVersion(models.Model):
    restaurant       = models.ForeignKey('Restaurant', null=True, blank=True)
    user             = models.ForeignKey(Profile, null=True, blank=True)
    description      = models.TextField(blank=True)
    html_description = models.TextField(blank=True)
    url              = models.CharField(max_length=765, blank=True)
    created_at       = models.DateTimeField(auto_now_add=True)
    
    def save(self, force_insert=False, force_update=False):
        self.html_description = markdown(self.description)
        super(RestaurantVersion, self).save(force_insert, force_update)
        
    class Meta:
        db_table = u'restaurant_version'

&lt;/textarea&gt;&lt;/div&gt;


&lt;p&gt;The only thing of note is that I'm enforcing a &lt;code&gt;1:M&lt;/code&gt; relation between &lt;code&gt;Restaurant&lt;/code&gt; and &lt;code&gt;RestaurantVersion&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;The Django implementation of &lt;code&gt;Restaurant&lt;/code&gt;&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;Restaurant&lt;/code&gt; is where the magic happens.  It needs to do a few things:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Do what a normal object does.&lt;/li&gt;
&lt;li&gt;Proxy attributes to the corresponding attribute of a &lt;code&gt;RestaurantVersion&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Generate a new &lt;code&gt;RestaurantVersion&lt;/code&gt; on demand.&lt;/li&gt;
&lt;li&gt;(optional) Manage which version is &quot;active&quot;.&lt;/li&gt;
&lt;/ol&gt;


&lt;p&gt;I say &quot;4&quot; is optional because I don't do this myself.  I built versioning into a few models because it was easier to do upfront than worry about it down the road.&lt;/p&gt;

&lt;p&gt;Here's the code I use:&lt;/p&gt;

&lt;div&gt;&lt;textarea name=&quot;code&quot; class=&quot;python&quot;&gt;

class Restaurant(models.Model):
    name           = models.CharField(max_length=765, blank=True)
    stripped_title = models.CharField(max_length=384, blank=True)
    approved       = models.IntegerField(null=True, blank=True)
    version        = models.ForeignKey(RestaurantVersion, related_name=&quot;the_restaurant&quot;)
    updated_at     = models.DateTimeField(auto_now=True)
    created_at     = models.DateTimeField(auto_now_add=True)
    new_version    = None
    
    def save(self, force_insert=False, force_update=False):
        if not self.stripped_title:
            self.stripped_title = slugify(self.name)
        
        super(Restaurant, self).save(force_insert, force_update)
        if self.new_version:
            self.new_version.restaurant = self
            self.new_version.save()
            self.version = self.new_version
            super(Restaurant, self).save(force_insert, force_update)        
        
    def __setattr__(self, name, value):
        if name == 'description':
            self.get_new_version().description = value
        
        elif name == 'url':
            self.get_new_version().url = value
        
        else:
            object.__setattr__(self, name, value)

    def __getattr__(self, name):
        try:
            if name == 'description':
                return self.version.description

            elif name == 'url':
                return self.version.url
        except RestaurantVersion.DoesNotExist:
            return ''
            
        models.Model.__getattribute__(self, name)
    
    def get_new_version(self):
        if self.new_version == None:
            try:
                rv    = self.version
                rv.id = None
            except RestaurantVersion.DoesNotExist:
                rv = RestaurantVersion()
            
            self.new_version = rv

        return self.new_version
            
    class Meta:
        db_table     = u'restaurant'
&lt;/textarea&gt;&lt;/div&gt;


&lt;p&gt;It's not rocket science, but it wasn't necessarily easy either.  Let's look at requirements 2 and 4 in a bit more detail.&lt;/p&gt;

&lt;h4&gt;Proxy attributes to the corresponding &lt;code&gt;RestaurantVersion&lt;/code&gt; attributes&lt;/h4&gt;

&lt;p&gt;Proxying attributes is a way of masking the whole versioning infrastructure from the developer.  We do this with &lt;code&gt;__getattr__&lt;/code&gt; and &lt;code&gt;__setattr__&lt;/code&gt; methods.&lt;/p&gt;

&lt;div&gt;&lt;textarea name=&quot;code&quot; class=&quot;python&quot;&gt;
    def __getattr__(self, name):
        try:
            if name == 'description':
                return self.version.description

            elif name == 'url':
                return self.version.url
        except RestaurantVersion.DoesNotExist:
            return ''
            
        models.Model.__getattribute__(self, name)
&lt;/textarea&gt;&lt;/div&gt;


&lt;p&gt;The &lt;code&gt;__getattr__&lt;/code&gt; determins if you are looking for &lt;code&gt;description&lt;/code&gt; or &lt;code&gt;url&lt;/code&gt; attributes of a &lt;code&gt;Restaurant&lt;/code&gt;.  If you are then it uses the current &lt;code&gt;RestaurantVersion&lt;/code&gt;'s attribute.&lt;/p&gt;

&lt;div&gt;&lt;textarea name=&quot;code&quot; class=&quot;python&quot;&gt;
    def __setattr__(self, name, value):
        if name == 'description':
            self.get_new_version().description = value
        
        elif name == 'url':
            self.get_new_version().url = value
        
        else:
            object.__setattr__(self, name, value)
&lt;/textarea&gt;&lt;/div&gt;


&lt;p&gt;&lt;code&gt;__setattr__&lt;/code&gt; is very similar, except since we're changing a versionable attribute we're going to make a request to a method, &lt;code&gt;get_new_version()&lt;/code&gt;, which we will detail later.  It does what it says, though, it gets the &quot;new&quot; &lt;code&gt;RestaurantVersion&lt;/code&gt; of the &lt;code&gt;Restaurant&lt;/code&gt;.&lt;/p&gt;

&lt;h4&gt;Generate a new &lt;code&gt;RestaurantVersion&lt;/code&gt; on demand&lt;/h4&gt;

&lt;p&gt;As you can see from the above code, I am &quot;auto-versioning&quot;.  This is done mostly via &lt;code&gt;get_new_version()&lt;/code&gt;.  We also have to do a few tricks to make sure the bidirectional relationship gets maintained on save.&lt;/p&gt;

&lt;div&gt;&lt;textarea name=&quot;code&quot; class=&quot;python&quot;&gt;
    def get_new_version(self):
        if self.new_version == None:
            try:
                rv    = self.version
                rv.id = None
            except RestaurantVersion.DoesNotExist:
                rv = RestaurantVersion()
            
            self.new_version = rv

        return self.new_version
&lt;/textarea&gt;&lt;/div&gt;


&lt;p&gt;&lt;code&gt;get_new_version()&lt;/code&gt; either returns the current &quot;new version&quot;, a brand new &quot;new version&quot; or a &quot;copy&quot; of the current version.&lt;/p&gt;

&lt;p&gt;The &quot;copy&quot; is done simply by setting the &lt;code&gt;id&lt;/code&gt; attribute of the new version to &lt;code&gt;None&lt;/code&gt;.  Django takes care of assigning it a new &lt;code&gt;id&lt;/code&gt; on save, thus preserving the old version.&lt;/p&gt;

&lt;p&gt;Note that when we create a brand new &lt;code&gt;RestaurantVersion&lt;/code&gt;, we don't immediately set it's &lt;code&gt;restaurant&lt;/code&gt; attribute.  That's because we haven't saved the current &lt;code&gt;restaurant&lt;/code&gt; yet.  It's a &quot;chicken and the egg&quot; problem that gets solved in our &lt;code&gt;save()&lt;/code&gt; method:&lt;/p&gt;

&lt;div&gt;&lt;textarea name=&quot;code&quot; class=&quot;python&quot;&gt;
    def save(self, force_insert=False, force_update=False):
        if not self.stripped_title:
            self.stripped_title = slugify(self.name)
        
        super(Restaurant, self).save(force_insert, force_update)
        if self.new_version:
            self.new_version.restaurant = self
            self.new_version.save()
            self.version = self.new_version
            super(Restaurant, self).save(force_insert, force_update)
        
&lt;/textarea&gt;&lt;/div&gt;


&lt;p&gt;We first save the &lt;code&gt;Restaurant&lt;/code&gt;, then we save a new version if there is one.  If we save a new version we want to update the &lt;code&gt;Restaurant&lt;/code&gt; a second time.  This ensures that there's a &lt;code&gt;1:1&lt;/code&gt; relationship between &lt;code&gt;Restaurant&lt;/code&gt; and the current &lt;code&gt;RestaurantVersion&lt;/code&gt; and it also establishes a &lt;code&gt;1:M&lt;/code&gt; relationship between &lt;code&gt;Restaurant&lt;/code&gt; and &lt;em&gt;all&lt;/em&gt; &lt;code&gt;RestaurantVersion&lt;/code&gt;s.&lt;/p&gt;

&lt;h3&gt;Conclusion and Drawbacks&lt;/h3&gt;

&lt;p&gt;While, I think that this setup works in my particular situation, I feel like it has some major flaws.&lt;/p&gt;

&lt;p&gt;The code is quite messy and very specific to this model.  My goal was to take care of this quickly, not necessarily in a reusable manner.  I also was not familiar enough with the Django model to create some sort of extension.&lt;/p&gt;

&lt;p&gt;This way of versioning does not allow for versioned attributes to be set upon instantiation of the model:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;r=Restaurant(description=&quot;Great place&quot;) 
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;won't work.  You'll have to do:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;r=Restaurant()
r.description=&quot;Great place&quot;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;I figured this was acceptable.&lt;/p&gt;

&lt;p&gt;Lastly I'm not entirely happy with having to explicitly save the &lt;code&gt;Restaurant&lt;/code&gt; model twice, but I think my bidirectional relation requires this.&lt;/p&gt;

&lt;p&gt;All in all this works in my particular situation.  I'm hoping that this can be simplified.  I'm curious to hear about other versioning schemes.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Mimic propel's update_at and created_at in Django models</title>
   <link href="http://davedash.com/2008/11/29/mimic-propels-update_at-and-created_at-in-django-models/"/>
   <updated>2008-11-29T00:00:00-08:00</updated>
   <id>http://davedash.com/2008/11/29/mimic-propels-update_at-and-created_at-in-django-models</id>
   <content type="html">&lt;p&gt;One &quot;trick&quot; that propel offers you is tables with fields &lt;code&gt;created_at&lt;/code&gt; and &lt;code&gt;updated_at&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The fields are self explanatory and within Propel you just define them and they just do their business.&lt;/p&gt;

&lt;p&gt;To simulate this in Django just do:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;updated_at = models.DateTimeField(auto_now=True)
created_at = models.DateTimeField(auto_now_add=True)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;code&gt;auto_now&lt;/code&gt; automatically sets a field to the current time, and &lt;code&gt;auto_now_add&lt;/code&gt; only does this if the object is being added (not updated).&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Django models: saving markdown</title>
   <link href="http://davedash.com/2008/11/29/django-models-saving-markdown/"/>
   <updated>2008-11-29T00:00:00-08:00</updated>
   <id>http://davedash.com/2008/11/29/django-models-saving-markdown</id>
   <content type="html">&lt;p&gt;I love markdown.  I write my blogs in markdown.  For most user text areas in my web apps I support markdown and save both the markdown and the formatted text into my data store.&lt;/p&gt;

&lt;p&gt;To do this I had to install &lt;a href=&quot;http://www.freewisdom.org/projects/python-markdown/Installation&quot;&gt;markdown for python&lt;/a&gt;.  For my Django projects I prefer downloading (or externally linking) to source code versus &lt;code&gt;easy_install&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Then you override your save model like so:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;from markdown import markdown

class MyNote(models.Model):
    def save(self, force_insert=False, force_update=False):
        self.html_note = markdown(self.note)
        super(MyNote, self).save(force_insert, force_update)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Easy.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Custom error messages for Django forms</title>
   <link href="http://davedash.com/2008/11/28/custom-error-messages-for-django-forms/"/>
   <updated>2008-11-28T00:00:00-08:00</updated>
   <id>http://davedash.com/2008/11/28/custom-error-messages-for-django-forms</id>
   <content type="html">&lt;p&gt;For some reason, it was difficult for me to find the documentation for this.  If your Django form field is required you'll by default get an error stating that 'This field is required.'  You can easily replace that when defining your form like so:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;class ReviewForm(forms.Form):
    rating = forms.ChoiceField(choices=STARS, error_messages={'required': 'Please choose a star rating'})
    note   = forms.CharField(widget=forms.Textarea(),)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;code&gt;error_messages&lt;/code&gt; is just a simple dictionary of validation messages that override the default.&lt;/p&gt;

&lt;p&gt;While this is properly documented it was not quickly searchable.  But the &lt;a href=&quot;http://docs.djangoproject.com/en/dev/ref/forms/fields/&quot;&gt;django form fields reference page&lt;/a&gt; documents this well.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>sfGuardUser -> django.contrib.auth</title>
   <link href="http://davedash.com/2008/11/20/sfguarduser-djangocontribauth/"/>
   <updated>2008-11-20T00:00:00-08:00</updated>
   <id>http://davedash.com/2008/11/20/sfguarduser-djangocontribauth</id>
   <content type="html">&lt;p&gt;If you find yourself moving from symfony to Django, here's how you &lt;code&gt;sf_guard_user&lt;/code&gt;'s user table to &lt;code&gt;django.contrib.auth&lt;/code&gt; user table:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;INSERT INTO 
    auth_user (id, username, password, is_active, last_login, date_joined)
SELECT 
    id, 
    username, 
    CONCAT(algorithm,'$', salt, '$', password), 
    1, 
    last_login, 
    created_at 
FROM sf_guard_user;

DROP TABLE sf_guard_user;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Luckily, django uses a similar salting and encryption strategy as symfony, so it's easy to go back and forth.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Django Admin and Cookies</title>
   <link href="http://davedash.com/2008/11/15/django-admin-and-cookies/"/>
   <updated>2008-11-15T00:00:00-08:00</updated>
   <id>http://davedash.com/2008/11/15/django-admin-and-cookies</id>
   <content type="html">&lt;p&gt;I was dusting off an old Django project and everything was working except the admin site:&lt;/p&gt;

&lt;blockquote&gt;&lt;p&gt;Looks like your browser isn't configured to accept cookies. Please enable cookies, reload this page, and try again.&lt;/p&gt;&lt;/blockquote&gt;

&lt;p&gt;The culprit was &lt;code&gt;SESSION_COOKIE_DOMAIN = &quot;onyxfoundation.org&quot;&lt;/code&gt; being set.&lt;/p&gt;

&lt;p&gt;The project wasn't loading into Development mode (it's triggered by hostname) so it set the cookie domain to what I require in production.  Once remedied, everything worked as expected.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Why code rewrites are often coupled with redesigns</title>
   <link href="http://davedash.com/2008/08/13/why-code-rewrites-are-often-coupled-with-redesigns/"/>
   <updated>2008-08-13T00:00:00-07:00</updated>
   <id>http://davedash.com/2008/08/13/why-code-rewrites-are-often-coupled-with-redesigns</id>
   <content type="html">&lt;p&gt;I've done some rewrites of code, and they usually are coupled with redesigns.&lt;/p&gt;

&lt;p&gt;Redesigns and rewrites are tricky.  With web sites existing users tend to prefer incremental changes with each.  Changing a design element or a feature are pretty much equivalent when its done incrementally.&lt;/p&gt;

&lt;p&gt;Usually small changes are like surgery.  You make a small change, you possibly announce it, and people look at it and usually say yes, this change is better.  But mostly a small change can go unnoticed.&lt;/p&gt;

&lt;p&gt;Tiny atomic changes are nice and they improve the product.&lt;/p&gt;

&lt;p&gt;A rewrite of code however is a discrete change.  They take forever.  Second system and all that.  They inevitably involve a redesign as well.  They tend to be received with mixed reviews.&lt;/p&gt;

&lt;p&gt;Generally a design of a site is grafted onto code.  Sometimes by templating languages, sometimes in a tightly coupled system.  In either case there's usually two options:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Make a faithful port of the design.&lt;/li&gt;
&lt;li&gt;Redesign&lt;/li&gt;
&lt;/ol&gt;


&lt;p&gt;The latter is generally preferred since this saves a lot of time.  Generally there are bugs with a design, and there is a design backlog.   A faithful port of the design would mean porting every broken HTML code, every non user-friendly element, etc.&lt;/p&gt;

&lt;p&gt;Unfortunately this leaves web developers with a scary situation: Launching a product which changes peoples functional and UI experience.&lt;/p&gt;

&lt;p&gt;The good thing is redesigns usually mean evolutionary leaps.  Meaning, iterations can happen faster, both in design and functionality.  We can easily please new customers, and we can quickly bring current customers up to speed.&lt;/p&gt;

&lt;p&gt;In my spare time, I've been rewriting code that I wrote in symfony (PHP) into django (python).  It's a tiresome long process that can easily kill a side project.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>nginx proxying to apache</title>
   <link href="http://davedash.com/2008/04/16/nginx-proxying-to-apache/"/>
   <updated>2008-04-16T00:00:00-07:00</updated>
   <id>http://davedash.com/2008/04/16/nginx-proxying-to-apache</id>
   <content type="html">&lt;p&gt;I gave up on fastcgi with NginX and django.  Too many things just didn't work, so I decided to keep Apache, but lock it down and thrown NginX in the front to serve static content and to prevent max client issues.&lt;/p&gt;

&lt;p&gt;I also applied a similar approach for symfony.  Server configurations after the jump...&lt;/p&gt;

&lt;!--more--&gt;


&lt;h3&gt;Apache&lt;/h3&gt;

&lt;p&gt;You should configure Apache as you would if you were serving directly from Apache.  In otherwords, if you are already using Apache, you don't need to do anything different, save changing a port.&lt;/p&gt;

&lt;p&gt;The one tweak I made to a standard configuration is to limit the allowed hosts to just the ones I want.&lt;/p&gt;

&lt;p&gt;Here's my django app's &lt;code&gt;apache.conf&lt;/code&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;NameVirtualHost *
&amp;lt;VirtualHost *&amp;gt;
    ServerName onyxfoundation.org

    SetEnvIf X-Magic-Header ^secret$ let_me_in
    &amp;lt;Location &quot;/&quot;&amp;gt;
            SetHandler python-program
            PythonHandler django.core.handlers.modpython
            SetEnv DJANGO_SETTINGS_MODULE onyx.settings
            PythonDebug On
            PythonPath &quot;['/var/www/django/'] + sys.path&quot;
            Order Deny,Allow
            Deny from all
            Allow from env=let_me_in
    &amp;lt;/Location&amp;gt;
&amp;lt;/VirtualHost&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Note the &lt;code&gt;SetEnvIf&lt;/code&gt; it can be set however you want, I prefer to match a specific header that I send from &lt;code&gt;nginx&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;If you are using symfony, something like this will be more appropriate:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;&amp;lt;VirtualHost *&amp;gt;
        ServerName reviewsby.us
        DocumentRoot /var/www/reviewsby.us/web
        DirectoryIndex index.php
       SetEnvIf X-Magic-Header ^secret$ let_me_in

        &amp;lt;Directory /var/www/reviewsby.us/web&amp;gt;
                Options Indexes FollowSymLinks

                RewriteEngine On

                RewriteRule ^$ index.html [QSA]
                RewriteRule ^([^.]+)$ $1.html [QSA]

                RewriteCond %{REQUEST_FILENAME} !-f
                RewriteRule ^(.*)$ index.php [QSA]
                Order Deny,Allow
                Deny from all
                Allow from env=let_me_in
        &amp;lt;/Directory&amp;gt;
&amp;lt;/VirtualHost&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;You'll also need to listen on a different port (preferably one that is not exposed to the outside world):&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;Listen 8080
&lt;/code&gt;&lt;/pre&gt;

&lt;h3&gt;NginX&lt;/h3&gt;

&lt;p&gt;Now NginX needs to be configured to do 2 things:
1. Serve all static content
2. Pass requests that need interpreting to django or symfony&lt;/p&gt;

&lt;p&gt;The Django conf of Nginx is very easy:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;server {
  listen   80;
  server_name onyxfoundation.org;

  location ^~ /static/ {
    alias        /var/www/django/onyx/static/;
    access_log   off;
    expires      30d;
  }

  location / {
    proxy_pass      http://127.0.0.1:8080/;
    proxy_redirect  off;

    proxy_set_header   Host             $host;
    proxy_set_header   X-Real-IP        $remote_addr;
    proxy_set_header   X-Forwarded-For  $proxy_add_x_forwarded_for;

    proxy_set_header        X-Magic-Header &quot;secret&quot;;
    client_max_body_size       10m;
    client_body_buffer_size    128k;

    proxy_connect_timeout      90;
    proxy_send_timeout         90;
    proxy_read_timeout         90;

    proxy_buffer_size          4k;
    proxy_buffers              4 32k;
    proxy_busy_buffers_size    64k;
    proxy_temp_file_write_size 64k;

  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The settings are trivial.  Everything that's &lt;code&gt;/static&lt;/code&gt; gets served straight from NginX and the django application is served over Apache.&lt;/p&gt;

&lt;p&gt;The same thing is a bit trickier in symfony:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;server {
  listen   80;
  server_name  reviewsby.us;

  charset utf-8;

  location  /sf/ {
    alias  /var/www/reviewsby.us/lib/vendor/symfony/data/web/sf/;
  }
  location /css/ {
    alias /var/www/reviewsby.us/web/css/;
  }
  location /images/ {
    alias /var/www/reviewsby.us/web/images/;
  }

  location /js/ {
    alias /var/www/reviewsby.us/web/js/;
  }

  location / { 
    proxy_pass http://reviewsby.us:8080/;
    proxy_redirect off;

    proxy_set_header   Host             $host;
    proxy_set_header   X-Real-IP        $remote_addr;
    proxy_set_header   X-Forwarded-For  $proxy_add_x_forwarded_for;

    proxy_set_header        X-Magic-Header &quot;secret&quot;;
    client_max_body_size       10m;
    client_body_buffer_size    128k;

    proxy_connect_timeout      90;
    proxy_send_timeout         90;
    proxy_read_timeout         90;

    proxy_buffer_size          4k;
    proxy_buffers              4 32k;
    proxy_busy_buffers_size    64k;
    proxy_temp_file_write_size 64k;
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The added difficulty with symfony is specific to this app (and most default apps) since static content is split amongst the web root (&lt;code&gt;/js&lt;/code&gt;, &lt;code&gt;/css&lt;/code&gt;, &lt;code&gt;/images&lt;/code&gt;, etc) versus the suggested django approach of throwing everything in &lt;code&gt;/static&lt;/code&gt;.  I now adopt this approach for symfony as well.  It makes everything more flexible in the long-run.&lt;/p&gt;

&lt;h3&gt;Conclusion&lt;/h3&gt;

&lt;p&gt;If you've been hesitating about putting a reverse proxy in front of Apache, hopefully this can help you out.  NginX is a lightweight fast server that can handle far more requests than Apache.  By putting it on the front-lines you can give your app that extra inch it needs to keep churning out requests.&lt;/p&gt;

&lt;p&gt;Let me know if this configuration works for you.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Star Rating using YUI (and Django)</title>
   <link href="http://davedash.com/2008/03/04/star-rating-using-yui-and-django/"/>
   <updated>2008-03-04T00:00:00-08:00</updated>
   <id>http://davedash.com/2008/03/04/star-rating-using-yui-and-django</id>
   <content type="html">&lt;p&gt;I have a very good star rater on &lt;a href=&quot;http://reviewsby.us/&quot;&gt;reviewsby.us&lt;/a&gt;, but it was written using
some sloppy prototype code.  I wanted to redo star raters in a well thought out
manner and I wanted to use &lt;a href=&quot;http://developer.yahoo.com/yui/&quot;&gt;YUI&lt;/a&gt;.  In this particular tutorial I will use
&lt;a href=&quot;http://djangoproject.com/&quot;&gt;Django&lt;/a&gt; although it is not a requirement.&lt;/p&gt;

&lt;p&gt;For some background information on star raters, see this
&lt;a href=&quot;http://developer.yahoo.com/ypatterns/pattern.php?pattern=ratinganobject&quot;&gt;Yahoo! Design Pattern&lt;/a&gt;.  Our pattern is more of a join star rater, similar
to what's found on Netflix: you see an average rating for a restaurant or dish
unless you yourself have rated it.&lt;/p&gt;

&lt;p&gt;This was a thought out design decision for our &lt;a href=&quot;http://reviewsby.us/&quot;&gt;reviewsby.us&lt;/a&gt; redesign.
Our site is primarily a personal utility that answers the question, &quot;What
dishes do I like at a particular restaurant?&quot;  If you haven't rated something
the website can only offer up an average and you can use that as a decision as
to whether you should eat something or not.&lt;/p&gt;

&lt;p&gt;If you have eaten something however, that average rating is irrelevant.  You
don't need fellow meal advisors to tell you that you liked Chicken Makhani, you
already know that for yourself.  Therefore we show only your rating unless you
haven't rated something.&lt;/p&gt;

&lt;h3&gt;Working backwards&lt;/h3&gt;

&lt;p&gt;I like to &quot;work backwards&quot; as it were.  Meaning, I like to just write the code
that I ultimately will use to output a star rater.  From there I will work on
the supporting code that is necessary.  I find by using this strategy, I can
keep my code fairly clean and organized.&lt;/p&gt;

&lt;h3&gt;The template&lt;/h3&gt;

&lt;p&gt;So ultimately I want this:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;{\% star 'mything' 3 4 '/path/to/script' %}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;To show up as this:&lt;/p&gt;

&lt;div style=&quot;text-align:center&quot;&gt;
&lt;img src=&quot;http://spindrop.us/wp-content/uploads/2008/03/starrater.png&quot; alt=&quot;starrater.png&quot; border=&quot;0&quot; width=&quot;105&quot; height=&quot;31&quot; /&gt;
&lt;/div&gt;




&lt;!--more--&gt;


&lt;p&gt;Unfortunately &lt;a href=&quot;http://www.djangoproject.com/documentation/templates/&quot;&gt;Django templates&lt;/a&gt; doesn't seem to have named attributes for &lt;a href=&quot;http://www.djangoproject.com/documentation/templates_python/&quot;&gt;template tags&lt;/a&gt;, so I'll need to explain my syntax:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;star&lt;/code&gt;: is the template tag which we define below&lt;/li&gt;
&lt;li&gt;&lt;code&gt;'mything'&lt;/code&gt;: is an id string we will use for this rater and its associated objects&lt;/li&gt;
&lt;li&gt;&lt;code&gt;3&lt;/code&gt;: this is the second argument to star, it will be the users current rating, it can also be None&lt;/li&gt;
&lt;li&gt;&lt;code&gt;4.1&lt;/code&gt;: this is the third argument, it will be the average rating, it can also be None&lt;/li&gt;
&lt;li&gt;&lt;code&gt;/path/to/script&lt;/code&gt;: is the form that will process our rating&lt;/li&gt;
&lt;/ul&gt;


&lt;h3&gt;The HTML we want&lt;/h3&gt;

&lt;p&gt;Another developer had a &lt;a href=&quot;http://www.unessa.net/en/hoyci/projects/yui-star-rating/&quot;&gt;good approach for handling star ratings&lt;/a&gt; and for handling Javascript in general.  Create an underlying Javascript-free system, and then let the Javascript make it pretty.  This is way to degrade gracefully.&lt;/p&gt;

&lt;p&gt;Ultimately, I had my own approach to this problem, I wanted much of the visual lifting to happen on the CSS layer.  So, we'll use the following code:&lt;/p&gt;

&lt;p&gt;&lt;textarea name=&quot;code&quot; class=&quot;html&quot;&gt;
&lt;span class=&quot;joint_star_rater&quot;&gt;
    &lt;form id=&quot;rater_restaurant&quot; method=&quot;post&quot; action=&quot;/restaurant/pizza-luce/rate/&quot;&gt;
        &lt;fieldset&gt;
            &lt;legend&gt;Rating&lt;/legend&gt;
            &lt;ul&gt;

        &lt;li style=&quot;width: 100px;&quot; title=&quot;5&quot; class=&quot;current meta&quot;&gt;Current Rating: 5&lt;/li&gt;


        &lt;li title=&quot;Poor&quot; class=&quot;star_1 star&quot;&gt;
            &lt;label for=&quot;restaurant_rating_1&quot;&gt;Poor&lt;/label&gt;
            &lt;input type=&quot;radio&quot; name=&quot;rating&quot; value=&quot;1&quot; id=&quot;restaurant_rating_1&quot;/&gt;
        &lt;/li&gt;

        &lt;li title=&quot;Fair&quot; class=&quot;star_2 star&quot;&gt;
            &lt;label for=&quot;restaurant_rating_2&quot;&gt;Fair&lt;/label&gt;
            &lt;input type=&quot;radio&quot; name=&quot;rating&quot; value=&quot;2&quot; id=&quot;restaurant_rating_2&quot;/&gt;
        &lt;/li&gt;

        &lt;li title=&quot;Good&quot; class=&quot;star_3 star&quot;&gt;
            &lt;label for=&quot;restaurant_rating_3&quot;&gt;Good&lt;/label&gt;
            &lt;input type=&quot;radio&quot; name=&quot;rating&quot; value=&quot;3&quot; id=&quot;restaurant_rating_3&quot;/&gt;
        &lt;/li&gt;

        &lt;li title=&quot;Very Good&quot; class=&quot;star_4 star&quot;&gt;
            &lt;label for=&quot;restaurant_rating_4&quot;&gt;Very Good&lt;/label&gt;
            &lt;input type=&quot;radio&quot; name=&quot;rating&quot; value=&quot;4&quot; id=&quot;restaurant_rating_4&quot;/&gt;
        &lt;/li&gt;

        &lt;li title=&quot;Excellent&quot; class=&quot;star_5 star&quot;&gt;
            &lt;label for=&quot;restaurant_rating_5&quot;&gt;Excellent&lt;/label&gt;
            &lt;input type=&quot;radio&quot; name=&quot;rating&quot; value=&quot;5&quot; id=&quot;restaurant_rating_5&quot;/&gt;
        &lt;/li&gt;

            &lt;/ul&gt;
        &lt;/fieldset&gt;
        &lt;input type=&quot;submit&quot; name=&quot;rate&quot; value=&quot;rate it&quot; class=&quot;submit&quot;/&gt;
    &lt;/form&gt;
&lt;/span&gt;

&lt;/textarea&gt;&lt;/p&gt;


&lt;p&gt;A couple things to note in our HTML.  Our unique string is &lt;code&gt;restaurant&lt;/code&gt;.  It's got an ID that is as unique as you want: &lt;code&gt;rater_restaurant&lt;/code&gt; where &lt;code&gt;restaurant&lt;/code&gt; was the first argument to our template tag.  We use &lt;code&gt;restaurant&lt;/code&gt; to create some other unique IDs as well.&lt;/p&gt;

&lt;p&gt;Also, this rating form makes a lot of sense semantically.  While this form in its current state is a far cry from some ajaxy goodness, it makes clear sense as to what is going on.&lt;/p&gt;

&lt;h3&gt;The template tag&lt;/h3&gt;

&lt;p&gt;Well we know what we want from the HTML side, so let's start coding our &lt;code&gt;star&lt;/code&gt; tag:&lt;/p&gt;

&lt;p&gt;&lt;textarea name=&quot;code&quot; class=&quot;python&quot;&gt;
@register.simple_tag
def star(id_string, current, average, path, spanfree=False):
    meta = None
    if current != None:
        meta = &quot;&quot;&quot;
        &lt;li class=&quot;current meta&quot; title=&quot;%d&quot; style=&quot;width:%dpx&quot;&gt;Current Rating: %d&lt;/li&gt;
        &quot;&quot;&quot; % (int(current), int(current)*20, int(current))
    else:
        meta = &quot;&quot;&quot;
        &lt;li class=&quot;average meta&quot; title=&quot;%.1f&quot; style=&quot;width:%dpx&quot;&gt;Average Rating: %.1f&lt;/li&gt;
        &quot;&quot;&quot; % (average, average*20,average)

    stars   = ''
    ratings = ['Poor', 'Fair', 'Good', 'Very Good', 'Excellent']

    for i in range(1,6):
        stars = stars + &quot;&quot;&quot;
        &lt;li class=&quot;star_%d star&quot; title=&quot;%s&quot;&gt;
            &lt;label for=&quot;%s_rating_%d&quot;&gt;%s&lt;/label&gt;
            &lt;input id=&quot;%s_rating_%d&quot; type=&quot;radio&quot; value=&quot;%d&quot; name=&quot;rating&quot;/&gt;
        &lt;/li&gt;
        &quot;&quot;&quot; % (i, ratings[i-1],id_string, i, ratings[i-1], id_string, i, i)
    html = &quot;&quot;&quot;
    &lt;form action=&quot;%s&quot; method=&quot;post&quot; id=&quot;rater_%s&quot;&gt;
        &lt;fieldset&gt;
            &lt;legend&gt;Rating&lt;/legend&gt;
            &lt;ul&gt;
            %s
            %s
            &lt;/ul&gt;
        &lt;/fieldset&gt;
        &lt;input type=&quot;submit&quot; class=&quot;submit&quot; value=&quot;rate it&quot; name=&quot;rate&quot;/&gt;
    &lt;/form&gt;
    &quot;&quot;&quot; % (path, id_string, meta,stars)
    if spanfree:
        return html
    else:
        return &quot;&quot;&quot;&lt;span class=&quot;joint_star_rater&quot;&gt;%s&lt;/span&gt;&quot;&quot;&quot; % html
    return html

&lt;/textarea&gt;&lt;/p&gt;


&lt;h3&gt;The CSS&lt;/h3&gt;

&lt;p&gt;A lot of work will happen via CSS.  The CSS will remove quite a bit of the textual data that can be interpreted graphically with stars.&lt;/p&gt;

&lt;p&gt;The strategy we use is to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;fix the &lt;code&gt;UL&lt;/code&gt; at a certain width with a background of grey stars&lt;/li&gt;
&lt;li&gt;decorate the &lt;code&gt;LI.average&lt;/code&gt; and &lt;code&gt;LI.current&lt;/code&gt; with repeating stars (blue and orange respectively) with a  &lt;code&gt;z-index&lt;/code&gt; of &lt;code&gt;1&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;decorate the &lt;code&gt;LI.average:hover&lt;/code&gt; and &lt;code&gt;LI.current:hover&lt;/code&gt; with a transparent background&lt;/li&gt;
&lt;li&gt;decorate &lt;code&gt;LI:hover input&lt;/code&gt; as a colored in star and a &lt;code&gt;z-index&lt;/code&gt; of &lt;code&gt;2&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;This might not make sense now, until you see the CSS in full action.  Also for the stars we'll use a sprite of 3 stars.  A grey defunct star as the default background, a blue star if it's the average rating for an item and an orange star if it's what the user wants.&lt;/p&gt;

&lt;p&gt;I use the following sprite:&lt;/p&gt;

&lt;div style=&quot;background: #000;text-align:center; padding:1em&quot;&gt;
&lt;img src=&quot;http://spindrop.us/wp-content/uploads/2008/03/stars.png&quot; alt=&quot;stars.png&quot; border=&quot;0&quot; width=&quot;20&quot; height=&quot;60&quot; /&gt;
&lt;/div&gt;


&lt;p&gt;The following CSS will do some magic:&lt;/p&gt;

&lt;p&gt;&lt;textarea name=&quot;code&quot; class=&quot;css&quot;&gt;
.joint_star_rater {display:inline-block;}
.joint_star_rater ul{width:100px;position:relative;height:20px;background:url(../images/icons/stars.png) repeat-x 0 0}
.joint_star_rater li.meta{position:absolute;text-indent:-9999px;display:block;z-index:1;}
.joint_star_rater ul:hover li.meta{display:none;}
.joint_star_rater li.current{background:url(../images/icons/stars.png) repeat-x 0 -40px}
.joint_star_rater li.average{background:url(../images/icons/stars.png) repeat-x 0 -20px}
.joint_star_rater li{height:20px;width:20px;position:absolute;text-indent:-9999px;z-index:3;}
.joint_star_rater li.star_2{left:20px;}
.joint_star_rater li.star_3{left:40px}
.joint_star_rater li.star_4{left:60px}
.joint_star_rater li.star_5{left:80px}
.joint_star_rater li.star_1:hover{width:20px}
.joint_star_rater li.star_2:hover{width:40px}
.joint_star_rater li.star_3:hover{width:60px}
.joint_star_rater li.star_4:hover{width:80px}
.joint_star_rater li.star_5:hover{width:100px}
.joint_star_rater li.star:hover{background:url(../images/icons/stars.png) repeat-x 0 -40px;z-index:2;left:0;}
.joint_star_rater input.submit{display:none;}
&lt;/textarea&gt;&lt;/p&gt;


&lt;p&gt;The &lt;code&gt;inline-block&lt;/code&gt; value for &lt;code&gt;display&lt;/code&gt; is not supported very well.  I recently switched to Firefox 3 Beta and it renders as expected.  Firefox 2 has problems with it.  I may revise the CSS later to accommodate it.&lt;/p&gt;

&lt;h3&gt;The Javascript&lt;/h3&gt;

&lt;p&gt;The fundamental drawback to the design here, is that it really only works well with the Javascript on.  In fact, with the CSS on and Javascript off, this code will not work very well for the end user.  This too will be revised in the future.&lt;/p&gt;

&lt;p&gt;Our Javascript needs to do something very simple:
* extract the star value you clicked on
* send it to the server
* redraw the stars&lt;/p&gt;

&lt;p&gt;It's a very simple operation, but I honestly think other libraries have an advantage to YUI in this regard.&lt;sup id=&quot;#fnr_1&quot;&gt;&lt;a href=&quot;#fn_1&quot;&gt;1&lt;/a&gt;&lt;/sup&gt;  Here's some unobtrusive code I came up with:&lt;/p&gt;

&lt;p&gt;&lt;textarea name=&quot;code&quot; class=&quot;js&quot;&gt;
var MA = {}; // MA namespace
MA.e = YAHOO.util.Event;
MA.d = YAHOO.util.Dom;
MA.c = YAHOO.util.Connect;

MA.star_rater = function() {
    var e = YAHOO.util.Event;
    var d = YAHOO.util.Dom;

    return {
        init: function() {
            e.onDOMReady(this.setup,this, true)
        },

        setup: function() {
            e.on(d.get('doc4'),'click',this.handleClick,this,true);
        },

        handleClick: function(ev) {
            var target = e.getTarget(ev);
            if (d.hasClass(target, 'star')
            &amp;&amp; d.hasClass(target.parentNode.parentNode.parentNode.parentNode, 'joint_star_rater')) {
                this.rate(target);
            }
        },

        rate: function(el) {
            if (MA.is_authenticated('Please sign in before rating =)')) {

                root   = el.parentNode.parentNode.parentNode.parentNode;
                action      = el.parentNode.parentNode.parentNode.action;
                input       = MA.d.getFirstChildBy(el, function(d) {return (d.tagName == 'input'||d.tagName=='INPUT')});
                this.value  = input.value;
                postdata    = &quot;value=&quot;+this.value;

                handleSuccess = function(o) { root.innerHTML = o.responseText }
                callback = {
                    success:handleSuccess,
                }


                var request = MA.c.asyncRequest('POST', action, callback, postdata);
                // construct a connection object to this and use it to make a post
                // retrieve the post and then replace it with the original span
            }
        },

    }
}();

MA.star_rater.init();
&lt;/textarea&gt;&lt;/p&gt;


&lt;p&gt;Note: I intentionally left out irrelevant pieces of code, like the function definition of &lt;code&gt;MA.is_authenticated()&lt;/code&gt;, this code isn't meant for cutting and pasting, it's meant for cutting-pasting and then some careful editing.&lt;/p&gt;

&lt;h3&gt;The callback view&lt;/h3&gt;

&lt;p&gt;The callback script is what you specify when you call &lt;code&gt;{\% star ... %}&lt;/code&gt;.  The view I use is as follows:&lt;/p&gt;

&lt;p&gt;&lt;textarea name=&quot;code&quot; class=&quot;python&quot;&gt;
@login_required
def rate(request, slug):
    MyObject = get_my_object()
    value    = request['value']

    MyObject,rate(value);
    return render_to_response(&quot;rating.html&quot;, locals(), context_instance=RequestContext(request))

&lt;/textarea&gt;&lt;/p&gt;


&lt;p&gt;That code is oversimplified... you have to write your own logic as it applies to our site.  The &lt;code&gt;rating.html&lt;/code&gt; is simply the call to your star tag:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;{\% load tags %}
{\% star 'mything' restaurant.current_rating restaurant.average_rating restaurant.get_rating_url 1 %}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Note the &lt;code&gt;1&lt;/code&gt; at the end.  It's a flag to turn off the outer &lt;code&gt;span&lt;/code&gt; so we can just insert the guts back into the original &lt;code&gt;span&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;Final Thoughts&lt;/h3&gt;

&lt;p&gt;The star-rater is really a large problem that's hard to tackle in one sitting and quite frankly is not documented well anywhere.  The code I've provided is a shadow of the real code I'll be using, but hopefully it's enough to get you started.&lt;/p&gt;

&lt;p&gt;I definitely will update my production code to solve a few outstanding issues, as I mentioned above.  I'll try to update this tutorial at the same time.  If there are questions about the examples given, feel free to ask and I'll attempt to answer.&lt;/p&gt;

&lt;div class=&quot;footnotes&quot;&gt;
&lt;ol&gt;
&lt;li id=&quot;fn_1&quot;&gt;YUI has the &lt;code&gt;Selector&lt;/code&gt; and that might alleviate some problems, but jQuery has very nice selection capabilities.  In this future version I keep promising, I'll use the YUI &lt;code&gt;Selector&lt;/code&gt; &lt;a href=&quot;#fnr_1&quot; class=&quot;footnoteBackLink&quot;  title=&quot;Jump back to footnote 1 in the text.&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/li&gt;&lt;/ol&gt;
&lt;/div&gt;

</content>
 </entry>
 
 <entry>
   <title>Unicode or How to deal with f'd up text in Django</title>
   <link href="http://davedash.com/2008/02/11/unicode-or-how-to-deal-with-fd-up-text-in-django/"/>
   <updated>2008-02-11T00:00:00-08:00</updated>
   <id>http://davedash.com/2008/02/11/unicode-or-how-to-deal-with-fd-up-text-in-django</id>
   <content type="html">&lt;p&gt;So I've been going out of my mind trying to figure out why something like:&lt;/p&gt;

&lt;p&gt;Pham's would look like Phamâ€™s&lt;/p&gt;

&lt;p&gt;After searching as much as I could into django and unicode, I found &lt;a href=&quot;http://automatthias.wordpress.com/2006/12/10/mysql-encoding-problems-on-dreamhost/&quot;&gt;this article&lt;/a&gt; which worked.&lt;/p&gt;

&lt;p&gt;As near as my feeble USA-centric &quot;cafes not cafés&quot; understood it, my data was encoded incorrectly, and PHP's mysql ignores encoding and expects UTF-8 whereas django tries to understand the encoding.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Enabling a debug.css in django</title>
   <link href="http://davedash.com/2008/02/11/enabling-a-debugcss-in-django/"/>
   <updated>2008-02-11T00:00:00-08:00</updated>
   <id>http://davedash.com/2008/02/11/enabling-a-debugcss-in-django</id>
   <content type="html">&lt;p&gt;I like for extra magical stuff to occur when I am in development/debug mode.  One of those magical things is a a magic &lt;code&gt;debug.css&lt;/code&gt; style sheet.&lt;/p&gt;

&lt;p&gt;Django sets a &lt;code&gt;debug&lt;/code&gt; variable when the following conditions are met:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;django.core.context_processors.debug&lt;/code&gt; is listed under &lt;code&gt;TEMPLATE_CONTEXT_PROCESSORS&lt;/code&gt; and your IP address (127.0.0.1 if your using the standard development server) is listed under &lt;code&gt;INTERNAL_IPS&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Then in your &lt;code&gt;base.html&lt;/code&gt; just add something like this:&lt;/p&gt;

&lt;div&gt;&lt;textarea name=&quot;code&quot; class=&quot;html&quot;&gt;
  
&lt;/textarea&gt;&lt;/div&gt;


&lt;p&gt;For my CSS I like to use the following:&lt;/p&gt;

&lt;div&gt;&lt;textarea name=&quot;code&quot; class=&quot;css&quot;&gt;
.incomplete { background:#c0c !important}
.incomplete .incomplete{background:#d0d !important}
.incomplete .incomplete .incomplete{background:#e0e !important}
.incomplete .incomplete .incomplete .incomplete{background:#f0f !important}
&lt;/textarea&gt;&lt;/div&gt;


&lt;p&gt;As I am developing my site, if I feel that a block of content isn't fully finished for whatever reason, I mark it with a class of &lt;code&gt;incomplete&lt;/code&gt;.  This results in a purple color (which I don't use on my site), the purpler it is... the more incomplete the content.&lt;/p&gt;

&lt;p&gt;It's like eating that stuff that makes your teeth red if you haven't brushed them enough.  Once all the purple's gone the site is ready for production.&lt;/p&gt;

&lt;p&gt;Eventually we can use all these hooks into the template to implement a symfony-style debug bar... later.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>the magic of django: get_callable</title>
   <link href="http://davedash.com/2008/02/08/the-magic-of-django-get_callable/"/>
   <updated>2008-02-08T00:00:00-08:00</updated>
   <id>http://davedash.com/2008/02/08/the-magic-of-django-get_callable</id>
   <content type="html">&lt;p&gt;&lt;a href=&quot;http://symfony-project.com/&quot;&gt;symfony&lt;/a&gt; is an amazing framework simply because of the uphill battle it has
with PHP.  There's a lot of behind the scenes magic that ameliorates the
frustrations one might have with PHPs lack of syntactical magic.&lt;/p&gt;

&lt;p&gt;A lot of work is done to make sure certain things are autoloaded and that
certain things behave the way you expect.&lt;/p&gt;

&lt;p&gt;I hadn't had a chance to peek under Django's hood too much myself, but it
appears that despite the inherent magic of python, there were some much needed
additions.  My savior for today was &lt;code&gt;get_callable&lt;/code&gt;.&lt;/p&gt;

&lt;!--more--&gt;


&lt;p&gt;I have a very particular vision of interacting with OpenID.  Basically I like
to decouple as much of the OpenID interactions away from the inner workings of
my web site.  I do, however, want a hook where I can supply some of my own
logic after OpenID has been verified.&lt;/p&gt;

&lt;p&gt;It's roughly how I implimented the sfOpenIDPlugin.   Luckily this time, I was
able to rely on the &lt;a href=&quot;http://www.openidenabled.com/openid/libraries/python/&quot;&gt;OpenID 2.1
libraries&lt;/a&gt; from
OpenIDEnabled.&lt;/p&gt;

&lt;p&gt;I did ditch their example code, because I wanted a sexy package.  The package
isn't quite ready for primetime, but you can &lt;a href=&quot;http://svn.spindrop.us/django/trunk/&quot;&gt;have a
gander&lt;/a&gt; (and yes, I do welcome
collaborators and am open to merging my work with the myriad of work that's out
there).&lt;/p&gt;

&lt;h3&gt;Getting to the point&lt;/h3&gt;

&lt;p&gt;Anyway, &lt;code&gt;get_callable&lt;/code&gt; is what allowed me to write my &quot;hook&quot; into my OpenID
logic.&lt;/p&gt;

&lt;p&gt;In my &lt;code&gt;settings.py&lt;/code&gt; I defined:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;python&quot;&gt;&lt;span class=&quot;n&quot;&gt;OPENID_SUCCESS&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;#39;myproject.myapp.views.openid_handler&amp;#39;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;The way my OpenID library works, is it does it's business and when it verifies
a url belongs to someone it then delivers he request to the &lt;code&gt;OPENID_SUCCESS&lt;/code&gt;
hook.  Here's how:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;python&quot;&gt;&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;settings&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;OPENID_SUCCESS&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;view&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;get_callable&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;settings&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;OPENID_SUCCESS&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;view&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;request&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;result&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;&lt;code&gt;get_callable&lt;/code&gt; works some python magic by splitting
&lt;code&gt;myproject.myapp.views.openid_handler&lt;/code&gt; into the module: &lt;code&gt;myproject.myapp.views&lt;/code&gt;
and the attribute &lt;code&gt;openid_handler&lt;/code&gt;.  It uses this to produce a callable object.
In the example above I gave it parameters of &lt;code&gt;request&lt;/code&gt; and &lt;code&gt;result&lt;/code&gt; as they
were required by my app.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>sfGuardUser to django.contrib.auth.models.User</title>
   <link href="http://davedash.com/2008/02/07/sfguarduser-to-djangocontribauthmodelsuser/"/>
   <updated>2008-02-07T00:00:00-08:00</updated>
   <id>http://davedash.com/2008/02/07/sfguarduser-to-djangocontribauthmodelsuser</id>
   <content type="html">&lt;p&gt;Let's pretend that your assignment was to convert a symfony app that used sfGuardAuth to a django-based system.  Wouldn't it be great if someone just gave you a bunch of SQL that you could use to convert the &lt;a href=&quot;http://symfony-project.com/&quot;&gt;symfony&lt;/a&gt; &lt;code&gt;sf_guard_user&lt;/code&gt; table to a &lt;a href=&quot;http://djangoproject.com/&quot;&gt;django&lt;/a&gt; &lt;code&gt;auth_user&lt;/code&gt; table?&lt;/p&gt;

&lt;!--more--&gt;


&lt;p&gt;Here you go:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;REPLACE INTO 
  auth_user

SELECT 
  p.id AS id, 
  replace(username, 'http://', '') AS username,
  null AS first_name,
  null AS last_name,
  email,
  concat(algorithm,'$',salt,'$',password),
  0 as is_staff,
  1 as is_active,
  0 as is_superuser, 
  last_login,
  u.created_at as date_joined


FROM 
  `sf_guard_user` u, profile p 

WHERE
  p.userid = u.id
&lt;/code&gt;&lt;/pre&gt;
</content>
 </entry>
 
 <entry>
   <title>Django circular model references</title>
   <link href="http://davedash.com/2008/02/03/django-circular-model-references/"/>
   <updated>2008-02-03T00:00:00-08:00</updated>
   <id>http://davedash.com/2008/02/03/django-circular-model-references</id>
   <content type="html">&lt;p&gt;I'm used to circular references in my model.  Often I do a versioning of an &lt;code&gt;Item&lt;/code&gt; with an &lt;code&gt;ItemVersion&lt;/code&gt;.  &lt;code&gt;Item&lt;/code&gt; will link to the latest &lt;code&gt;ItemVersion&lt;/code&gt; and &lt;code&gt;ItemVersion&lt;/code&gt; will link to the relevant &lt;code&gt;Item&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Here's how you can define your appropriate &lt;a href=&quot;http://djangoproject.com/&quot;&gt;django&lt;/a&gt; models:&lt;/p&gt;

&lt;div&gt;&lt;textarea name=&quot;code&quot; class=&quot;python&quot;&gt;
class Item(models.Model):
  id      = models.IntegerField(primary_key=True)
  version = models.ForeignKey('ItemVersion', null=True, blank=True)

class ItemVersion(models.Model):
  id   = models.IntegerField(primary_key=True)
  item = models.ForeignKey(Item, null=True, blank=True)
&lt;/textarea&gt;&lt;/div&gt;


&lt;p&gt;Note in the first model, &lt;code&gt;Item&lt;/code&gt;, we reference &lt;code&gt;ItemVersion&lt;/code&gt; in quotes because &lt;code&gt;ItemVersion&lt;/code&gt; is not yet defined.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Why Django Templating is awesome and why I get smarty again</title>
   <link href="http://davedash.com/2008/02/01/why-django-templating-is-awesome-and-why-i-get-smarty-again/"/>
   <updated>2008-02-01T00:00:00-08:00</updated>
   <id>http://davedash.com/2008/02/01/why-django-templating-is-awesome-and-why-i-get-smarty-again</id>
   <content type="html">&lt;p&gt;I get Smarty thanks to django... yeah, it's weird.&lt;/p&gt;

&lt;p&gt;Back to my &lt;a href=&quot;http://spindrop.us/2008/01/28/templating/&quot;&gt;original comment about templating&lt;/a&gt;, smarty really is trying to limit the scope of PHP in a good way.  Too often I see a lot of heavy-lifting in the templates.  It's so bad it makes my MVC'd brain explode.&lt;/p&gt;

&lt;p&gt;Django templates are very limited, based on a philosophy of keeping view logic and only view logic in the templates.&lt;/p&gt;

&lt;p&gt;This is what smart tries to do and it's a reasonable solution to the fact that PHP is a templating language with a kitchen sink.  It's saying, okay... well let's treat PHP as a programming language, and keep Smarty as the template.&lt;/p&gt;

&lt;p&gt;symfony of course says (well not really, or in any official capacity, but would you believe... frameworks talk to me), some PHP is view and some is model/controller.  We'll suggest which ones are which, but really we're not getting in the way of making your life a living hell by sticking complicated business logic inline.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Girl Geek Dinner</title>
   <link href="http://davedash.com/2008/02/01/girl-geek-dinner/"/>
   <updated>2008-02-01T00:00:00-08:00</updated>
   <id>http://davedash.com/2008/02/01/girl-geek-dinner</id>
   <content type="html">&lt;p&gt;Katie and I went to &lt;a href=&quot;http://upcoming.yahoo.com/event/408117/&quot;&gt;Girl Geek Dinner&lt;/a&gt;.  The best thing about being a Geek Husband is having a Geek Wife to bring you as a guest.&lt;/p&gt;

&lt;p&gt;The panel talk was pretty good.  Featuring:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Irene Au, Director of User Experience, Google&lt;/li&gt;
&lt;li&gt;Rashmi Sinha, CEO, SlideShare&lt;/li&gt;
&lt;li&gt;Leah Culver, Lead Developer &amp;amp; Co-Founder, Pownce&lt;/li&gt;
&lt;li&gt;Sumaya Kazi, Entrepreneur &amp;amp; Social Media Manager, Sun Microsystems&lt;/li&gt;
&lt;li&gt;Katherine Barr (moderator), Partner, Mohr Davidow Ventures&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;What really made the talk was it had a lot of good advice in general.  Writing in a blog for example is how a lot of people got their credibility.  It's how I got mine, and why I now live in the bay area and ultimately why I work on del.icio.us.&lt;/p&gt;

&lt;p&gt;The talk was really reaffirming of my move out here.  It also makes me want to code-like-mad.&lt;/p&gt;

&lt;p&gt;Following the Django theme... Pownce was written in Django ;)&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>reusability</title>
   <link href="http://davedash.com/2008/01/30/reusability/"/>
   <updated>2008-01-30T00:00:00-08:00</updated>
   <id>http://davedash.com/2008/01/30/reusability</id>
   <content type="html">&lt;p&gt;[tags]django, plugins, apps, projects, symfony[/tags]&lt;/p&gt;

&lt;blockquote&gt;&lt;p&gt;A project is a collection of settings for an instance of Django, including database configuration, Django-specific options, and application-specific settings.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;http://www.djangobook.com/en/1.0/chapter02/&quot;&gt;The Django Book, Chapter 2&lt;/a&gt;:&lt;/p&gt;&lt;/blockquote&gt;

&lt;p&gt;A few people have been asking for more comparisons between symfony and Django.  For me it's a great way of understanding Django and python as well as symfony and PHP.&lt;/p&gt;

&lt;p&gt;Reusability is at the core of Django, not an afterthought.  The only unique part of an app is the settings and the views.  Everything else is an application that can exist independently of your app.  It's nice and decoupled.&lt;/p&gt;

&lt;p&gt;This wouldn't be impossible to do in symfony.  Each module could be designed from the start as a plugin.  Complete with its own set of models and default templates.  The configuration of a project/app could then make the web app unique.&lt;/p&gt;

&lt;p&gt;Right now the bulk of my symfony models are tightly coupled to their apps.  It's a little confusing, but there isn't a direct correlation between Django projects, Django apps and symfony Projects, apps and modules.  Each kind of overlaps one another.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Templating</title>
   <link href="http://davedash.com/2008/01/28/templating/"/>
   <updated>2008-01-28T00:00:00-08:00</updated>
   <id>http://davedash.com/2008/01/28/templating</id>
   <content type="html">&lt;p&gt;[tags]smarty, symfony, php, python, django[/tags]&lt;/p&gt;

&lt;p&gt;I used to use the Smarty templating system quite heavily in my PHP apps.  Then after switching over to &lt;a href=&quot;http://symfony-project.com/&quot;&gt;symfony&lt;/a&gt;, I broke that habit.&lt;/p&gt;

&lt;p&gt;PHP &lt;em&gt;is&lt;/em&gt; a templating language for better or worse.  Smarty was a way of saying that &quot;well things could be easier&quot;, but that's against the grain of what PHP fundamentally is.&lt;/p&gt;

&lt;p&gt;One frustration of PHP is this.  A &quot;pure&quot; PHP file with no HTML looks like this:&lt;/p&gt;

&lt;div&gt;&lt;textarea name=&quot;code&quot; class=&quot;php&quot;&gt;
    &lt;?php
    
    // code goes here
    // ...
    
    // end of file
&lt;/textarea&gt;&lt;/div&gt;


&lt;p&gt;PHP is an HTML templating system, by default everything in PHP is just stuff waiting to be sent untouched to the browser.  So in essence, PHP web apps aren't really web apps... they are very complicated templates all talking to each other.&lt;/p&gt;

&lt;p&gt;So you'll note in the above example, even a pure PHP file must begin with &lt;code&gt;&amp;lt;?php&lt;/code&gt;, and signal that we're actually doing code.  In fact, to prevent any unintended whitespace being sent to the browser, a PHP only file will by convention omit the closing &lt;code&gt;?&amp;gt;&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;So my shiny new Django framework is a breath of fresh air.  There's no &lt;code&gt;&amp;lt;?py&lt;/code&gt; tags, it's all just python.  And template files are explicitly template files parsed by a template engine built on top of a scripting language.&lt;/p&gt;

&lt;p&gt;I can easily see PHP evolving into something similar one day.  Where all PHP files are just PHP by default.  It would be more in line with the way MVC development is going.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>django experiment: day 2 templates, and that's it?</title>
   <link href="http://davedash.com/2008/01/28/django-experiment-day-2-templates-and-thats-it/"/>
   <updated>2008-01-28T00:00:00-08:00</updated>
   <id>http://davedash.com/2008/01/28/django-experiment-day-2-templates-and-thats-it</id>
   <content type="html">&lt;p&gt;[tags]django, symfony[/tags]&lt;/p&gt;

&lt;p&gt;[&lt;strong&gt;Note&lt;/strong&gt;: This really does have something to do with symfony.]&lt;/p&gt;

&lt;p&gt;So I finished the tutorials on Django, but the Django tutorial is nothing compared to the Askeet Advent Calendar.  Askeet was 24 one hour tutorials that go in depth to each nook and cranny of &lt;a href=&quot;http://symfony-project.com/&quot;&gt;symfony&lt;/a&gt;, whereas I still feel like there's got to be more to Django.&lt;/p&gt;

&lt;p&gt;I get Templating now, and I really like the flexibility offered in Django.  The one major difference is the layout structure.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;http://symfony-project.com/&quot;&gt;symfony&lt;/a&gt; has this nice structure of defining a general layout, and then all following templates automatically inherit from the default layout (unless otherwise specified).  Django on the other hand requires you to explicitly extend other layouts and define regions within those layouts.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;I like the symfony style because I inherit almost always from the general template.&lt;/li&gt;
&lt;li&gt;The Django style however offers the flexibility of having subsections (which inherit from the base style) which you can inherit from.  E.g. you may have a site which has 1. a blog and 2. a gallery.  Both the blog and gallery sections share common elements from a main template, but all the pages within blog all have some unique bloggish features that the gallery lacks.&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;I've got a lot more to learn with Django, but I am enjoying it so far.&lt;/p&gt;

&lt;p&gt;I...&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;del&gt;still have to learn how to create templates.&lt;/del&gt;&lt;/li&gt;
&lt;li&gt;&lt;del&gt;want better understanding of the available field types.&lt;/del&gt;&lt;/li&gt;
&lt;li&gt;want to find a good CMS package&lt;/li&gt;
&lt;li&gt;want to know if there's the idea of environments in Django (like in symfony)&lt;/li&gt;
&lt;li&gt;want to override .save() on my models&lt;/li&gt;
&lt;li&gt;want to learn how to have self-referencing models (E.g. a hierarchical category)&lt;/li&gt;
&lt;/ul&gt;

</content>
 </entry>
 
 <entry>
   <title>python: relative paths</title>
   <link href="http://davedash.com/2008/01/27/python-relative-paths/"/>
   <updated>2008-01-27T00:00:00-08:00</updated>
   <id>http://davedash.com/2008/01/27/python-relative-paths</id>
   <content type="html">&lt;p&gt;So I started yesterday with Django, and I decided I didn't want to futz with creating another mysql database that I'd need to manage, etc.  Instead I'll just use &lt;code&gt;sqlite&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;I wanted to keep my &lt;code&gt;sqlite&lt;/code&gt; database within my project regardless of where I might move my project later.  So I did this:&lt;/p&gt;

&lt;div&gt;&lt;textarea name=&quot;code&quot; class=&quot;python&quot;&gt;
    import os        
    DATABASE_NAME = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'data/db.sqlite')        # Or path to database file if using sqlite3.
&lt;/textarea&gt;&lt;/div&gt;


&lt;p&gt;I confused a lot of people on IRC, but it's really quite easy:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;__file__&lt;/code&gt; is the filename of the current script, very similar to PHP's &lt;code&gt;__FILE__&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;os.path.abspath&lt;/code&gt; calculates the absolute path, hence the absolute path of the current file&lt;/li&gt;
&lt;li&gt;&lt;code&gt;os.path.join&lt;/code&gt; does all the nasty business of joining paths together and figuring out what type of slashes are needed, etc.&lt;/li&gt;
&lt;li&gt;'data/db.sqlite' is a string&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;So really all we were doing is creating a relative path, but setting it absolutely.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>GeoDjango</title>
   <link href="http://davedash.com/2008/01/27/geodjango/"/>
   <updated>2008-01-27T00:00:00-08:00</updated>
   <id>http://davedash.com/2008/01/27/geodjango</id>
   <content type="html">&lt;p&gt;[tags]geodjango, django, gis[/tags]&lt;/p&gt;

&lt;p&gt;I just discovered &lt;a href=&quot;http://code.djangoproject.com/wiki/GeoDjango&quot;&gt;GeoDjango&lt;/a&gt;.  The existence of this is awesome.&lt;/p&gt;

&lt;p&gt;The GIS layer of &lt;a href=&quot;http://reviewsby.us/&quot;&gt;reviewsby.us&lt;/a&gt; is incredibly complicated, and if I do another project of that magnitude, it'll be nice to know that a framework exists to tackle problems.  It looks functional, but not quite documentation complete for usage, but if I endeavor to learn more about GIS, I'm going to dive-in.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>django experiment: Day 1 and Model Inheritence</title>
   <link href="http://davedash.com/2008/01/27/django-experiment-day-1-and-model-inheritence/"/>
   <updated>2008-01-27T00:00:00-08:00</updated>
   <id>http://davedash.com/2008/01/27/django-experiment-day-1-and-model-inheritence</id>
   <content type="html">&lt;p&gt;[tags]django, inheritance[/tags]&lt;/p&gt;

&lt;p&gt;I spent a few hours diving into Django.  I knew enough python to get around, and also to be dangerous.&lt;/p&gt;

&lt;p&gt;Here's a summary of what I've learned.&lt;/p&gt;

&lt;!--more--&gt;


&lt;h3&gt;Model Inheritence&lt;/h3&gt;

&lt;p&gt;So far I've learned that &lt;a href=&quot;http://code.djangoproject.com/wiki/ModelInheritance&quot;&gt;ModelInheritence is not quite ready&lt;/a&gt;. In other words, you can't define in your &lt;code&gt;models.py&lt;/code&gt; something like this:&lt;/p&gt;

&lt;div&gt;&lt;textarea name=&quot;code&quot; class=&quot;python&quot;&gt;
from django.db import models

class ContentZone(models.Model):
  slug     = models.SlugField()
  content  = models.TextField()
  notes    = models.CharField(max_length=200)
  pub_date = models.DateTimeField('date published')
  def __unicode__(self):
    return self.slug

class Page(ContentZone):
  title    = models.CharField(max_length=200)
  def __unicode__(self):
    return self.title
&lt;/textarea&gt;&lt;/div&gt;


&lt;p&gt;The model itself will work, and it will save, but things like &lt;code&gt;Page.objects.all()&lt;/code&gt; will return empty lists.&lt;/p&gt;

&lt;h3&gt;Where I'm still shaky&lt;/h3&gt;

&lt;p&gt;I...
* still have to learn how to create templates.
* want better understanding of the available field types.
* want to find a good CMS plugin
* want to know if there's the idea of environments in Django (like in symfony)
* want to override &lt;code&gt;.save()&lt;/code&gt; on my models
* want to learn how to have self-referencing models (E.g. a hierarchical category)&lt;/p&gt;

&lt;p&gt;I'm going to keep on plugging along, it's really easy to figure out django.&lt;/p&gt;
</content>
 </entry>
 

</feed>

