14

I have multiple admin sites, so different users get a different experience of editing the objects in the database. Each admin site has a different set of objects exposed, and a different styling. All of this can be done by overriding templates and ModelAdmin objects.

I can't work out how to provide different help_text through the different sites. help_text is always taken straight from the model field definition, and there doesn't seem to be a way to override it.

Am I missing something, or is this impossible?

djvg
  • 11,722
  • 5
  • 72
  • 103
Toby
  • 141
  • 1
  • 3

7 Answers7

17

You can create a new model form and override the help_text there:

class MyForm(forms.ModelForm):
    def __init__(self, *args, **kwargs):
        super(MyForm, self).__init__(*args, **kwargs)
        self.fields['myfield'].help_text = 'New help text!'

then use the new form in your ModelAdmin:

class MyModel(admin.ModelAdmin):
     ...
     form = MyForm

This is the cleaner way to achieve what you want since form fields belong to forms anyway!

ppetrid
  • 3,745
  • 27
  • 29
  • 1
    Oddly, this doesn't seem to work with `editable=False` fields. These don't even appear in form.fields... – Cerin Mar 27 '14 at 19:06
  • Hello @Cerin, yes you're right, read only fields are always excluded from the admin model forms. They are not readonly/disabled form inputs or something like that, it's just the str repr of the model field or method. – ppetrid Mar 27 '14 at 19:15
10

An alternative way is to pass help_texts keyword to the get_form method like so:

def get_form(self, *args, **kwargs):
    help_texts = {'my_field': 'Field explanation'}
    kwargs.update({'help_texts': help_texts})
    return super().get_form(*args, **kwargs)

The help_texts keyword gets eventually passed to the modelform_factory method and rendered as the standard help text from a model in the Django admin.

In case you're using an InlineModelAdmin, you need to override get_formset in the same manner.

This also works if you have readonly_fields in your ModelAdmin subclass.

Erik Kalkoken
  • 30,467
  • 8
  • 79
  • 114
Milan Cermak
  • 7,476
  • 3
  • 44
  • 59
  • 1
    Indeed, I tried the above approaches and this is the only one that works with `readonly_fields`. The reason is that Django Form objects don't handle the `readonly_fields`, so when you try `self.fields['my_field'].help_text = `, you just get a KeyError. – pandichef Jun 17 '20 at 00:28
  • This also works for custom fields that do not exist in the model. – Erik Kalkoken Jul 06 '21 at 16:56
8

In Django 1.9, similar to below works for me

def get_form(self, request, obj=None, **kwargs):
    form = super(MyAdmin, self).get_form(request, obj, **kwargs)
    form.base_fields['my_field'].help_text = """
    Some helpful text
    """
    return form
James Hiew
  • 6,040
  • 5
  • 27
  • 41
1

Cerin is right, but his code does not work well (at least with Django 1.4).

def get_readonly_fields(self, request, obj):
    try:
        field = [f for f in obj._meta.fields if f.name == 'author']
        if len(field) > 0:
            field = field[0]
            field.help_text = 'some special help text'
    except:
        pass
    return self.readonly_fields

You will have to change "author" and the help_text string to fit your needs.

Steve K
  • 10,879
  • 4
  • 39
  • 39
0

You can always change form field attributes on ModelAdmin constructor, something like:

    def __init__(self, *args, **kwargs):
        super(ClassName, self).__init__(*args, **kwargs)
        if siteA:
            help_text = "foo"
        else:
            help_text = "bar"
        self.form.fields["field_name"].help_text = help_text
Carlos H Romano
  • 616
  • 6
  • 9
  • Doesn't work as far as I can see - ModelAdmin.fields is just a list of strings: http://docs.djangoproject.com/en/dev/ref/contrib/admin/#django.contrib.admin.ModelAdmin.fields – Toby Apr 20 '11 at 16:17
  • Oops! Actually, fields will be available through the form attribute of ModelAdmin. Also, make sure parent constructor is called first. See edit. – Carlos H Romano Apr 20 '11 at 16:49
  • Still doesn't work for me: "type object 'ModelForm' has no attribute 'fields'" – Toby Apr 26 '11 at 11:38
  • I am getting the same error as well. Did you find a solution to this? I also tried overriding the get_form() method of the ModelAdmin and manipulating the field with no luck. – onurmatik Sep 09 '11 at 14:50
0

If you've defined a custom field in your admin.py only, and the field is not in your model, then you can add help_text using the class Meta of a custom ModelForm:

(For example: you want to add a users photo on your form, you can define a custom html img tag like this).

class SomeModelForm(forms.ModelForm):
    # You don't need to define a custom form field or setup __init__()

    class Meta:
        model = SomeModel
        help_texts = {"avatar": "User's avatar Image"}


# And tell your admin.py to use the ModelForm:
class SomeModelAdmin(admin.ModelAdmin):
    form = SomeModelForm
    
    # ... rest of the code
Nitin Nain
  • 5,113
  • 1
  • 37
  • 51
  • This approach does not seam to work anymore. I get this error: `django.core.exceptions.ImproperlyConfigured: Creating a ModelForm without either the 'fields' attribute or the 'exclude' attribute is prohibited; form OwnerForm needs updating.` – Erik Kalkoken Jul 06 '21 at 17:02
  • @ErikKalkoken That's a different error. You can easily add an 'exclude' or 'fields' attribute to your class Meta like this: https://docs.djangoproject.com/en/3.2/topics/forms/modelforms/#selecting-the-fields-to-use – Nitin Nain Jul 06 '21 at 17:11
-1

Try this one (might need to replace self.fields with self.form.fields ...)

class PropertyForm(models.ModelAdmin):
    class Meta:
        model = Property
    def __init__(self, *args, **kwargs):
        super(PropertyForm, self).__init__(*args, **kwargs)
        for (key, val) in self.fields.iteritems():
            self.fields[key].help_text = 'what_u_want' 
zzart
  • 11,207
  • 5
  • 52
  • 47