At
Glasses Direct, we are setting up an internal system which needs a simple web UI. As we use
Django for all of our HTTP needs, the admin interface was the obvious, quick solution. All we need to do is write the requisite model, tie it in to the admin interface and we're done! Right? Wrong.
The above description is missing an important part of the puzzle: authentication. Django's admin interface (sensibly) requires authentication by default. However, this piece of our system will only be exposed internally, and we don't want to have to manage credentials for all of our internal users (as we are sadly lacking when it come to internal single sign-on).
The obvious course of action is to remove the authentication. However, this seems to be easier said than done. Firstly, there is no simple switch to disable authentication. Secondly, even were there, we wouldn't want everyone to have access to the full admin interface, largely because it would be confusing for the target users. So we can't get rid of authentication. What we really want is a default user.
A default user is easy enough, you can add it using a User fixture that looks something like this (the easiest way to do this is to create a User object and use the
dumpdata management command):
[{"pk": 2,
"model": "auth.user",
"fields": {
"username": "default",
"is_staff": true,
...
}}]
Voila! After running a
syncdb, you'll have a user who can access the admin interface. Unfortunately, they won't be able to do anything, because they don't have any permissions. Let's fix that by adding some (again, easiest to do this using dumpdata):
[{"pk": 2,
"model": "auth.user",
"fields": {
"username": "default",
"is_staff": true,
"user_permissions": [12, 13, 14],
...
}}]
You can see here that we've granted this user three permissions. The relevant entries will show up in the admin interface. We're done! Right? Wrong.
Everything will seem to be proceeding happily, possibly for quite some time. Then, in a few weeks or months, you'll add another model, or app or something and suddenly your default user will have permission to do really weird things. The problem here is that Django will occasionally regenerate the primary keys of permissions (and other internal objects). So what are we to do? After a fair amount of swearing this afternoon, my colleague Ondrej pointed me in the direction of
natural keys. With these, you can future-proof yourself against primary key oddities:
[{"pk": 2,
"model": "auth.user",
"fields": {
"username": "default",
"is_staff": true,
"user_permissions": [
["add_mymodel", "myapp", "mymodel"],
["change_mymodel", "myapp", "mymodel"],
["delete_mymodel", "myapp", "mymodel"]
],
...
}}]
As with the above examples, you should generate this output with
dumpdata, passing in the
--natural flag on the command line.
To conclude, we've looked at how we can use Django fixtures to give us a default user with a known username and password, with reliable, known permissions. Perfect!
N.B. One option for "auto-authentication" would be to use a middleware class that sets the user on the request to our default user, something along the lines of
this. This component is only meant to be a quick procedure fix, so we haven't taken the time to do that.