Monday, August 18, 2008

Django 1.0 custom admin two fields shown as one

I needed a way to have two model fields to be shown/edited on one form field. And I came up with the following.

(CurrencyField (expense) shows and edits fields `value` and `currency` in the actual model)

from django.contrib import admin
from budget.models import Expense
from django import forms
from django.forms.util import ValidationError

class CurrencyField(forms.CharField):
def clean(self, value):
amount = 0
currency = ''
amount = float(value.split(" ")[0].strip())
except (ValueError, TypeError), te:
raise ValidationError('Amount is incorrect!')

currency = value.split(" ")[1].strip().upper()
if len(currency) != 3:
raise TypeError('cur')
except (ValueError, TypeError), te:
raise ValidationError('Currency is incorrect! Should be three letter universal sign (e.g. EUR)')

return (amount, currency)

class ExpenseForm(forms.ModelForm):
expense = CurrencyField()
def __init__(self, *args, **kwargs):
super(ExpenseForm, self).__init__(*args, **kwargs)
self.initial['expense'] = "%s %s" % (self.instance.value or '',
self.instance.currency or '')

def save(self, commit=True):
self.instance.value, self.instance.currency = self.cleaned_data['expense']
return super(ExpenseForm, self).save(commit)

class Meta:
model = Expense

# Note added:
# Expense is like this:
# class Expense(models.Model):
# ...
# value = models.FloatField(...) # This contains the amount of currency, like 120.32
# currency = models.CharField(...) # Currency is e.g. 'USD', 'EUR' identifier of currency
# ...

class ExpenseAdmin(admin.ModelAdmin):
list_display = ('date', 'time', 'local_currency', 'in_euro', 'description', 'tags')
ordering = ('date','time')
form = ExpenseForm
fields = ('expense', 'date', 'time', 'description', 'tags'), ExpenseAdmin)

Tuesday, August 12, 2008

Django 1.0 admin custom inlines


class ChangeSetForm(forms.ModelForm):
dosomething = forms.BooleanField(label="Do something")
class Meta:
model = ChangeSet
exclude = ('modified',) # Note: This doesn't work!
fields = ('old_title',) # Note: This doesn't work!

ChangeSetInlineFormSet = inlineformset_factory(
Article, ChangeSet,
form = ChangeSetForm

class InlineChangeSet(admin.TabularInline):
model = ChangeSet
form = ChangeSetForm
extra = 0
raw_id_fields = ('editor',)
fields = ('old_title', ) # This works.


Completely custom inline (without delete checkbox etc)