RSS
 

Posts Tagged ‘django’

O Hai Django AdminPlus

04 Mar

Last night, as happens sometimes, I was wishing it was possible to add some of our custom admin views to the Django admin’s index page. It’s kind of a pain to have to type the URL every time, especially when talking to other people: “It’s in the admin, but no, you can’t… just go to this URL.”

So I was reading the Django admin docs and, frankly, they aren’t great. They tell you about the benefits of subclassing AdminSite, or running multiple AdminSites, but they never really mention how to do it.

So, with a little trial and error, I wrote my AdminSite subclass and figured out how to use it. It simplified a bunch of code in our custom admin app, so I thought I would share it.

Here’s Django AdminPlus (and on PyPI).

AdminPlus adds a method, admin.site.register_view, that connects an arbitrary view function to your admin, and puts a link to it on the admin index page. If you put calls to register_view in someapp/admin.py, they’re picked up during the normal admin.autodiscover() process.

  1. # myapp/admin.py
  2. from django.contrib import admin
  3. from django.shortcuts import render_to_response
  4.  
  5. def my_admin_view(request):
  6.     return render_to_response(‘myapp/admin/view.html’)
  7. admin.site.register_view(‘mypath’, my_admin_view)
  8.  
  9. # With an optional ‘name’ parameter:
  10. def my_other_admin_view(request):
  11.     return render_to_response(‘myapp/admin/other.html’)
  12. admin.site.register_view(‘otherpath’, my_other_admin_view, ‘Fancy Stuff!’)

Assuming your admin URLs start with admin/, this will make my_admin_view available at admin/mypath and my_other_admin_view available at admin/otherpath, but it also puts them in a new section on the admin index, so you don’t even need to worry about the URL.

If no name is given we try to guess from the name of the view function.

That’s about it! Read the README and the other docs and enjoy!

 
2 Comments

Posted in Articles

 

The Future of TodaysMeet

30 Jan

This is the second half of a two-part post. Start with part 1.

TodaysMeet is an interesting challenge because it has components that are absolutely real-time and should be built like a messaging system, not a CMS, and parts that aren’t real-time at all, and can totally be built like a CMS.

TodaysMeet has one loosely-coupled component, its Twitter integration. The site knows nothing about the daemon that executes Twitter searches and populates the database. If anything, I think it’s currently too loosely coupled, but it’s given me some insight into how to build the new system.

The guiding principles of this design are:

  • DRY. Only one part of the app should know about the canonical data store (MySQL for now).
  • Loosely coupled. A failure in one part of the service shouldn’t affect other parts.
  • Real-time, event-driven. Periodic polling is bad. Periodic Twitter searches are particularly so.
  • Use the right tool for the right job.

Obviously I’m a fan of Django. I could port TodaysMeet directly, using something like Playdoh to bootstrap the process, and get done relatively quickly. Django gets me a lot of stuff for free: a solid data store, users (something I want to add in a limited capacity, eventually), even a framework for building the crons and daemons necessary for running the site.

But Django is a lousy way to serve real-time content via long polling or socket connections.

I can easily serve real-time content via Node.js. I can do long polling or sockets. It’s also a great way to handle Twitter integration because I can just leave a connection to their streaming API, and handle new tweets as soon as they happen instead of checking periodically.

But even with things like Sequelize, MySQL connectivity through Node still feels awkward. (I think it will get better but I’m impatient.) And serving fairly static content is just weird.

So, Towelie, do you want to go real-time with Node, or do you want to use Django?

I’ll use… both!

Read on for a more technical overview. And a picture!

Read the rest of this entry »

 
Comments Off

Posted in Articles

 

Introducing Waffle for Django

23 Jan

Waffle is a feature-flipping library for Django that strives to be easy and intuitive, and work with both the Django/Jingo/Jinja2 stack we use at Mozilla, and Django templates out of the box.

Waffle lets you define various reasons a flag can be active for a given request. You can make flags active for all superusers, or authenticated users, for example. You can also define a percentage of “everyone else” who will see the flag as active.

If Waffle uses a dice roll to determine if the current request will have the flag turned on, it sets a cookie so the flag will continue to be active or inactive for subsequent requests. For all subsequent requests, the cookie value is respected. Waffle only sets cookies if a given flag was actually used during the request.

Flags are global: once a given flag is set for a user, that flag is set on every request or page view. You can test a flag on /foo and trust that a given user will see the same flag value on /bar.

Flags can be used in templates, in views, or even to hide whole views.

Optionally, Waffle can activate flags based on the query string, so you can guarantee a flag will be on or off for any request for testing.

Check out Waffle on Github and let me know what you think!

 
6 Comments

Posted in Articles

 

Django Fixtures with Circular Foreign Keys

29 Sep

If you create a nice, perfectly normalized database, you (probably) won’t ever run into circular foreign keys (when a row in table A references a row in table B that references the same row in table A).

In the real world, this happens pretty regularly. The most common situation is a “current” or “last” denormalization. You don’t really want to do a subquery with a sort every time you want to know the latest post in a forum thread, or current revision of a wiki page.

The problem—one we’ve been dealing with since we decided to rebuild SUMO—is that trying to load data with circular foreign keys produces a “chicken and the egg” situation: since each row depends on the other, neither can be loaded first.

(This is part of a bigger problem with MySQL, which is that it lacks deferred foreign key checks.)

The solution to this is to temporarily disable foreign key checks while you load in data. It’s not hard, but Django is so far unwilling to do it.

Well, now we get the chance to see if their concerns are realistic: with the latest commit to Jeff Balogh’s test-utils package for Django, we’re disabling foreign key checks during fixture loading.

Both SUMO and AMO have had to do some acrobatic hackery to get around the limit. This solution is definitely a filthy hack, but it’s contained in a single, small place, rather than spread throughout test cases in multiple projects.

Suggestions for improving this hideous monkey patch are welcome, but in the meantime I’ll be removing the gross parts from Kitsune that we needed to work around this.

 
3 Comments

Posted in Articles

 

Playing with the Real-Time Web

08 May

Since I left Facebook, I’ve been working on a little project to take its place as an aggregator, or a central hub of all me-related activity on the internet: Planetoid.

Right now, if you’ve got the patience to get it up and running without documentation, Planetoid is just a run of the mill, particularly ugly feed aggregator. It’s built on Django, and it has a cron job that well pull in updates from all your feeds. (You edit the list of feeds in the Django admin.)

But that’s boring.

This is just the platform I needed. Now, I want to make it real-time.

The first step is implementing Pubsubhubbub subscriber support. Then the cron will only be necessary for feeds that don’t push update notifications.

The next step is where things get interesting: both the cron and pubsubhubbub subscriber will push notifications using Redispubsub feature. Node.js, running in parallel, will subscribe to the channel in Redis and will provide the server half of a Comet/long-polling setup, the rest of which will be implemented on the client side.

Then I just need to enable pubsubhubbub in a few places, and anyone sitting on jamessocol.com should see things like blog posts in real-time, and everything else automatically with a small lag.

Real-time and the tools to do it are very, very fun.

 
Comments Off

Posted in Articles