Mobile Django Admin Patches

In addition to adding a couple of minor, but useful (at least for me), patches to to the awesome django-mobileadmin project by Jannis Leidel, I learned something new about how Python works.

The first patch was simply removing an extra slash from a URL in a template. No big deal:

commit 599f172df85586742b5b1ef2bd5b7a24298a0839
Author: Patrick Altman <>
Date:   Wed Dec 31 23:13:57 2008 -0600

    fixed bug where app links had an extra trailing slash

diff --git a/mobileadmin/templates/mobileadmin/mobile_safari/index.html b/mobileadmin/templates/mobileadmin/mobile_safar
index 046a39d..1d66f59 100644
--- a/mobileadmin/templates/mobileadmin/mobile_safari/index.html
+++ b/mobileadmin/templates/mobileadmin/mobile_safari/index.html
@@ -10,7 +10,7 @@
 {% if app_list %}
     <ul id="applist" selected="true">
     {% for app in app_list %}
-    <li><a href="{{ app.app_url }}/" id="{{|slugify }}_app">{% blocktrans with as name %}{{ name }}{%
+    <li><a href="{{ app.app_url }}" id="{{|slugify }}_app">{% blocktrans with as name %}{{ name }}{% 
     <script type="text/javascript">truncate({'{{|slugify }}_app': 35});</script>
     {% endfor %}

Django Mobile for ShiftingBitsThe second patch took a bit more research to figure out what was going on. The symptom I was witnessing was that the mobile interface looked fine in my iPhone until I tried to view a model's list of objects. It kept showing me the default admin view (as you would expect to on the desktop) and it didn't jive with the (screenshots I saw on Flickr)[] that Jannis had posted showing off the app.

After seeing some drastic differences between the output of a dir command on the admin_site variable and the contents of admin_site.__dict__, it quickly became apparent that __dict__ on the object wasn't showing the whole picture and thus there was a bug in the autoregister function.

I then found Keith Waclena's excellent course documentation describing the problem perfectly. It turns out that __dict__ only reveals the members of the class or instance and NOT the inherited members, so one must recurse down through base classes to be complete. So, I borrowed his recursive lookup function, and rewrote a couple lines to approach the lookup differently but accomplishing the same intent (at least I hope so -- it seems to work as intended for me):

commit 5945491fe1216239471d41e590425bfe384d3d99
Author: Patrick Altman <>
Date:   Thu Jan 1 00:52:46 2009 -0600

    fixed bug in autoregister where attribute searching didn't search deep enough (didn't search base classes)

diff --git a/mobileadmin/ b/mobileadmin/
index f8658ac..77e0de1 100644
--- a/mobileadmin/
+++ b/mobileadmin/
@@ -4,6 +4,21 @@ from django.core.exceptions import ImproperlyConfigured
 from mobileadmin import decorators, views
 from mobileadmin.conf import settings

+### From
+def classlookup(C, name):
+       if C.__dict__.has_key(name):
+               return (1, C.__dict__[name])
+       else:
+               for b in C.__bases__:
+                   success, value = classlookup(b, name)
+                   if success:
+                           return (1, value)
+                   else:
+                           pass
+               else:
+                   return (0, None)
 def autoregister():
     Auto-register all ModelAdmin instances of the default AdminSite with the
@@ -14,11 +29,11 @@ def autoregister():

     for model, modeladmin in main_site._registry.iteritems():
         admin_class = modeladmin.__class__
-        for name, value in admin_class.__dict__.iteritems():
-            if name in settings.TEMPLATE_MAPPING:
+        for name in settings.TEMPLATE_MAPPING:
+            (found, value) = classlookup(admin_class, name)
+            if found:
                 setattr(admin_class, name, decorators.mobile_templates(value))
         if admin_class == UserAdmin:
             setattr(admin_class, 'add_view', views.auth_add_view)

I have pushed in these changes to my fork of the git project and sent pull requests to Jannis. Hopefully, he'll integrate them into his project soon, but in the meantime, my fork is available.

Being that this occurred shortly after the stroke of midnight, it is officially the first thing that I have done in 2009!

Happy New Year!