Django Tip: Smarter Output From Management Commands

Have you ever tried to add a helpful output for showing the progress of a slow management command but all the output frustratingly appears in one go after the script has finished? You’ve tripped into something called output buffering and luckily it’s very easy to fix.

Use self.stdout instead of print in management commands

You should never use print inside Django management commands as they have a special self.stdout method that makes testing easier. This method frustratingly takes slightly different arguments than print, but it also has more features like styling. Here’s how you would do a simple row of dots that grows iteratively:

self.stdout(".", ending="", flush=True) self.stdout.flush()

Note the flush(). This is wat forces the output to be shown to the user before the script finishes. And the same with print:

print(".", end="", flush=True)

Both self.stdout and print will add newline to the output by default but you can disable that by explicitly setting the ending as an empty string. And when you flush your output manually, you’ll get nice and interactive console output for your management commands — voilà!

(Btw. If you have ever wondered about ENV PYTHONUNBUFFERED 1 in some of the Docker images for Python, this is why; disabling output buffering makes reading Docker logs way easier.)

Redirect to Custom URL After Saving in Django Admin

Here’s a quick and dirty admin hack that can save you lots of time if you’re used to browsing between editing objects in admin and vieving the results on a live site.

Put following change_view-method in your admin.py and now you can make links to admin change page that return you back to where you came from:

 class BlogEntryAdmin(admin.ModelAdmin):      ...      def change_view(self, request, object_id, form_url='', extra_context=None):         result = super(BlogEntryAdmin, self).change_view(request, object_id, form_url, extra_context)         if request.GET.get('return_to', False):                         result['Location'] = request.GET['return_to']         return result 

In your template you’d have something like:

 {% if request.user.is_staff %}     <a href="/admin/blog/blogentry/{{ entry.pk }}/?return_to={{ entry.get_absolute_url }}">Edit in admin</a> {% endif %} 

Of course, if you’re smart, you should convert any places that need this kind of functionality with frontend editing tools so you can forget going to the Admin in the first place. But meanwhile, those few lines of code may come in handy!

Django Tip: Custom Admin Templates

One of Django’s best assets is its extensive and very good documentation. However, there are few cases where the documentation is lacking or totally missing. Customizing the automatic admin interface is one of these cases.

In the official Django documentation there are FAQs titled How can I customize the functionality of the admin interface? and The dynamically-generated admin site is ugly! How can I change it?. What they explain, in a nutshell, is that you can use custom JavaScript to add functionality, and modify the CSS to customize how the admin looks. Latter also points to a new documentation page titled Customizing the Django admin interface. All these pages fail to mention, however, that you can customize the templates too.

Even the Django tutorial mentions the possibility of overriding the basic admin templates — just like you can do with any other app. But modifying a template admin-wide is not always enough. Wouldn’t it be great to override templates per-app basis, just like with generic views? Well, turns out you can do exactly that.

The change_list.html and change_form.html templates can be overridden on per app and per object basis. That means that you can customize a template for not only for a specific app, but for a specific model, too. This is very handy!

To override a template with your own, copy the original to your templates directory in one of these locations:

  • admin/<app_label>/<object_name>/change_form.html
  • admin/<app_label>/change_form.html
  • admin/change_form.html

The admin templates have also very flexible blocks built in so you can just extend the original template and override just the blocks you want if you don’t want to write the whole template yourself. This way you can keep the custom template code very nice and clean.

With custom templatetags and custom templates, the possibilities of customizing the Django admin interface are endless. That said, it’s also good to remember that the automatic admin is not perfect for everything. If you feel that it doesn’t quite cut it, just write your own admin views. With the newforms-library that they are cooking at the Django HQ, it’s not only easy, but truly fun.

Further reading

  • NewAdminChanges – A wiki page that explains some of the functionality in the admin app
  • /trunk/django/contrib/admin – The best way of learning things is to look inside. Browse trough the admin app code — just to see that its really just an ordinary (well, not really) Django app.