<?xml version="1.0" encoding="UTF-8"?>
<rss xmlns:dc="http://purl.org/dc/elements/1.1/" version="2.0"><channel><description>David Ziegler’s personal blog of computing, math, and other heroic achievements.</description><title>David Ziegler's Blog</title><generator>Tumblr (3.0; @davidziegler)</generator><link>https://blog.davidziegler.net/</link><item><title>Django-css is dead, long live Django Compressor</title><description>&lt;p&gt;This announcement is long past due. When I originally forked django-css from django-compressor the Django landscape and state of django-compressor were very different. The main impetus for the fork was to be able to use CSS compilers and fix some outstanding bugs.&lt;/p&gt;
&lt;p&gt;Since then, django-compressor has been taken over and revitalized by &lt;a href="https://github.com/jezdez"&gt;Jannis Leidel&lt;/a&gt;. Not only is there a lot more active development, but it has a pre-compiler feature which allows you to easily plug in your favorite CSS and JS compilers. Since the original goals of django-css are now being met and surpassed by its parent, I think the responsible thing to do is officially kill django-css and recommend that people migrate to django-compressor. &lt;/p&gt;
&lt;p&gt;github: &lt;a href="https://github.com/jezdez/django_compressor"&gt;https://github.com/jezdez/django_compressor&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;documentation: &lt;a href="http://django_compressor.readthedocs.org"&gt;http://django_compressor.readthedocs.org&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;pypi: &lt;a href="http://pypi.python.org/pypi/django_compressor"&gt;http://pypi.python.org/pypi/django_compressor&lt;/a&gt;&lt;/p&gt;

&lt;br/&gt;
&lt;h3&gt;Migrating from django-css to django-compressor&lt;/h3&gt;
&lt;p&gt;For the most part, settings and usage and very similar. You should probably read the excellent &lt;a href="http://django_compressor.rtfd.org/"&gt;documentation&lt;/a&gt; before you do anything, but I just want to highlight the main difference in how django-css and django-compressor handle pre-compilation of files.&lt;/p&gt;
&lt;p&gt;Let&amp;rsquo;s assume my django-css setup looks like this:&lt;/p&gt;
&lt;p&gt;HTML:&lt;/p&gt;
&lt;pre class="prettyprint lang-html"&gt;{% load compress %}
{% compress css %}
&amp;lt;link rel="stylesheet" href="/media/css/one.css" type="text/css" charset="utf-8"&amp;gt;
&amp;lt;link rel="stylesheet" href="/media/css/two.sass" type="text/css" charset="utf-8"&amp;gt;
{% endcompress %}
&lt;/pre&gt;
&lt;p&gt;Settings.py:&lt;/p&gt;
&lt;pre class="prettyprint lang-py"&gt;COMPILER_FORMATS = {
    '.sass': {
        'binary_path':'/path/to/sass',
        'arguments': '*.sass *.css'
    }
}
&lt;/pre&gt;
&lt;p&gt;The equivalent django-compressor code would look like this:&lt;/p&gt;
&lt;p&gt;HTML:&lt;/p&gt;
&lt;pre class="prettyprint lang-html"&gt;{% load compress %}
{% compress css %}
&amp;lt;link rel="stylesheet" href="/media/css/one.css" type="text/css" charset="utf-8"&amp;gt;
&amp;lt;link rel="stylesheet" href="/media/css/two.sass" type="text/x-sass" charset="utf-8"&amp;gt;
{% endcompress %}
&lt;/pre&gt;
&lt;p&gt;Settings.py:&lt;/p&gt;
&lt;pre class="prettyprint lang-py"&gt;COMPRESS_PRECOMPILERS = (
    ('text/x-sass', 'sass {infile} {outfile}'),
)
&lt;/pre&gt;
&lt;p&gt;That&amp;rsquo;s basically it, but for more info check out the COMPRESS_PRECOMPILER setting &lt;a href="http://readthedocs.org/docs/django_compressor/en/latest/settings/#compress-precompilers"&gt;in the docs&lt;/a&gt;.&lt;/p&gt;</description><link>https://blog.davidziegler.net/post/7617900947</link><guid>https://blog.davidziegler.net/post/7617900947</guid><pubDate>Thu, 14 Jul 2011 09:57:38 -0700</pubDate></item><item><title>Graceful Degradation and Web Typography</title><description>&lt;p&gt;This is a cross-post from the &lt;a title="Codio Engineering Blog" href="http://dev.codio.com"&gt;Codio engineering blog&lt;/a&gt;, but I feel it&amp;rsquo;s justified since I wrote it: &lt;a href="http://dev.codio.com/graceful-degradation-for-non-web-standard-fon"&gt;Graceful Degradation For Non-Standard Web Fonts&lt;/a&gt;. &lt;/p&gt;</description><link>https://blog.davidziegler.net/post/2910779404</link><guid>https://blog.davidziegler.net/post/2910779404</guid><pubDate>Mon, 24 Jan 2011 10:27:36 -0800</pubDate></item><item><title>Codio Now in Beta</title><description>&lt;p&gt;&lt;a title="Codio" href="http://www.codio.com"&gt;Codio&lt;/a&gt; is now in Beta! &lt;a title="Codio goes Beta" href="http://blog.codio.com/codio-goes-beta"&gt;http://blog.codio.com/codio-goes-beta&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Things have been going pretty well so far. Since Chris is in San Francisco and I&amp;rsquo;m in Pittsburgh for the time being, we&amp;rsquo;ve been working on our own schedules and coordinating online.&lt;/p&gt;
&lt;p&gt;Pros of working in Pittsburgh: I don&amp;rsquo;t know anyone here, so there&amp;rsquo;s not much to distract me. All I do is code, work out, and sleep.&lt;/p&gt;
&lt;p&gt;Cons: It&amp;rsquo;s cold as shit, and all I do is code, work out, and sleep.&lt;/p&gt;
&lt;p&gt;I don&amp;rsquo;t want this to become a blog about Codio, so barring an IPO or acquisition I&amp;rsquo;ll try not to mention it here anymore. If you want to follow Codio&amp;rsquo;s progress check out our &lt;a title="Codio Blog" href="http://blog.codio.com"&gt;blog&lt;/a&gt; and &lt;a title="Codio Twitter" href="http://twitter.com/codiohq"&gt;twitter account&lt;/a&gt;. &lt;/p&gt;</description><link>https://blog.davidziegler.net/post/2312252876</link><guid>https://blog.davidziegler.net/post/2312252876</guid><pubDate>Tue, 14 Dec 2010 05:27:00 -0800</pubDate></item><item><title>django-urlcrypt now with RSA</title><description>&lt;p&gt;&lt;a href="http://www.reddit.com/r/django/comments/e040c/djangourlcrypt/c148io3"&gt;Someone on Reddit&lt;/a&gt; pointed out that our url obfuscation method for &lt;a title="django-urlcrypt" href="https://github.com/dziegler/django-urlcrypt"&gt;django-urlcrypt&lt;/a&gt; was rather simplistic. We already kind of new this, and that if someone was able to figure out the obfuscation key then they&amp;rsquo;d be able to decode the urls to get someone&amp;rsquo;s hashed password. I don&amp;rsquo;t think that&amp;rsquo;s the end of the world because the password is still sha1 hashed, but it&amp;rsquo;s certainly not ideal.&lt;/p&gt;
&lt;p&gt;So with &lt;a title="django-css" href="http://pypi.python.org/pypi/django-urlcrypt/0.1.4"&gt;0.1.4&lt;/a&gt; Chris added an option to use RSA to encrypt the url tokens, and we&amp;rsquo;re not including the hashed passwords as info that we&amp;rsquo;re encrypting. From the end user&amp;rsquo;s perspective the only difference is that if the user changes their password, the old links will still be valid.&lt;/p&gt;
&lt;p&gt;If you want to use RSA, which is recommended, just add &lt;/p&gt;
&lt;pre&gt;URLCRYPT_PRIVATE_KEY_PATH = '/path/to/private_key'&lt;/pre&gt;
&lt;p&gt;in your settings.&lt;/p&gt;</description><link>https://blog.davidziegler.net/post/1494593948</link><guid>https://blog.davidziegler.net/post/1494593948</guid><pubDate>Sat, 06 Nov 2010 00:11:47 -0700</pubDate></item><item><title>django-urlcrypt</title><description>&lt;p&gt;&lt;a href="http://github.com/dziegler/django-urlcrypt"&gt;http://github.com/dziegler/django-urlcrypt&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a title="Christopher Hesse" href="http://twitter.com/cshesse"&gt;Chris&lt;/a&gt; and I just open sourced &lt;a href="http://github.com/dziegler/django-urlcrypt"&gt;django-urlcrypt&lt;/a&gt;, a Django app for encrypting information in urls. The main use case for this is when you want to give a user a url that logs the user in, and redirects them to some url. &lt;/p&gt;
&lt;p&gt;For example if I want to email users a link that logs them in and sends them to &lt;a href="http://www.davidziegler.net/inbox/,"&gt;http://www.davidziegler.net/inbox/,&lt;/a&gt; I would send them something like &lt;a href="http://www.davidziegler.net/r/TkNJBkNFAghDWkdFGPUAQEfcDUJfEBIREgEUFl1BQ"&gt;http://www.davidziegler.net/r/TkNJBkNFAghDWkdFGPUAQEfcDUJfEBIREgEUFl1BQ&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Some desired properties of this url are that &lt;/p&gt;
&lt;p&gt;1. User X can&amp;rsquo;t construct a url that logs him in as User Y&lt;/p&gt;
&lt;p&gt;2. If User X changes his password, it should invalide all of the old login ursl.&lt;/p&gt;
&lt;p&gt;3. The url should be relatively obfuscated so it&amp;rsquo;s not totally obvious what we&amp;rsquo;re doing.&lt;/p&gt;
&lt;h3&gt;Usage&lt;/h3&gt;
&lt;p&gt;There&amp;rsquo;s more in depth examples in the README, but basically it works like this:&lt;/p&gt;
&lt;pre class="prettyprint lang-py"&gt;from django.core.urlresolvers import reverse
from urlcrypt import lib as urlcrypt

token = urlcrypt.generate_login_token(user, reverse('message_inbox'))
encoded_url = reverse('urlcrypt_redirect', args=(token,))&lt;/pre&gt;
&lt;p&gt;Or in a template, &lt;/p&gt;
&lt;pre class="prettyprint lang-html"&gt;{% load urlcrypt_tags %}

&amp;lt;a href="{% encoded_url user message_inbox %}"&amp;gt; 
    click me to log in as {{user.username}} and go to {% url message_inbox %} 
&amp;lt;/a&amp;gt;
&lt;/pre&gt;
&lt;p&gt;Basically it uses &lt;a href="http://docs.python.org/library/hmac.html"&gt;hmac&lt;/a&gt; to create a hash using your SECRET_KEY from settings.py, the user&amp;rsquo;s hashed password, id, and timestamp. For details, check out &lt;a href="http://github.com/dziegler/django-urlcrypt/blob/master/urlcrypt/lib.py"&gt;urlcrypt/lib.py in the source&lt;/a&gt;. It&amp;rsquo;d be relatively straight forward adapt to other frameworks but I just haven&amp;rsquo;t had the need to do so yet.&lt;/p&gt;
&lt;p&gt;I guess we could have just used public key encryption too&amp;hellip;but &lt;strike&gt;pycrypto is a pain to install&lt;/strike&gt; (EDIT: oops, I was thinking of python-mcrypt. Maybe someday we&amp;rsquo;ll implement public key encryption). Of course, crypto is hard and it&amp;rsquo;s possible that there&amp;rsquo;s some glaring security hole in there that we missed, so please let us know if you find one or send us a patch on github.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;update (11/6/10): &lt;a href="http://blog.davidziegler.net/post/1494593948/django-urlcrypt-now-with-rsa"&gt;django-urlcrypt now with RSA&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;</description><link>https://blog.davidziegler.net/post/1429956249</link><guid>https://blog.davidziegler.net/post/1429956249</guid><pubDate>Thu, 28 Oct 2010 23:56:00 -0700</pubDate></item><item><title>Codio Alpha Launch</title><description>&lt;p&gt;Hiring is one of those topics you constantly hear people gripe about. I&amp;rsquo;ve been on both sides of the fence and know how hard it is to find top talent and how frustrating it can be to get lost in a stack of resumes because you didn&amp;rsquo;t include the right buzz words and acronyms.&lt;/p&gt;
&lt;p&gt;&lt;a title="Codio" href="http://www.codio.com"&gt;Codio&lt;/a&gt; is an attempt to improve the technical hiring process. Companies post jobs and specify what programming languages they&amp;rsquo;d like candidates to be tested on. When a candidate applies for a job, they&amp;rsquo;ll be scored on an adaptive set of tests in that language. All keyboard input is recorded so whoever reviews the submissions can playback the solution and see how the applicant arrived at their answer.&lt;/p&gt;
&lt;p&gt;We&amp;rsquo;re hoping this allows companies to screen people who are obviously terrible coders without wasting time on a phone screen or in-person interview, and gives non-technical people a better metric to judge engineers, since 90% of resumes are useless.&lt;/p&gt;
&lt;p&gt;This is only an alpha release so there are probably bugs, but we&amp;rsquo;re iterating quickly to clean things up and add new features. My co-founder &lt;a href="http://twitter.com/cshesse"&gt;Chris&lt;/a&gt; and I are so excited about Codio that we&amp;rsquo;re leaving Mingle to work on it full time starting in November.&lt;/p&gt;
&lt;p&gt;If you&amp;rsquo;re a company or recruiter and you&amp;rsquo;d like to try it out, signup at &lt;a title="Codio" href="http://www.codio.com"&gt;http://www.codio.com&lt;/a&gt; using the code &amp;lsquo;daveblog&amp;rsquo;. Everything is free right now and when we solidify our pricing model, early adopters will get grandfathered in at a free or discounted rate. &lt;/p&gt;
&lt;p&gt;Feel free to send any feedback or problems you have to &lt;a href="mailto:%20david@codio.com"&gt;david@codio.com&lt;/a&gt;.&lt;/p&gt;</description><link>https://blog.davidziegler.net/post/1386077270</link><guid>https://blog.davidziegler.net/post/1386077270</guid><pubDate>Sat, 23 Oct 2010 20:15:00 -0700</pubDate></item><item><title>Python Books</title><description>&lt;p class="p1"&gt;My dad recently asked me for a good book to learn Python, causing my heart to swell with pride. I&amp;rsquo;m pretty sure the last programming language he learned was &lt;a href="http://twitter.com/#!/tia_marie/status/26136725483"&gt;Fortran&lt;/a&gt;, since that&amp;rsquo;s what they&amp;rsquo;ve been using for the past zillion years in his department at GE. He once told me that he&amp;rsquo;s gotten to the age where every new thing he learns causes something else to get deleted, but I think Python is worth giving up his memories of my crappy piano recitals.&lt;/p&gt;
&lt;p class="p1"&gt;Coincidentally I was asked not too long ago to review the books &lt;a title="Python Multimedia" href="http://www.amazon.com/gp/product/1849510164?ie=UTF8&amp;amp;tag=wwwdavidziegl-20&amp;amp;linkCode=as2&amp;amp;camp=1789&amp;amp;creative=390957&amp;amp;creativeASIN=1849510164"&gt;Python Multimedia&lt;/a&gt; and &lt;a title="MySQL for Python" href="http://www.amazon.com/gp/product/1849510180?ie=UTF8&amp;amp;tag=wwwdavidziegl-20&amp;amp;linkCode=as2&amp;amp;camp=1789&amp;amp;creative=390957&amp;amp;creativeASIN=1849510180"&gt;MySQL for Python&lt;/a&gt;. MySQL for Python hasn&amp;rsquo;t been published yet, but I&amp;rsquo;m looking forward to reading it because we use MySQL at Mingle, and to be honest, my MySQL knowledge is not the greatest. If it wasn&amp;rsquo;t for John and Glen the database server would probably be on fire actually.&lt;/p&gt;
&lt;p class="p1"&gt;When I&amp;rsquo;m done with Python Multimedia I&amp;rsquo;ll post a full review.&lt;/p&gt;
&lt;p class="p1"&gt;Full disclosure: I received a free electronic copy of Python Multimedia and the amazon links are affiliate links (have to get my laundry money somehow).&lt;/p&gt;
&lt;p class="p1"&gt;&lt;a title="Python Multimedia" href="http://www.packtpub.com/python-multimedia-application-beginner's-guide/book?utm_source=blog.davidziegler.net&amp;amp;utm_medium=bookrev&amp;amp;utm_content=blog&amp;amp;utm_campaign=mdb_004876%20"&gt;&lt;figure class="tmblr-full" data-orig-height="617" data-orig-width="500"&gt;&lt;img src="https://64.media.tumblr.com/b2c2c731ab810c02b9a472ddfd3a795e/321353e1a835135e-35/s540x810/9f749cc3df1e42c71becea337432ef1d466fb4ca.jpg" data-orig-height="617" data-orig-width="500"/&gt;&lt;/figure&gt;&lt;/a&gt;&lt;/p&gt;</description><link>https://blog.davidziegler.net/post/1244081466</link><guid>https://blog.davidziegler.net/post/1244081466</guid><pubDate>Mon, 04 Oct 2010 13:12:00 -0700</pubDate></item><item><title>Life Update</title><description>&lt;p&gt;It&amp;rsquo;s been a while since I&amp;rsquo;ve written here because my life has been pretty busy lately. Here&amp;rsquo;s the rundown:&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;m splitting my time between Palo Alto and Pittsburgh. Helen is doing a &lt;a href="http://www.mpd.cmu.edu/"&gt;MS in product design at CMU&lt;/a&gt; so I decided to move to Pittsburgh with her. Her program is only a year long, and we plan on moving back to the bay area in May. I&amp;rsquo;m still working full time at &lt;a href="http://www.mingle.com"&gt;Mingle&lt;/a&gt;, and they&amp;rsquo;ve been generous enough to fly me back to Palo Alto roughly every two weeks to work face to face with the rest of the team. &lt;/p&gt;
&lt;p&gt;That means a lot of traveling, which is good and bad. Flying sucks, but living in two places at once is kind of fun. I&amp;rsquo;ve only been doing this for about a month, so we&amp;rsquo;ll see how long I can keep it up.&lt;/p&gt;
&lt;p&gt;I want to publicly announce that I&amp;rsquo;m working on a project called cod.io, and that I hope to release it in private beta in the next two weeks. This is mainly just to give me an incentive to keep it on schedule, so if you want more info about it just wait until then or send me an email. &lt;/p&gt;
&lt;p&gt;Minor updates:&lt;/p&gt;
&lt;ul&gt;&lt;li&gt;I&amp;rsquo;ll be at &lt;a href="http://startupschool.org/"&gt;Startup School&lt;/a&gt; on Oct. 16th&lt;/li&gt;
&lt;li&gt;Djangocon 2010 was &lt;a href="http://sunlightlabs.com/blog/2010/djangocon-2010-and-conferences/"&gt;meh&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;My cat &lt;a href="http://sphotos.ak.fbcdn.net/hphotos-ak-ash1/hs448.ash1/24712_918484572403_1200606_50546023_5820301_n.jpg"&gt;Lucifer&lt;/a&gt; died of liver failure&lt;/li&gt;
&lt;/ul&gt;</description><link>https://blog.davidziegler.net/post/1232169663</link><guid>https://blog.davidziegler.net/post/1232169663</guid><pubDate>Sat, 02 Oct 2010 19:30:17 -0700</pubDate></item><item><title>Some Common Django ORM Pitfalls</title><description>&lt;p&gt;For the most part, I like the Django ORM because it makes it easy to write reusable code that reads and writes from the database. I&amp;rsquo;ve found that the ORM can be a double edged sword though, as it sometimes becomes &lt;em&gt;too&lt;/em&gt; easy to read and write from the database. In hindsight, most of the following mistakes are pretty obvious once you understand how the ORM works, but I still see these all the time so I thought it&amp;rsquo;d be good to point them out. If you want a more basic guide to Django model and querying patterns, &lt;a href="http://www.ibm.com/developerworks/opensource/library/os-django-models/index.html"&gt;Better Django Models&lt;/a&gt; is a great article for that, so I won&amp;rsquo;t reiterate the points made in there.&lt;/p&gt;
&lt;p&gt;For the following examples, I&amp;rsquo;ll be using these models:&lt;/p&gt;
&lt;pre class="prettyprint lang-py"&gt;
class Book(models.Model):
    author = models.ForeignKey(User)
    
class Profile(models.Model):
    user = models.ForeignKey(User)
&lt;/pre&gt;
&lt;br/&gt;
&lt;h2&gt;1. book.author does a database query&lt;/h2&gt;
&lt;p&gt;OK, this is pretty basic, but it has a bunch of implications, such as:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;book.author.id != book.author_id&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Well, the values returned will be the same, but book.author.id does an additional database query. There is pretty much never a good reason to do book.author.id unless you know for sure that you&amp;rsquo;re accessing an internally cached instance, either obtained from &lt;a href="http://docs.djangoproject.com/en/1.1/ref/models/querysets/#id4"&gt;select_related&lt;/a&gt; or because you&amp;rsquo;ve already accessed book.author and created a cached instance, but even then, why chance it?&lt;/p&gt;
&lt;p&gt;For the same reason,&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;this is bad&lt;/strong&gt;&lt;/p&gt;
&lt;pre class="prettyprint lang-py"&gt;
book = Book()
book.author = profile.user
book.save()
&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;and this is good&lt;/strong&gt;&lt;/p&gt;
&lt;pre class="prettyprint lang-py"&gt;
book = Book()
book.author_id = profile.user_id
book.save()
&lt;/pre&gt;
&lt;br/&gt;

&lt;h2&gt;2. Querysets are not lists&lt;/h2&gt;
&lt;p&gt;How many database queries is this?&lt;/p&gt;
&lt;pre class="prettyprint lang-py"&gt;
books = Book.objects.all()
print books[0]
print books[1]
&lt;/pre&gt;
&lt;p&gt;The answer is 2, one for each slice. It&amp;rsquo;s much easier to see that this is 2 separate queries once you realize that the above is essentially equivalent to&lt;/p&gt;
&lt;pre class="prettyprint lang-py"&gt;
print Book.objects.all()[0]
print Book.objects.all()[1]
&lt;/pre&gt;
&lt;p&gt;This result is a combination of Django&amp;rsquo;s querysets being lazy, meaning they won&amp;rsquo;t be evaluated until they&amp;rsquo;re accessed, and because a queryset&amp;rsquo;s internal cache doesn&amp;rsquo;t get populated unless you iterate through the queryset. If we do:&lt;/p&gt;
&lt;pre class="prettyprint lang-py"&gt;
books = Book.objects.all()
for book in books:
    print book
print books[0]
print books[1]
&lt;/pre&gt;
&lt;p&gt;This will result in one database query because by iterating through the queryset, the internal cache will get populated and books[0] and books[1] will simply access the internal cache (I don&amp;rsquo;t recommend iterating through the entire queryset if you only need the first two books, I&amp;rsquo;m just trying to make a point).&lt;/p&gt;

&lt;br/&gt;

&lt;h2&gt;3. Use iterator() when you don&amp;rsquo;t need or want the internal queryset cache&lt;/h2&gt;
&lt;p&gt;As I just mentioned, iterating through the queryset will populate the internal cache. Sometimes though, the internal cache may not be desirable. For example if we have one million users:&lt;/p&gt;
&lt;pre class="prettyprint lang-py"&gt;
users = User.objects.all()
for user in users:
    print user.username
&lt;/pre&gt;
&lt;p&gt;this will load one million users into memory because users internal cache will be populated. The &lt;a href="http://docs.djangoproject.com/en/1.1/ref/models/querysets/#iterator"&gt;iterator() method&lt;/a&gt; will tell the queryset not to populate the internal cache, which can significantly reduce memory usage and increase performance. &lt;/p&gt;
&lt;pre class="prettyprint lang-py"&gt;
users = User.objects.all()
for user in users.iterator()
    print user.username
&lt;/pre&gt;
&lt;p&gt;Even for smaller querysets, it&amp;rsquo;s not a bad idea to use the iterator() method if you know you&amp;rsquo;re not going to reuse the queryset.&lt;/p&gt;

&lt;br/&gt;

&lt;h2&gt;4. Be careful with model properties/methods that do database lookups&lt;/h2&gt;
&lt;pre class="prettyprint lang-py"&gt;
class Profile(models.Model):
    
    user = models.ForeignKey(User)
    
    @property
    def username(self):
        return self.user.username
&lt;/pre&gt;
&lt;p&gt;There&amp;rsquo;s nothing necessarily wrong about this, but it&amp;rsquo;s dangerous to expose properties or methods that hide database lookups. Especially if you&amp;rsquo;re working with designers who may not know what your schema looks like, exposing properties like this makes it easy to do:&lt;/p&gt;
&lt;pre class="prettyprint lang-py"&gt;
{% for profile in profiles %}
    &amp;lt;li&amp;gt;{{ profile.username }}&amp;lt;/li&amp;gt;
{% endfor %}
&lt;/pre&gt;
&lt;p&gt;whereas it&amp;rsquo;s much easier to see that&lt;/p&gt;
&lt;pre class="prettyprint lang-py"&gt;
{% for profile in profiles %}
    &amp;lt;li&amp;gt;{{ profile.user.username }}&amp;lt;/li&amp;gt;
{% endfor %}
&lt;/pre&gt;
&lt;p&gt;will do N User lookups. If for some reason you find that you do need to create a property that does a database lookup, make it private.&lt;/p&gt;
&lt;pre class="prettyprint lang-py"&gt;
class Profile(models.Model):
    
    user = models.ForeignKey(User)
    
    @property
    def _username(self):
        return self.user.username
&lt;/pre&gt;
&lt;p&gt;Private methods can&amp;rsquo;t be used in templates, so it becomes much harder for a designer to shoot your site in the foot.&lt;/p&gt;

&lt;p&gt;Hopefully this was helpful for someone. Feel free to comment, &lt;a href="http://feeds2.feedburner.com/DavidZieglersBlog"&gt;subscribe&lt;/a&gt;, or &lt;a href="http://twitter.com/david_ziegler"&gt;follow me on twitter&lt;/a&gt;.&lt;/p&gt;</description><link>https://blog.davidziegler.net/post/548363214</link><guid>https://blog.davidziegler.net/post/548363214</guid><pubDate>Sun, 25 Apr 2010 09:19:00 -0700</pubDate></item><item><title>Announcing django-cachebot</title><description>&lt;blockquote&gt;
&lt;p&gt;&amp;ldquo;There are only two hard things in Computer Science: cache invalidation and naming things.&amp;rdquo; —&lt;a href="http://people.famouswhy.com/phil%5Fkarlton/"&gt;Phil Karlton&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Over the past couple weeks I&amp;rsquo;ve been working on a Django app to do automated caching and invalidation. The basic usage follows like this:&lt;/p&gt;
&lt;pre class="prettyprint lang-py"&gt;Photo.objects.cache().filter(user=user, status=2)
&lt;/pre&gt;
&lt;p&gt;Anything I would say here would mostly be a repeat of the documentation I wrote, so you should just check it out for yourself: &lt;a href="http://github.com/dziegler/django-cachebot"&gt;http://github.com/dziegler/django-cachebot&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Be sure read the caveats. We&amp;rsquo;re using this in production at mingle.com, but it&amp;rsquo;s an early stage project so it&amp;rsquo;s possible that there are edge cases that I&amp;rsquo;ve missed. That being said, since we&amp;rsquo;re using it in production, I will try to fix any bugs as soon as I can. If you&amp;rsquo;re familiar with Django internals or feeling adventurous, feel free to take a look at the source and send me some feedback on how it could be improved.&lt;/p&gt;
&lt;p&gt;Also, as a followup to Phil Karlton&amp;rsquo;s second point, I was thinking of naming this Sir-Cache-a-Lot, but thought that would be too hard to import, so I went with django-cachebot.&lt;/p&gt;</description><link>https://blog.davidziegler.net/post/429237463</link><guid>https://blog.davidziegler.net/post/429237463</guid><pubDate>Fri, 05 Mar 2010 17:28:57 -0800</pubDate></item><item><title>Test Database Settings in Django</title><description>&lt;p&gt;For early stage local development with Django, I typically use sqlite. It&amp;rsquo;s easy to setup, delete the database if I need to, etc. Later on though, I find that it&amp;rsquo;s a good idea to switch my local database to whatever I&amp;rsquo;m using in production (postgresql, mysql, etc), either because I want to make sure that my schema migrations work, or I might have some custom non-database agnostic SQL written for an app.&lt;/p&gt;
&lt;p&gt;The problem is that if you&amp;rsquo;re not using sqlite, Django tests run incredibly slow. With sqlite, Django will use an in-memory database for testing that is an order of magnitude faster than mysql or postgresql.&lt;/p&gt;
&lt;p&gt;For some reason there’s no way to specify your test database engine in settings.py, but if you do the following settings hack you can use the in-memory database as your test database.&lt;/p&gt;
&lt;p&gt;Create a file called settings_test.py that contains:&lt;/p&gt;
&lt;pre class="prettyprint lang-py"&gt;from settings import *

DATABASE_ENGINE = 'sqlite3'
DATABASE_NAME = 'dev.db' 
DATABASE_USER = ''   
DATABASE_PASSWORD = ''         
DATABASE_HOST = ''         
DATABASE_PORT = '' 
&lt;/pre&gt;
&lt;p&gt;And when running tests just do:&lt;/p&gt;
&lt;pre class="prettyprint lang-bash"&gt;python manage.py test --setting=settings_test
&lt;/pre&gt;
&lt;p&gt;You can obviously include other variables in this file if you want create some test specific behavior. For example, if you have a signal that makes an API call to some remote server everytime you create a user, you might not want to do this during testing. The simple way to deal with this would be to create a variable called RUNNING_TESTS and default it to False in settings.py and set it to TRUE in settings_test.py.&lt;/p&gt;
&lt;p&gt;Hopefully now you have one less excuse for writing unit tests, and the people who inherit your code won&amp;rsquo;t have to track you down and strangle you.&lt;/p&gt;</description><link>https://blog.davidziegler.net/post/370368042</link><guid>https://blog.davidziegler.net/post/370368042</guid><pubDate>Thu, 04 Feb 2010 02:21:05 -0800</pubDate></item><item><title>See Which Twitterers Don’t Follow You Back (updated)</title><description>&lt;p&gt;It turns out that if you were following more than 100 people or had more than 100 followers, there was a bug in my &lt;a href="http://blog.davidziegler.net/post/107429458/see-which-twitterers-don-t-follow-you-back-in-less-than"&gt;script to check who on Twitter doesn&amp;rsquo;t follow you back&lt;/a&gt;. Since I&amp;rsquo;m not super popular and have less than 100 for both, it took me a while to figure this out.&lt;/p&gt;
&lt;p&gt;The getFriends and getFollowers api methods in python-twitter are paginated to 100 results per call, so I needed to modify the script to loop over the paginated results. If I was doing anything more complicated I&amp;rsquo;d probably use tweepy because it&amp;rsquo;s a more robust api wrapper, but whatever.&lt;/p&gt;
&lt;p&gt;Also, my follower/followee count is still less than 100, so feel free to let me know if this doesn&amp;rsquo;t work, or &lt;a href="http://twitter.com/david_ziegler"&gt;follow me an twitter&lt;/a&gt; so I can test it myself :)&lt;/p&gt;
 
&lt;script src="http://gist.github.com/271926.js?file=twit_heathens_2.py"&gt;&lt;/script&gt;</description><link>https://blog.davidziegler.net/post/323078951</link><guid>https://blog.davidziegler.net/post/323078951</guid><pubDate>Fri, 08 Jan 2010 01:16:39 -0800</pubDate></item><item><title>Programming Gloves</title><description>&lt;p&gt;Unfortunately a lot of the code I&amp;rsquo;m working on is on &lt;a href="http://twitter.com/david_ziegler/status/6265474555"&gt;lock down at the moment&lt;/a&gt;, but I thought that since it&amp;rsquo;s winter, I&amp;rsquo;d share a little trick to keep your hands warm during those cold late night coding sessions.&lt;/p&gt;
&lt;p&gt;If you&amp;rsquo;re like me, you&amp;rsquo;re unnecessarily frugal. This means wearing 3 layers of clothes, a blanket, and maybe even a snuggie before thinking about turning on the heat. Unfortunately, computer work requires finger mobility which generally leaves my hands exposed while I&amp;rsquo;m working. It used to get so cold that my hands would be in physical pain unless I stopped every 5 minutes to sit on them to warm them up.&lt;/p&gt;
&lt;p&gt;&lt;a title="hobo gloves" href="http://www.wetcanvas.com/Articles2/532/552/images/coldweather_glove.jpg"&gt;Hobo gloves&lt;/a&gt; would probably work, except they come up a little too high on your fingers to type, and I don&amp;rsquo;t have a pair of gloves lying around to cut the fingers off (obviously, my unnecessary frugality prevents me from buying them). So if you&amp;rsquo;re like me and cheaper than a hobo, you can make some fancy fingerless gloves out of old socks.&lt;/p&gt;
&lt;p&gt;Just cut 5 holes on the end, and you&amp;rsquo;re done. I recommend thick socks obviously to keep your hands warmer, and black socks are probably a little more stylish.&lt;/p&gt;
&lt;p&gt;&lt;figure class="tmblr-full" data-orig-height="375" data-orig-width="500"&gt;&lt;img src="https://64.media.tumblr.com/7166f758cd42bc3703823a5182ad0ebc/72ae8a879826ca42-70/s540x810/88faa4fe2d3c49d6244ecb6ac5c60c281b2f010e.jpg" data-orig-height="375" data-orig-width="500"/&gt;&lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class="tmblr-full" data-orig-height="375" data-orig-width="500"&gt;&lt;img src="https://64.media.tumblr.com/7cb894e6c25f6d7303adf31d348666ac/72ae8a879826ca42-11/s540x810/df0df4883414810e7e5a3b5ca17c158b8a54c456.jpg" data-orig-height="375" data-orig-width="500"/&gt;&lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class="tmblr-full" data-orig-height="375" data-orig-width="500"&gt;&lt;img src="https://64.media.tumblr.com/00ede86a705a2be9cf0598458096e86e/72ae8a879826ca42-54/s540x810/2aa468462417a1646bf3b2d4e8d2c956242e6612.jpg" data-orig-height="375" data-orig-width="500"/&gt;&lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;This is also a good use for all of those lame socks that go all the way up your calf (I don&amp;rsquo;t know why my mom keeps sending these to me?), because it&amp;rsquo;ll keep your forearms warm.&lt;/p&gt;
&lt;p&gt;Try it, it works.&lt;/p&gt;
&lt;p&gt;&lt;figure class="tmblr-full" data-orig-height="480" data-orig-width="360"&gt;&lt;img src="https://64.media.tumblr.com/31efa19d19c97f26337a4d5e32af122a/72ae8a879826ca42-84/s540x810/b4be0060744d14cb4e77f1ee4aa719480df2cd37.jpg" data-orig-height="480" data-orig-width="360"/&gt;&lt;/figure&gt;&lt;/p&gt;</description><link>https://blog.davidziegler.net/post/268584320</link><guid>https://blog.davidziegler.net/post/268584320</guid><pubDate>Thu, 03 Dec 2009 20:20:14 -0800</pubDate></item><item><title>Halloween</title><description>&lt;p&gt;This is me as Kim Jong Il.&lt;/p&gt;
&lt;p&gt;&lt;img height="604" width="453" alt="kim jong il" src="http://www.davidziegler.net/images/kim_jong_il.jpg"/&gt;&lt;/p&gt;
&lt;p&gt;Unfortunately, my dedication to the role meant shaving a receding hairline, which means I now have a shaved head. My alternative costume was to be Kim Jong ILL, North Korea&amp;rsquo;s finest gangster rapper.&lt;/p&gt;</description><link>https://blog.davidziegler.net/post/230614825</link><guid>https://blog.davidziegler.net/post/230614825</guid><pubDate>Mon, 02 Nov 2009 00:26:54 -0800</pubDate></item><item><title>A replacement for django-admin.py startproject</title><description>&lt;p&gt;When I create new Django projects, I find myself doing a lot of the same things over and over. For instance, the file structure of each project is pretty much identical, and looks something like this:&lt;/p&gt;
&lt;ul&gt;&lt;li&gt;deploy  
&lt;ul&gt;&lt;li&gt;wsgi_handler.py&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;docs&lt;/li&gt;
&lt;li&gt;env (my virtualenv folder)&lt;/li&gt;
&lt;li&gt;src  
&lt;ul&gt;&lt;li&gt;apps  
&lt;ul&gt;&lt;li&gt;profiles&lt;/li&gt;
&lt;li&gt;photos&lt;/li&gt;
&lt;li&gt;etc.&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;localsettings.py&lt;/li&gt;
&lt;li&gt;manage.py&lt;/li&gt;
&lt;li&gt;scripts&lt;/li&gt;
&lt;li&gt;settings.py&lt;/li&gt;
&lt;li&gt;static  
&lt;ul&gt;&lt;li&gt;css&lt;/li&gt;
&lt;li&gt;images&lt;/li&gt;
&lt;li&gt;js&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;templates&lt;/li&gt;
&lt;li&gt;urls.py&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;The things is, I&amp;rsquo;m lazy, and it&amp;rsquo;s tedious to create all those directories, create my wsgi_handler, uncomment the admin app, update my settings.py, urls.py, etc for every project I create. I basically end up copying/pasting/deleting from old projects.&lt;/p&gt;
&lt;p&gt;So to automate some of that, I made a small reusable django app to serve as a replacement for django-admin.py startproject. So instead of&lt;/p&gt;
&lt;pre class="prettyprint lang-bash"&gt;
 django-admin.py startproject project_name
&lt;/pre&gt;
&lt;p&gt;you would do&lt;/p&gt;
&lt;pre class="prettyprint lang-bash"&gt;
 create_project project_name
&lt;/pre&gt;
&lt;p&gt;To install, either clone the git repository which you can find here:&lt;/p&gt;
&lt;p&gt;&lt;a href="http://github.com/dziegler/django-create-project"&gt;http://github.com/dziegler/django-create-project&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;or install with pip using:&lt;/p&gt;
&lt;pre class="prettyprint lang-bash"&gt;
pip install -e git+git://github.com/dziegler/django-create-project.git#egg=django-create-project
&lt;/pre&gt;
&lt;p&gt;I made this mainly for my benefit, so some of the settings are tuned to my preferences. For example, it changes TIME_ZONE in in settings.py from &amp;lsquo;America/Chicago&amp;rsquo; to 'America/Los_Angeles&amp;rsquo;, and automatically installs django_extensions, debug_toolbar, and django-css because I use those in all of my projects. Since it&amp;rsquo;s on github, it&amp;rsquo;s fairly easy to fork and customize to fit your preferences. You can find it here:&lt;/p&gt;
&lt;p&gt;&lt;a href="http://github.com/dziegler/django-create-project"&gt;http://github.com/dziegler/django-create-project&lt;/a&gt;&lt;/p&gt;</description><link>https://blog.davidziegler.net/post/201559423</link><guid>https://blog.davidziegler.net/post/201559423</guid><pubDate>Wed, 30 Sep 2009 23:16:37 -0700</pubDate><category>django</category></item><item><title>Procrastination</title><description>&lt;p&gt;I just wasted an hour solving this stupid puzzle: &lt;a href="http://www.techcrunch.com/2009/09/21/google-is-searching-for-beautiful-minds-but-so-far-no-m-i-t-students-have-broken-its-code/"&gt;http://www.techcrunch.com/2009/09/21/google-is-searching-for-beautiful-minds-but-so-far-no-m-i-t-students-have-broken-its-code/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;I say stupid, because once you discover the answer you&amp;rsquo;re like, why did I just waste my time solving this? It&amp;rsquo;s not a cool puzzle that you might have to write a neat algorithm to decipher, it&amp;rsquo;s just one of those &amp;ldquo;ah-ha!&amp;rdquo; type puzzles, which to me, don&amp;rsquo;t really tell you that much about a person if you were looking to hire them.&lt;/p&gt;
&lt;p&gt;If you call the number they admit that they&amp;rsquo;re not even Google! I don&amp;rsquo;t particularly want a job either at Google or in Massachusetts, but now I&amp;rsquo;m annoyed that they lied to me. I&amp;rsquo;m still curious though, so I left a message and I&amp;rsquo;ll post info if they call me back. Probably not a good way to hire people by lying to them off the bat though.&lt;/p&gt; 

&lt;p&gt;&lt;a href="#javascript:(function()%7B%24('#stupid_answer').show();%7D)()"&gt;Click here for the answer&lt;/a&gt;&lt;/p&gt;
&lt;p id="stupid_answer" style="display:none"&gt;
617-274-8660
&lt;br/&gt;
Just count the characters in between the empty characters. Ignore line breaks. The last number is 0 because there are no characters.
&lt;/p&gt;</description><link>https://blog.davidziegler.net/post/193691468</link><guid>https://blog.davidziegler.net/post/193691468</guid><pubDate>Mon, 21 Sep 2009 16:07:01 -0700</pubDate></item><item><title>Email Fail</title><description>&lt;p&gt;I just noticed that my mail client will occasionally auto-select my old work email address for the &amp;ldquo;from&amp;rdquo; field when composing new emails. Unfortunately, I no longer have access to emails sent to this address.&lt;/p&gt;
&lt;p&gt;So if I wrote you an email and you responded to it, but I never replied back, this is probably the reason. Sigh.&lt;/p&gt;</description><link>https://blog.davidziegler.net/post/174886645</link><guid>https://blog.davidziegler.net/post/174886645</guid><pubDate>Sat, 29 Aug 2009 12:30:10 -0700</pubDate></item><item><title>Feeling Nostalgic</title><description>&lt;p&gt;I had the urge to create a &lt;a title="retro" href="http://www.davidziegler.net/retro.html"&gt;retro&lt;/a&gt; version of my homepage today. I cheated a little bit because I didn&amp;rsquo;t have the patience to use frames or tables.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://www.davidziegler.net/retro.html"&gt;http://www.davidziegler.net/retro.html&lt;/a&gt;&lt;/p&gt;</description><link>https://blog.davidziegler.net/post/167043074</link><guid>https://blog.davidziegler.net/post/167043074</guid><pubDate>Wed, 19 Aug 2009 20:56:00 -0700</pubDate></item><item><title>Sikarra</title><description>&lt;p&gt;No updates in a while because I&amp;rsquo;ve been traveling around a lot. I did manage to build this in my free time though: &lt;a href="http://www.sikarra.com"&gt;http://www.sikarra.com&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;It&amp;rsquo;s basically an online wishlist that lets you bookmark stuff you&amp;rsquo;d like to buy. Nothing fancy or anything, it&amp;rsquo;s something that I mainly just wanted for myself. I use Amazon wishlist a lot, but I didn&amp;rsquo;t like how I could only bookmark Amazon products. I have some cool features in mind that I&amp;rsquo;d like to build into it, but it depends on how much free time I have or if other people actually start to use it.&lt;/p&gt;
&lt;p&gt;When my birthday came around my parents had no idea what to get me, so I figured I&amp;rsquo;d make it easy to share with your friends and family.  The link to my public list is just &lt;a href="http://www.sikarra.com/david"&gt;http://www.sikarra.com/david&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Maybe I can market this to camwhores or something? Who knows.&lt;/p&gt;</description><link>https://blog.davidziegler.net/post/160873372</link><guid>https://blog.davidziegler.net/post/160873372</guid><pubDate>Tue, 11 Aug 2009 17:15:00 -0700</pubDate><category>sikarra</category></item><item><title>SF Theater Buzz</title><description>&lt;p&gt;It looks like it&amp;rsquo;s safe to mention this now. I recently finished building this site for a client: &lt;a href="http://www.sftheaterbuzz.org"&gt;http://www.sftheaterbuzz.org&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;My friend &lt;a href="http://twitter.com/3am_studio"&gt;Kim Nguyen&lt;/a&gt; did the design and artwork, and I think it looks pretty awesome. You should definitely hire her, as long as it doesn&amp;rsquo;t interfere with her working with me. The whole thing is written with Django and jQuery, and I used &lt;a href="http://github.com/dziegler/django-css/tree/master"&gt;django-css&lt;/a&gt; with &lt;a href="http://github.com/dziegler/clevercss/tree/master"&gt;CleverCSS&lt;/a&gt; to write the CSS.&lt;/p&gt;
&lt;p&gt;It&amp;rsquo;s a little sad because there are no reviews yet, but I don&amp;rsquo;t think the client has had time to promote it. I hope he gets around to it, because I&amp;rsquo;d hate to see such a beautiful site go to waste. Also, if you&amp;rsquo;re in the Bay Area, check out &lt;a href="http://www.sftheaterfestival.org/"&gt;SF Theater Festival&lt;/a&gt; this Sunday. It&amp;rsquo;s free theater, and maybe afterwards you might feel like writing about what you saw&amp;hellip;hint hint.&lt;/p&gt;</description><link>https://blog.davidziegler.net/post/148412882</link><guid>https://blog.davidziegler.net/post/148412882</guid><pubDate>Fri, 24 Jul 2009 12:12:39 -0700</pubDate></item></channel></rss>
