如何为Django管理模型添加实例表单设置初始数据?

时间:2012-04-03 20:32:03

标签: django forms model admin

如何在显示表单之前在自动生成的表单中设置字段的初始值以添加Django模型实例?我正在使用Django 1.3.1。

我的模型如下:

class Foo(models.Model):
  title = models.CharField(max_length=50)
  description = models.TextField()

并且当前的管理表单确实没什么特别的

class FooAdmin(admin.ModelAdmin):
  ordering = ('title',)

当我使用管理页面添加一个新的Foo实例时,我得到一个很好的表单,其中包含标题和描述的空字段。我想要的是描述字段是通过调用函数获得的模板设置的。

我目前最好的尝试是:

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

但如果我试试这个,我会收到这个Django错误:

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

我不知道这里有什么问题,我应该做些什么才能让它发挥作用。我也觉得这个错误很奇怪(除了我完全看到它的事实)是我的代码中根本没有FooForm?

4 个答案:

答案 0 :(得分:23)

Alasdair的方法很不错但过时了。 Radev的方法看起来很不错,正如评论中所提到的那样,令我印象深刻的是文档中没有任何内容。

除此之外,由于Django 1.7在ModelAdmin中有一个函数get_changeform_initial_data,它设置初始表单值:

def get_changeform_initial_data(self, request):
    return {'name': 'custom_initial_value'}

答案 1 :(得分:21)

您需要在self方法定义中包含__init__作为第一个参数,但在调用超类方法时不应包含它。

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)

话虽如此,模型字段可以对其default进行调用,因此您可能根本不需要定义自定义管理表单。

class Foo(models.Model):
    title = models.CharField(max_length=50)
    description = models.TextField(default=get_default_content)

答案 2 :(得分:9)

超过3年后, 但实际上你应该做的是覆盖admin.ModelAdmin formfield_for_dbfield ..就像这样:

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

干杯;

答案 3 :(得分:0)

添加对象时,按照get_changeform_initial_data()的建议使用Wtower很方便。

但是,当更改现有对象时,这不起作用(请参阅source)。

在这种情况下,您可以按如下方式扩展 ModelAdmin.get_form()(使用 OP 的示例):

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)