<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/rss2full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><rss xmlns:geo="http://www.w3.org/2003/01/geo/wgs84_pos#" xmlns:creativeCommons="http://backend.userland.com/creativeCommonsRssModule" version="2.0"><channel><title>On the other hand</title><link>http://joshourisman.com</link><description>An experiment in independence</description><language>en-us</language><lastBuildDate>Thu, 15 Oct 2009 10:30:27 -0500</lastBuildDate><geo:lat>37.889125</geo:lat><geo:long>-122.29371</geo:long><creativeCommons:license>http://creativecommons.org/licenses/by-sa/2.0/</creativeCommons:license><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" href="http://feeds.feedburner.com/joshourisman/lRQx" type="application/rss+xml" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com" /><item><title>Django admin awesomeness
</title><link>http://joshourisman.com/2009/10/15/django-admin-awesomeness/</link><description>&lt;p&gt;Yes, I realize that this is now my third post not related to DVCSes since I said my next post would be about DVCSes. So sue me.&lt;/p&gt;

&lt;p&gt;I recently encountered an interesting requirement for the &lt;a href="http://www.djangoproject.com/"&gt;Django&lt;/a&gt; &lt;a href="http://docs.djangoproject.com/en/dev/ref/contrib/admin/#ref-contrib-admin"&gt;admin&lt;/a&gt;: we wanted people to normally only see (and be able to edit) objects that either they created themselves, or that the creator had assigned them to. Fortunately this is insanely easy in Django 1.1, all you have to do is override the queryset() method of the appropriate ModelAdmin like so:&lt;/p&gt;

&lt;p&gt;&lt;script src="http://gist.github.com/211008.js"&gt;&lt;/script&gt;&lt;/p&gt;

&lt;p&gt;This snippet very easily allows you to apply essentially any filter you want to the QuerySet that gets passed on to the change_list and allows you to provide an exception for super users (always a good thing!). That part was really easy and something I've done before (even in 1.0.x where the functionality is there, just not exposed). Where it got trickier was where the client also wanted the functionality to be able to view &lt;em&gt;all&lt;/em&gt; the objects regardless of who created them, but still only have editing capabilities for their own objects (and only see the information available on the change_list for others).&lt;/p&gt;

&lt;p&gt;This part was much harder, but fortunately also made very possible by the updates to ModelAdmin in the 1.1.x branch. The first thing I wanted to do was just provide a new URL and view integrated seamlessly into the admin. Again this was very simple with the new admin, and required only overriding the get_urls() method on the ModelAdmin:&lt;/p&gt;

&lt;p&gt;&lt;script src="http://gist.github.com/211020.js"&gt;&lt;/script&gt;&lt;/p&gt;

&lt;p&gt;Getting that all_objects view to return something essentially identical to the normal change_list, but with a completely different filter on the queryset, and some different display options was the real problem I had to address. Wrapping my head around the problem took some time, but fortunately even this was pretty simple once I really started to get into the flexibility of the ModelAdmin class.&lt;/p&gt;

&lt;p&gt;Broken down to it's most basic level, what I wanted to do was return the change_list view from a Model Admin. This in itself is very simple to do, and requires very little code:&lt;/p&gt;

&lt;p&gt;&lt;script src="http://gist.github.com/211023.js"&gt;&lt;/script&gt;&lt;/p&gt;

&lt;p&gt;Once I figure that out it was pretty obvious that what I needed to do was subclass my ModelAdmin and just re-overide the relevant functions. Turns out this is really easy to do, and gives you a whole lot of flexibility. So I created a special AllItemsAdmin subclass of ThisAdmin, and overrode &lt;em&gt;that&lt;/em&gt; queryset() method to return all the objects. I then had to figure out a way to get it to only display but not link to edit pages for objects that the current user doesn't own. Since I needed them to be in the queryset, this was a little trickier.&lt;/p&gt;

&lt;p&gt;Anyone who's been working with the Django admin should know about the &lt;a href="http://docs.djangoproject.com/en/dev/ref/contrib/admin/#django.contrib.admin.ModelAdmin.list_display"&gt;list_display&lt;/a&gt; option on the ModelAdmin. What you might not know (I didn't until recently) is that no only can the list_display list contain field names and properties from the model (Actually, if you didn't know that you can provide &lt;a href="http://docs.djangoproject.com/en/dev/topics/db/models/#id4"&gt;callable properties from your model&lt;/a&gt;, you should check that out. It lets you do some very useful things.), you can also provide &lt;em&gt;callables from within your model admin&lt;/em&gt;. So you could set your list_display to something like ['title', 'my_function'] where my_function is a method on your model admin with a definition along the lines of my_function(self, object) that can perform operations on the Django object for that row and return whatever value you want.  The normal options for model properties (such as allow_tags and short_description) work here as well. So what I was able to do with this was create a custom column for my change_list that looked at the specific object, checked the ownership properties as above, and then returned either just the name of the object, or the name of the object as a link to the regular edit page for that object. By setting list_display_links to (None,) I was able to prevent any of the fields from automatically be turned into links. Of course doing this required that method to have access to the request which it usually wouldn't, but since I was already working with a hacked up subclass of my ModelAdmin I was able to just override the __init__() to take the request object and pass that in when I instantiated it. What I ended up with was this really awesome view (if I do say so myself):&lt;/p&gt;

&lt;p&gt;&lt;script src="http://gist.github.com/211037.js"&gt;&lt;/script&gt;&lt;/p&gt;

&lt;p&gt;As you can see, this is also using another new feature in the 1.1.x admin: reversing of admin URLs. After this all I needed was a few simple changes to the change_list.html template for this model let me add a 'View all' link to go to this new view, and then the 'all' context variable being passed in as extra context simply tells it to provide a link back to the standard view otherwise.&lt;/p&gt;

&lt;p&gt;The result of all this was a seamless integration of my custom 'view, but don't edit all' view into the Django admin.&lt;/p&gt;
</description><pubDate>Thu, 15 Oct 2009 10:30:27 -0500</pubDate><guid>http://joshourisman.com/2009/10/15/django-admin-awesomeness/</guid></item><item><title>Sorry about the downtime
</title><link>http://joshourisman.com/2009/10/14/sorry-about-downtime/</link><description>&lt;p&gt;I just happened to check my Google analytics today and saw that my hits had dropped essentially to zero since October 8th. Turns out that my wsgi file was a little screwed up after my initial attempts to migrate my blog to django-mingus. I have, obviously, fixed it, though I still want to move the blog to mingus and will hopefully get the chance to actually do that soon. Until then, however, at least my blog is up!&lt;/p&gt;
</description><pubDate>Wed, 14 Oct 2009 09:47:27 -0500</pubDate><guid>http://joshourisman.com/2009/10/14/sorry-about-downtime/</guid></item><item><title>Storing IP addresses as integers in Python
</title><link>http://joshourisman.com/2009/10/07/storing-ip-addresses-integers-python/</link><description>&lt;p&gt;I just saw this very interesting (for a programmer) blog entry on &lt;a href="http://norbauer.com/notebooks/code/notes/storing-ip-addresses-as-integers"&gt;Storing IP addresses as integers&lt;/a&gt;. As the article says, anyone who wants to store IP addresses in a database is generally going to do as a string. However if you're really concerned about memory efficiency, you might want to find a lighter data type to use. Since an IP address is really just a collection of integers it would make sense to store it as an integer, however doing so without losing important information (specifically, the placements of the dots) becomes an issue.&lt;/p&gt;

&lt;p&gt;The blog post in question introduces the the pack() and unpack() functions, which 'allow you to create and extract data into and out of binary-packed strings' and provides the Ruby code necessary to encode an IP address as a simple integer and decode it back to a dotted quad. I thought this was pretty cool, so I decided to write the equivalent Python code. This is what I ended up with:&lt;/p&gt;

&lt;p&gt;&lt;script src="http://gist.github.com/204279.js"&gt;&lt;/script&gt;&lt;/p&gt;

&lt;p&gt;It seems to work as advertised, though the packed string the encode() function returns is different from what Ruby gives you, so they won't interoperate (it would probably only require changing the pack() and unpack() formats to do so, but I didn't feel like experimenting to figure out which ones).&lt;/p&gt;

&lt;p&gt;Of course, being a &lt;a href="http://www.djangoproject.com"&gt;Django&lt;/a&gt; guy, the immediate application of these functions that I see is creating a new &lt;a href="http://docs.djangoproject.com/en/dev/ref/models/fields/#ipaddressfield"&gt;IPAddressField&lt;/a&gt; that stores the address as an integer instead of a string transparently.&lt;/p&gt;
</description><pubDate>Wed, 07 Oct 2009 14:20:26 -0500</pubDate><guid>http://joshourisman.com/2009/10/07/storing-ip-addresses-integers-python/</guid></item><item><title>Building RESTful APIs with django-piston
</title><link>http://joshourisman.com/2009/09/26/building-restful-apis-django-piston/</link><description>&lt;p&gt;&lt;a href="http://creative.discovery.com"&gt;Discovery Creative&lt;/a&gt; has a lot of &lt;a href="http://creative.discovery.com/work/"&gt;web sites and apps&lt;/a&gt; out there. And quite a few of them need to send email in one form or another. Previously that has meant that every single one of those sites/apps needed to implement it's own mechanism for sending email. This is obviously a bit of a pain, not to mention a potential security risk, and a blatant violation of the &lt;a href="http://en.wikipedia.org/wiki/DRY"&gt;DRY principle&lt;/a&gt;. So I was tasked with building a better mousetrap, as it were.&lt;/p&gt;

&lt;p&gt;One of the cool new things I had heard about at &lt;a href="http://www.djangocon.org/"&gt;DjangoCon 2009&lt;/a&gt; (which I really should have written about...) was &lt;a href="http://bitbucket.org/jespern/django-piston/wiki/Home"&gt;Piston&lt;/a&gt;, a framework built in &lt;a href="http://www.djangoproject.com"&gt;Django&lt;/a&gt; for building RESTful APIs by the &lt;a href="http://bitbucket.org"&gt;bitbucket&lt;/a&gt; guys. I'd never actually built any sort of API before, but it seems to be the thing to do, so I decided to take django-piston for a whirl and how it works. As it turns out, it works extremely well. So well, in fact, that when coupled with some of the fun tools that Django provides (such as &lt;a href="http://docs.djangoproject.com/en/dev/topics/forms/modelforms/#topics-forms-modelforms"&gt;ModelForms&lt;/a&gt;) you can easily build a RESTful API in no time at all.&lt;/p&gt;

&lt;p&gt;Thanks to django-piston I was able to create a simple API that will allow us, moving forward, to use a single, centralized email solution for all our web apps. In fact anything that can send an HTTP POST request (including curl, which is what I've been using for testing) can send email using the API I created so long as it can also handle HTTP authentication (which django-piston easily handles against &lt;a href="http://docs.djangoproject.com/en/dev/topics/auth/#topics-auth"&gt;django.contrib.auth&lt;/a&gt;). I'm hoping, after a little more work and refinement, to open-source our API so that other can benefit from it (and, hopefully, contribute back to it!), but for now you'll have to make do with a sample project that I threw together for the most recent django-district meeting this past Thursday: &lt;a href="http://bitbucket.org/Josh/django-piston-presentation/wiki/Home"&gt;Django-Piston Presentation&lt;/a&gt;. It's a bitbucket repository that includes all the code for a simple RESTful API that allows you to create, fetch, and delete objects from a simple Django object. This particular project was designed to be extremely flexible, and all one needs to do is add or remove fields from the model (or point it at a different model) to adapt it to just about anything. Hopefully it will serve as a pretty good instructional example to anyone who wants to create their own API with django-piston. The project also contains my notes on how to build and test it in an Emacs org-mode file.&lt;/p&gt;

&lt;p&gt;Next up: Git, Mercurial, and moving on from Subversion.&lt;/p&gt;
</description><pubDate>Sat, 26 Sep 2009 09:17:24 -0500</pubDate><guid>http://joshourisman.com/2009/09/26/building-restful-apis-django-piston/</guid></item><item><title>Comments are go!
</title><link>http://joshourisman.com/2009/09/18/comments-are-go/</link><description>&lt;p&gt;Just a quick note: this blog now has &lt;a href="http://disqus.com/"&gt;Disqus&lt;/a&gt; comments. Turns out it's insanely simple to implement, thanks to &lt;a href="http://arthurkoziel.com/"&gt;Arthur Koziel&lt;/a&gt;'s awesome &lt;a href="http://github.com/arthurk/django-disqus"&gt;django-disqus&lt;/a&gt; app. Took me no more than five minutes during my lunch break to get everything to it's current state.&lt;/p&gt;
</description><pubDate>Fri, 18 Sep 2009 15:28:31 -0500</pubDate><guid>http://joshourisman.com/2009/09/18/comments-are-go/</guid></item><item><title>Blog has been migrated to the Rackspace Cloud
</title><link>http://joshourisman.com/2009/09/17/blog-has-been-migrated-rackspace-cloud/</link><description>&lt;p&gt;One of the reasons that I haven't been blogging lately is that I have a lot of planned changes for the blog. Most importantly, I've been planning on moving it to my Cloud Server on The Rackspace Cloud (née Mosso). I've finally taken care of that, and this post is the first on the new server. If you can see it, that means the DNS changes have propagated.&lt;/p&gt;

&lt;p&gt;Now that I've done this I have a number of other changes planned. I'm going to completely overhaul the backend to the blog. In the course of the migration I upgrade from &lt;a href="http://www.djangoproject.com"&gt;Django&lt;/a&gt; 1.0.2 to Django 1.1. Nothing else has changed yet, but I intend to also revamp the templates, add some fancy new feature to better integrate with the rest of my online life, and start using &lt;a href="http://bitbucket.org/montylounge/django-mingus/"&gt;django-mingus&lt;/a&gt;. One of the more urgent changes I want to make is to switch to &lt;a href="http://www.disqus.com/"&gt;Disqus&lt;/a&gt; powered comments. Previously I was using django.contrib.comments along with &lt;a href="http://akismet.com/"&gt;Akismet&lt;/a&gt; for spam filtering. Akismet really just hasn't worked at all for me for the past few months, which is why comments are current disabled. Fortunately, Disqus should cut down on the spam by requiring registration without imparting too large an onus on the readers by using a number of common authentication backends like OpenID, Facebook Connect, and Twitter. I'm hoping it will make for a good compromise.&lt;/p&gt;

&lt;p&gt;The most important change, of course, is that I intend to actually start writing again. I've got a lot of ideas that I've wanted to write about and simply haven't because either I didn't have the time, I wanted to wait until this migration, or I was just too lazy. Hopefully, that will be changing now!&lt;/p&gt;
</description><pubDate>Thu, 17 Sep 2009 23:21:01 -0500</pubDate><guid>http://joshourisman.com/2009/09/17/blog-has-been-migrated-rackspace-cloud/</guid></item><item><title>The Colony: Another Discovery Creative project goes live!
</title><link>http://joshourisman.com/2009/07/09/colony-another-discovery-creative-project-goes-live/</link><description>&lt;p&gt;I &lt;em&gt;will&lt;/em&gt; get around to actually writing something soon, I swear! But for now you'll all just have to make do with another announcement of a project going live. This time it's actually up on &lt;a href="http://dsc.discovery.com/"&gt;Discovery Channel&lt;/a&gt; site. It's a Flash and Django based app promoting one of Discovery's new shows &lt;a href="http://dsc.discovery.com/tv/colony/colony.html"&gt;The Colony&lt;/a&gt;, about survival in a post-apocalyptic LA. I've actually been looking forward to this show, can't wait to watch it!&lt;/p&gt;
</description><pubDate>Thu, 09 Jul 2009 16:16:12 -0500</pubDate><guid>http://joshourisman.com/2009/07/09/colony-another-discovery-creative-project-goes-live/</guid></item><item><title>Silverdocs.com: My first Discovery Creative project goes live!
</title><link>http://joshourisman.com/2009/06/02/silverdocscom-my-first-discovery-creative-project-goes-live/</link><description>&lt;p&gt;I'm actually a bit late on this one, but I've been so busy with my &lt;em&gt;next&lt;/em&gt; &lt;a href="http://creative.discovery.com/"&gt;Discovery Creative&lt;/a&gt; project that I just haven't had time for much else. Anyway, from June 15 through 22 AFI, in partnership with the Discovery Channel will be putting on their &lt;a href="http://silverdocs.com/"&gt;Silverdocs Documentary Film Festival&lt;/a&gt;. Check out the website for more details on the festival and the films they'll be showing, not to mention an example of how awesome my (and the rest of Discovery Creative, I guess) work is.&lt;/p&gt;
</description><pubDate>Tue, 02 Jun 2009 20:24:21 -0500</pubDate><guid>http://joshourisman.com/2009/06/02/silverdocscom-my-first-discovery-creative-project-goes-live/</guid></item><item><title>No more dydxtech.com!
</title><link>http://joshourisman.com/2009/06/02/no-more-dydxtechcom/</link><description>&lt;p&gt;This is just a quick update. I'm phasing out the dydxtech.com. As a result, dydxtech.com now redirects to this page. None of the content from the original site is sticking around other than my portfolio, which is now available on this site at &lt;a href="http://www.joshourisman.com/portfolio/"&gt;joshourisman.com/portfolio&lt;/a&gt;. I've done a half-assed job at re-skinning the portfolio page to look like the blog, and I'll put in some sort of link to it eventually.&lt;/p&gt;
</description><pubDate>Tue, 02 Jun 2009 19:27:40 -0500</pubDate><guid>http://joshourisman.com/2009/06/02/no-more-dydxtechcom/</guid></item><item><title>Life in Maryland
</title><link>http://joshourisman.com/2009/05/10/life-maryland/</link><description>&lt;p&gt;I've now been living in Maryland and working at &lt;a href="http://creative.discovery.com/"&gt;Discovery Creative&lt;/a&gt; for a whole month, so I think it's about time I started writing again! My first couple weeks I was here alone while Jessi finished things up in Boston I had little motivation to do much outside of work, so I found myself going in to work early and home (I was staying with my aunt and uncle who graciously offered me a place to stay at their home in Bethesda during the limbo time between moving out of the condo in Somerville and into the apartment in Silver Spring) late. That left me pretty exhausted at the end of the day so relaxing, eating, and sleeping were much higher on my to do list than writing. Since Jessi got down here my time outside work has been dedicated to unpacking boxes and transmitting what little I know of the area to her and her sister Becky who flew out to help with the move. Now, however, we're unpacked—if not completely then at least enough to be comfortable—with most of our furniture in place and awaiting delivery on the few remaining items that we've purchased. So time to start looking towards the future again.&lt;/p&gt;

&lt;p&gt;My experience here thus far suggests that there's a lot of interesting work ahead. I've got a few &lt;a href="http://www.djangoproject.com/"&gt;Django&lt;/a&gt; projects already going on, including working with some new stuff like &lt;a href="http://openid.net/"&gt;OpenID&lt;/a&gt;, &lt;a href="http://opencalais.com/"&gt;OpenCalais&lt;/a&gt;, &lt;a href="http://www.clickpass.com/"&gt;Clickpass&lt;/a&gt;, &lt;a href="http://www.twitter.com"&gt;Twitter&lt;/a&gt;, and many other things. I'll probably be starting work on a project using &lt;a href="http://code.google.com/appengine/"&gt;Google App Engine&lt;/a&gt; in the near future, and I've already begun learning about and starting to work on iPhone apps as well. So I should have lots of good fodder for technical posts in the coming months!&lt;/p&gt;

&lt;p&gt;On top of that there's a whole new city to explore, and nearly the entirety of my family spend time with. Before we knew we were going to be moving, Jessi and I had been planning on getting kayaks this summer so we could spend some time on the Charles and Mystic rivers, maybe the Harbor Islands, and hopefully take them up to the Adirondacks to explore the lakes up there. That plan certainly hasn't changed as now we've got the Potomac and other bodies of water to play with. Plus we're now so close to &lt;a href="http://www.nps.gov/shen/"&gt;Shenandoah&lt;/a&gt; that it would be a crime not to get in some camping and backpacking. (And after the missed opportunity last winter, I'm definitely planning on some winter backpacking in the Senandoah back country this year!)&lt;/p&gt;

&lt;p&gt;So with any luck I should be doing a lot of writing on a lot of different topics in the future. At the very least I need to do some work on this site as I want to integrate &lt;a href="http://dydxtech.com/portfolio/"&gt;my portfolio&lt;/a&gt; into the personal site and phase out the business one. And working on this site always seems to give my something to write about.&lt;/p&gt;
</description><pubDate>Sun, 10 May 2009 09:29:52 -0500</pubDate><guid>http://joshourisman.com/2009/05/10/life-maryland/</guid></item></channel></rss>
