29

在显示表单之前,如何在自动生成的表单中设置字段的初始值以添加 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

4 回答 4

37

Alasdair 的方法很好但已经过时了。Radev 的方法看起来相当不错,正如评论中所提到的,让我感到震惊的是,文档中没有任何关于此的内容。

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

def get_changeform_initial_data(self, request):
    return {'name': 'custom_initial_value'}
于 2015-11-11T10:37:14.877 回答
26

您需要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)

话虽如此,模型字段可以将 callable 作为其默认值,因此您可能根本不需要定义自定义管理表单。

class Foo(models.Model):
    title = models.CharField(max_length=50)
    description = models.TextField(default=get_default_content)
于 2012-04-03T21:16:06.913 回答
12

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

干杯;

于 2015-06-28T01:16:14.647 回答
0

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

但是,在更改现有对象时,这不起作用(请参阅源代码)。

在这种情况下,您可以按如下方式扩展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)
于 2021-06-22T08:48:44.500 回答