Archive for the ‘programming’ Category.

Default (initial) value in Django's admin for a choice field

I was trying to set the initial value for a choice field in the admin like this:

from django import forms
from django.contrib import admin
from mptt.admin import MPTTModelAdmin
from author.models import Author
from serials.constants import STATUS_CHOICES

class AuthorAdminForm(forms.ModelForm):
    class Meta:
        model = Author

class AuthorAdmin(MPTTModelAdmin):
    form = AuthorAdminForm(initial={'status': STATUS_CHOICES[0][0]}), AuthorAdmin)

Logically, I should have been able to do it this way, I thought, at least according to the docs. But instead it was giving me this error: TypeError: issubclass() arg 1 must be a class. (Uh, ok.) After a bit of searching, I eventually found this comment, and realized I must be trying to instantiate a form that the admin would instantiate automatically, had already been instantiated, or something like that.

After some more searching, I found the answer on the way to do what I needed here:

from django import forms
from django.contrib import admin
from mptt.admin import MPTTModelAdmin
from author.models import Author
from serials.constants import STATUS_CHOICES

class AuthorAdminForm(forms.ModelForm):
    class Meta:
        model = Author

    def __init__(self, *args, **kwargs):
        super(AuthorAdminForm, self).__init__(*args, **kwargs)
        self.initial['status'] = STATUS_CHOICES[0][0]
class AuthorAdmin(MPTTModelAdmin):
    form = AuthorAdminForm, AuthorAdmin)

Yay! Hope this helps someone else who has the same issue. :)

Django trick: using named admin urls in templates

To add a link to an admin page on the user-side of your django site, you can use the named url patterns. (Seems like a simple and fairly straightforward thing to want to do, but I frequently find that things are not so simply found in most open source docs, nor are the examples always useful. But my usual open source docs rant is for another day. *g*)

It took a bit of digging, but I finally found that the admin url pattern options are listed here. From that, I was able to figure out that if I wanted to link to the edit (change action) page (parameter) for an article (model) in the app article, the pattern was:

{{ app_label }}_{{ model_name }}_action [parameters]

The namespace for the admin is, of course, admin, so putting that together using the {% url %} template tag, you get:

<a href="{% url 'admin:article_article_change' %}">{% trans 'Edit' %}</a>

That correctly creates the relative url to /admin/article/article/2. Yay!

Be sure to load the admin template tags in your template, too, or it won't work:

{% load admin_urls %}

Et voilà! *vbg* Hope this saves someone else a bit of time.

(This works for Django 1.4, btw.)

Htaccess trick

Here's what I ended up putting in an .htaccess file for each of the various sites I run/own/manage to participate in the SOPA/PIPA protest today:

RewriteEngine On
RewriteCond %{TIME_HOUR}%{TIME_MIN} >0459
RewriteCond %{TIME_HOUR}%{TIME_MIN} <1701 RewriteCond %{TIME_YEAR}%{TIME_MON}%{TIME_DAY} =20120118 RewriteRule ^(.*)$ [R=307,NC,L]

Learn something new every day. *g*

This forwarded each site to the protest page for a certain time frame (the length of the protest, adjusted for the server's time). You could use something like that to put a site in maintenance mode, for example. Just be sure to add a RewriteCond that checks for your IP so you can get to the site to test it. ;)

Django, MySQL, and Windows 7 64-bit installation tips

Here are the solutions to a few annoying things that caused issues when I was installing Python, Django, and MySQL on a new Windows 7 64-bit laptop.

1. Be sure to set your PYTHONPATH variable.

After I installed ActiveState Python, it didn't set up the environmental variable. I added it and restarted the command window, and voilà. (I don't remember having to set that up manually on my XP machine, but I could be mistaken since it's been a very long time since I installed everything on that machine. Regardless, it's a good thing to check. *g* Also check your PATH variable, to make sure that Python, Django, and MySQL are all in there.)

2. Assign the read_default_file setting in the database dictionary.

I was getting "Error 2003: Can't connect to MySQL server on 'localhost' (10061)." It wasn't the firewall blocking the port, because mysql is running on a socket. (Though I could be wrong, as I just switched over to Codomo from ZoneAlarm, which had issues with Win7 64-bit and Filezilla, and I haven't learned all of Codomo's quirks yet, so who knows?) Even though I've got the admin service set up to execute "C:\progs\mysql\bin\mysqld" --defaults-file="C:\progs\mysql\my.ini" MySQL, it still wasn't finding the ini file for some reason. Weirdly, telling Django which my.ini file to run MySQL with fixed it. In your, in the database section, you'll add the OPTIONS entry:

    'default': {
        'ENGINE': 'django.db.backends.mysql',
        'NAME': 'database_name',                      
        'USER': 'username',
        'PASSWORD': 'password',
        'HOST': '',
        'PORT': '',
        'OPTIONS': {
            'read_default_file': 'c:\path\to\your\my.ini',

Another simple but useful Django trick

Say you need the full URL of the current page you're displaying that you need to use on the template of that page, for example, to add links to Facebook, Delicious, etc., and you don't want to have additional JavaScript that you didn't write on your pages. (Why yes, I'm a control freak, shush. :P) Also say that you don't want to use the sites framework to hack it together. The permalink decorator won't work, either, because that just gives you the relative link.

Thankfully, there's a new request object that's been added to 1.0 that will do it.

To use it, include the bolded bit in your file, as part of each view where you want to have the variable available:

return render_to_response('dir/template.html', {'object': obj, 'link': request.build_absolute_uri()}, RequestContext(request))

Then you can use the link variable on the template where you need the URL:

<a href="{{ link|urlencode }}&t={{ title|urlencode }}">

I have yet to figure out how to get it to work with generic views, so feel free to holler if you know how. *vbg*