Last month, Lincoln Loop gave a talk at EuroDjangoCon about customizing the Django admin interface. After presenting some of the admin customizations we had done on Gondola, I had a bunch of people get in touch with me asking me to do a write-up about how it was done. After about 8 months of heel-dragging, I finally took the time to do it in presentation form.
Our talk was divided into two parts. First our User Experience Director, Michael, gave an overview of user interface design and why it is important, pulling examples from some real-world interfaces. Comparing the default Django admin to a custom built application specific interface was an intentional cheap-shot to get people to think outside-the-box when working with the admin. Our argument was that it is possible to recreate any of the example interfaces while still leveraging some of the power baked into django.contrib.admin ...
I’ve always disliked the way named anchors (<a href="#name">...</a>) behave in browsers. It jumps your viewport to a different part of the page, but it’s rarely obvious which section you have landed on. If the page is long enough, the referenced section will start at the top of your browser, but where does it end? If the content is towards the bottom of the page, it may not be at the top of the page, but somewhere in the middle. And what if your content is in two columns? Or a table? What you’ve linked to becomes totally ambiguous.
Sphinx uses named anchors quite a bit, so I wanted something that would improve their usability for Django Best Practices. That’s when I dug up this clever little jQuery snippet from our code vault.
// highlight and fade background on named anchors// requires jquery.color.js ...
One of the things I love about Python and Django is the philosophy that there is one obvious way to do things. Standards make it easy to dive into other people’s code and figure out what is going on pretty quickly. As with anything under active development, however, those standards are subject to change over time. What was best practice for building sites with Django 0.91 is significantly different than building sites with Django 1.0. Better tools and more experience allow us to refine our processes over time into a set of best practices. While both Python and Django are very well documented, much of the experience and wisdom that is outside the scope of the official documentation is not.
Blogs are Bad for Documentation
Most of this information lives scattered across blogs ...
Yep, it is. These little snippets aren’t much, but they speak volumes. The White House is using open source software, specifically the Apache web server, the Drupal CMS and the jQuery javascript framework.
So What?
Open source adoption is most definitely on the rise, but it still has a stigma attached. The idea that Microsoft and ...
December 23, 2008 |
django, screencast |
5 comments
Satchmo is an amazing E-Commerce engine built on top of Django. After struggling in the past with difficult packages like ZenCart and OSCommerce, Satchmo’s ease of customization make it a joy to work with.
Unfortunately, all the features can make the administration interface a bit daunting at first glance. I created a screencast to help shop owners get started with the process of adding products and product variations in Satchmo. I’m using the latest release as of this writing (0.8.1).
In the process of prepping Gondola CMS for public consumption, we’ve grown from having a developer (me), to having a development team. One pain point that quickly arose was the amount of time it took for new developers to setup a local development environment. In addition to our source code, the project depends on nearly a dozen other Django apps and Python packages. Initially, we simply tracked the requirements in a text file, but it required a lot of manual work to get them downloaded and installed.
Necessity is the Mother of Invention
Of course, this problem has been tackled many, many times before1. As I looked into what was out there, my first thought was that most of the existing options were far too complex for our needs. If I didn’t grok a system after clicking around the docs for 10 minutes or so, I moved ...
We all know not to serve static media (images, CSS, Javascript, etc.) in production directly from Django. Thankfully, Django gives us some nice settings like MEDIA_URL and MEDIA_ROOT to make serving them a lot less painless. Lately, however, I’ve come to realize that these settings shouldn’t really apply to all static media.
Not All Static Media Is Created Equal
Static media really comes in two flavors. Media that is part of your site like your stylesheets and user generated media or files that are uploaded to the site once it is live. We don’t want to serve all this media from the same place for a couple of reasons:
Our source checkouts shouldn’t be crufted up by stuff our users are uploading
User generated content and source code should live in two different places on the filesystem
We could fix the first problem with some .gitignore ...
After reading the comments on my last post on the subject, I realized there was definitely some room for improvement in my strategy. This is take two of the original post.
Problems
My original strategy had a couple of downfalls:
Poisoning the Python Path
I was adding directories to the Python Path that weren’t Python. This raised the chance of namespace collision and just wasn’t a very clean way to do things.
No project source repository
I was still storing all my source files in one big folder. Tracking which project is using what was more difficult than it needed to be.
Solutions
The first step to recovery was forgetting about sharing libraries between projects altogether. In theory it sounds great, in practice it was cumbersome to manage. My directory structure now looks like this:
Gondola is our content management system built on top of Django. I briefly showed it off during my DjangoCon Lightning Talk, but have been wanting to give it a proper screencast for a while. Here’s an introduction:
A few common questions I don’t tackle in the screencast:
Is this an open source project?
As of right now, no. I do plan on spinning off a few bits as open source over time. In fact, the WYSIWYG editor is already on Google Code as django-admin-uploads. Unfortunately it hasn’t been synced up with our in-house code in a while and isn’t working on 1.0. We’ll get that updated at some point in the near future.
How much will it cost?
I haven’t settled on a pricing structure yet, but I want it to be affordable for small businesses.
September 18, 2008 |
django, presentation, trailmapping |
2 comments
DjangoCon was an amazing conference all around. I met some great people and learned a lot. I also had the opportunity to get up on stage and present some of the things I’ve been working on here. I was really nervous and after seeing how well prepared the presenters before me were, I had doubts about my plan to go on stage and wing it. I spoke about Trailmapping and Gondola the CMS I’ve been working on.
Afterwards, I was blown away by the number of compliments I received. A few people told me they thought my talk was the best of the bunch which was really encouraging. To everyone that reached out, all I can say is thanks; it meant a lot. I’m inspired to carve out some more time to blog about the things I’m working on, specifically Django admin customization and jQuery.
A friend is in the process of setting up a new slice at everbody’s favorite VPS provider Slicehost and asked for some advice. I use MySQL, Nginx & Apache/mod_wsgi on Ubuntu to serve Django. I think Slicehost’s Articles are awesome and a great place to get help you get everything installed and running, so for this article, I’ll focus on some personal preferences regarding directory structure and repo management.
One of the biggest difficulties I’ve had to tackle lately is the rapid progress of Django. I have a number of client sites hosted on my slice and have had to freeze them at certain times when backwards incompatible changes come along. My original approach made this really messy, because I only accounted for having one copy of any given third party repo, symlinked from /usr/local/src to my Python site-packages directory. My new approach ...
July 20, 2008 |
django, trailmapping |
11 comments
All the recent hubbub about 1 week and 1 day application development, motivated me to see how quickly I could launch a website for myself. I, like many developers, struggle with building and releasing personal sites. Ask a web developer and they’re likely to tell you about a couple of sites they started and never finished. Time is always an issue, but the bigger problems are striving for perfection prior to launch and always holding out for that one “killer” feature. As time goes on, interest in the project wanes until it finally gets shelved.
The Plan
Prior to development, I set a few goals for myself:
Launching quickly was priority number one. I set a goal of 3 days.
Use as much existing code as possible. Even if it wasn’t a perfect fit, if it was functional, use it.
Lincoln Loop has been in “head down” mode for the last couple months. In addition to being knee deep in client projects, we have grown from a one-man development studio to a full-fledged Django development shop/consultancy. We are proud to announce that Lincoln Loop is the first (that we know of) company focusing solely on Django application development. Our development team is currently five strong and oozing with talent. Each member contributes to the community in blog posts or open source add-ons; a few of us have contributed code to Django itself. More on our dev team in the near future.
We went through the typical growing pains during the transition, but the kinks are worked out and we can officially say that we are open for business. Django projects big and small, send them our way. Our devs can handle nearly anything.
Lately, we’ve been taking over projects from people who began building their first site in Django, but either got in over their head or just found they didn’t have the time to continue. As I review the existing code, the first issue I typically see is using the render_to_response shortcut without including the RequestContext, preventing context processors from being used in the templates. The standard symptom is when people can’t access MEDIA_URL in their templates.
Here are a few ways to add RequestContext to your templates.
Option #1: Adding RequestContext to render_to_response
The Django documentation recommends passing RequestContext as an argument to render_to_response like this:
For those of you that have been hiding under a rock for the last 12 hours, App Engine is Google’s answer to Amazon Web Services. While it is less flexible in some senses (you don’t have a complete OS at your disposal), it does provide tighter integration for web applications and even includes a (somewhat crippled) version of Django out of the box.
I’m pretty excited about this mainly because I’m not a big fan of server administration, so I took a couple hours this morning to test it out. Here are some quick notes:
One of the things that drew me towards Django was the idea of being able to create reusable applications that would sit on my PYTHONPATH instead of copied across multiple sites. Coming from WordPress, the constant security updates that required me to revisit old projects began to drive me mad.
Trouble in Paradise
With some real world Django experience under my belt, I find myself re-using apps all the time, but not how I originally expected. A fair amount of my client work comes from building content management systems, so I started out building a generic app like flatpages but more extendable and a blogging app. I dropped them in my PYTHONPATH and started adding them to INSTALLED_APPS on my projects.
Over time, they evolved and improved, but they started to handcuff me. I started thinking things like, “This would be a great feature for Project X, but it would ...
A few months ago, I got sick of trying to deploy Django sites on my cPanel server and got a VPS at Slicehost. Thanks to SuperJared, setting up Apache/mod_python behind an Nginx frontend was a snap.
I started deploying and migrating sites to the new server and kept an eye on my server resources via Munin. I had about 10 sites running on a 1GB Slice, but the Apache processes were hogging all the RAM. Restarting Apache would bring memory usage down to around 500MB, but within a couple of hours, it would be using all my available RAM, with individual proceesses using as much as 120MB.
I started asking questions and trying different options including mod_wsgi, verifying projects weren’t in debug mode, etc. Nothing made a difference.
Here’s a little nugget I just posted to Django Snippets. It emulates the behavior of an old Perl script I used way back when, FormMail.pl.
I often find myself needing to build a form whose contents get emailed to the site owner(s). This class let’s you call form.notify() on any form that is a subclass of it to have the fields ordered and sent in a plain text email to all users that are flagged as staff.
fromdjangoimportnewformsasformsfromdjango.contrib.auth.modelsimportUserfromdjango.contrib.sites.modelsimportSitefromdjango.core.mailimportsend_mailclassFormMail(forms.Form):defnotify(self):""" Sends an email to all members of the staff with ordered list of fields and values for any form that subclasses FormMail """site_name=Site.objects.get_current().nameform_name=self.__class__.__name__subject='%s%s Submission ...
The newforms library is a huge time-saver, but when I first started using it, I still found myself writing tedious repetitve code to get it to function how I wanted. While I could get away with it on smaller sites, I recently built a site with some big forms on it and decided to improve my process.
HTML Rendering
First off, {{ form }} or {{ form.as_p }}, rarely cut it in real world apps. We need to be able to customize our forms to improve the layout or add extra information. I started using inclusion tags to render the form fields and labels. Here is my trivial inclusion tag:
@register.inclusion_tag('_display_field.html')defdisplay_field(field,alt_label=''):""" Print HTML for a newform field. Optionally, a label can be supplied that overrides the default label generated for the form. Example: {% display_field form.my_field "My New Label" %} """ifalt_label:field.label=alt_labelreturn{'field ...
< 30% of applicants correctly followed the instructions. Should have added "attention to detail" & "ability to follow instructions" as reqs
Pete, 1 week, 6 days ago
Use PERT technique for more accurate estimates Taking a weighted average of the most pessimistic, most optimistic, and most likely estimates of a task to get a realistic estimate of the time it will take. Pete, 2 weeks, 4 days ago
Evidence Based Scheduling - Joel on Software Interesting approach to software estimation. Pete, 2 weeks, 4 days ago
Less Wrong: Planning Fallacy People are terrible planners/estimators and there is evidence to prove it. Pete, 2 weeks, 4 days ago
A reminder of how simple business can be when you don't make it complicated - (37signals) Refreshing, especially after after spending 2 days wading through client contracts and work orders. Pete, 3 weeks, 6 days ago