Reputation: 3958
How can I set an initial value of a field in the automatically generated form for adding a Django model instance, before the form is displayed? I am using Django 1.3.1.
My model is the following:
class Foo(models.Model):
title = models.CharField(max_length=50)
description = models.TextField()
and the current admin form is really nothing special
class FooAdmin(admin.ModelAdmin):
ordering = ('title',)
When I use the admin page to add a new instance of Foo, I get a nice form with empty fields for title and description. What I would like is that the description field is set with a template that I obtain by calling a function.
My current best attempt at getting there is this:
def get_default_content():
return 'this is a template for a Foo description'
class FooAdminForm(django.forms.ModelForm):
class Meta:
model = Foo
def __init__(self, *args, **kwargs):
kwargs['initial'].update({'description': get_default_content()})
super(FooAdminForm, self).__init__(self, *args, **kwargs)
class FooAdmin(admin.ModelAdmin):
ordering = ('title',)
form = FooAdminForm
but if I try this I get this Django error:
AttributeError at /admin/bar/foo/add/
'FooForm' object has no attribute 'get'
Request Method: GET
Request URL: http://localhost:8000/admin/bar/foo/add/
Django Version: 1.3.1
Exception Type: AttributeError
Exception Value: 'FooForm' object has no attribute 'get'
Exception Location: /www/django-site/venv/lib/python2.6/site-packages/django/forms/widgets.py in value_from_datadict, line 178
I don't know what is wrong here, and what I should do to make it work. What I also find strange about this error (apart from the fact that I see it at all) is that there is no FooForm in my code at all?
Upvotes: 33
Views: 46370
Reputation: 14325
When adding new objects, it is convenient to use get_changeform_initial_data() as suggested by Wtower.
However, when changing existing objects, that does not work (see source).
In that case, you could extend ModelAdmin.get_form() as follows (using the OP's example):
def get_form(self, request, obj=None, change=False, **kwargs):
if obj and not obj.description:
obj.description = get_default_content()
return super().get_form(request, obj, change, **kwargs)
Upvotes: 4
Reputation: 891
More then 3 years later,
But actually what you should do is override admin.ModelAdmin formfield_for_dbfield
.. like this:
class FooAdmin(admin.ModelAdmin):
def formfield_for_dbfield(self, db_field, **kwargs):
field = super(FooAdmin, self).formfield_for_dbfield(db_field, **kwargs)
if db_field.name == 'description':
field.initial = 'My initial description'
elif db_field.name == 'counter':
field.initial = get_counter() + 1
return field
Cheers;
Upvotes: 15
Reputation: 19922
Alasdair's approach is nice but outdated. Radev's approach looks quite nice and as mentioned in the comment, it strikes me that there is nothing about this in the documentation.
Apart from those, since Django 1.7 there is a function get_changeform_initial_data
in ModelAdmin
that sets initial form values:
def get_changeform_initial_data(self, request):
return {'name': 'custom_initial_value'}
Upvotes: 44
Reputation: 309089
You need to include self
as the first argument in your __init__
method definition, but should not include it when you call the superclass' method.
def __init__(self, *args, **kwargs):
# We can't assume that kwargs['initial'] exists!
if 'initial' not in kwargs:
kwargs['initial'] = {}
kwargs['initial'].update({'description': get_default_content()})
super(FooAdminForm, self).__init__(*args, **kwargs)
Having said that, a model field can take a callable for its default, so you may not have to define a custom admin form at all.
class Foo(models.Model):
title = models.CharField(max_length=50)
description = models.TextField(default=get_default_content)
Upvotes: 32