Hi all,

I want to be able to add extra fields, that I control, to the admin forms. For example, a read-only list of documents authored by the user, which is ManyToMany, so an InlineAdmin doesn't work.

The admin module docs don't really say whether this is possible or not. They have much more to say about excluding, reordering and making fields read-only. However there are hints that it's possible (for ModelForm):

* "Also, if you manually add the excluded fields back to the form, they will not be initialized from the model instance."

* "you can extend and reuse ModelForms by inheriting them. This is useful if you need to declare extra fields"

And the admin interface uses ModelForm and allows you to specify your own form. So I create a custom subclass of ModelForm with the new field:

from django_tables2 import tables
class DocumentsAuthoredTable(tables.Table):
    ...

class DocumentsAuthoredWidget(widgets.Widget):
    def render(self, name, value, attrs=None):
        table = DocumentsAuthoredTable(value)
        return table.as_html()

class DocumentsAuthoredField(forms.Field):
    widget = DocumentsAuthoredWidget


class IntranetUserReadOnlyForm(ModelForm):
    class Meta:
        model = models.IntranetUser

    documents_authored = DocumentsAuthoredField()

Now I have to do some ugly things. The widget has no access to the instance (model), so I have to provide some data for it, by adding a method to either the IntranetUserReadOnlyForm or the model. I don't want to introduce a circular dependency in the model, so I have to do this in the form:

def __init__(self, data=None, files=None, auto_id='id_%s', prefix=None,
        initial=None, error_class=ErrorList, label_suffix=':',
        empty_permitted=False, instance=None):

        """
        Add a "method" to the initial data which is used to lookup the
        value of documents_authored by BoundField.
        """

        if initial is None:
            initial = {}
        from django.utils.functional import curry
initial['documents_authored'] = curry(self.get_documents_authored, instance)

        super(IntranetUserReadOnlyForm, self).__init__(data, files,
            auto_id, prefix, initial, error_class, label_suffix,
            empty_permitted, instance)

    def get_documents_authored(self, instance):
        # print "get_documents_authored(%s)" % instance
        return instance.document_set.all()

And now I have to do a really horrible hack in the Admin class, to add this field into the form:

class IntranetUserAdmin(AdminWithReadOnly):
    documents_authored = None

This is because AdminReadOnlyField tries to call label_for_field() on the field, which insists that it be a member of the Model or the Admin, not the Form. It doesn't really care what type of attribute it is, but it throws an exception if it's not there at all:

File "/usr/lib/pymodules/python2.6/django/template/defaulttags.py", line 227, in render
    nodelist.append(node.render(context))
File "/usr/lib/pymodules/python2.6/django/template/defaulttags.py", line 190, in render
    values = list(values)
File "/usr/lib/pymodules/python2.6/django/contrib/admin/helpers.py", line 103, in __iter__
    model_admin=self.model_admin)
File "/usr/lib/pymodules/python2.6/django/contrib/admin/helpers.py", line 135, in __init__
    label = label_for_field(field, form._meta.model, model_admin)
File "/usr/lib/pymodules/python2.6/django/contrib/admin/util.py", line 252, in label_for_field
    raise AttributeError(message)
TemplateSyntaxError: Caught AttributeError while rendering: Unable to lookup 'documents_authored' on IntranetUser or IntranetUserAdmin

So please can we have an easier way to add fields to an admin form? Ideally I wouldn't have to change the Model or the Admin at all, just add a new attribute to the custom Form.

Also please can the widget have access to the request? Rendering out a DjangoTable (with proper links) needs this.

Cheers, Chris.
--
Aptivate | http://www.aptivate.org | Phone: +44 1223 760887
The Humanitarian Centre, Fenner's, Gresham Road, Cambridge CB1 2ES

Aptivate is a not-for-profit company registered in England and Wales
with company number 04980791.

--
You received this message because you are subscribed to the Google Groups "Django 
developers" group.
To post to this group, send email to django-developers@googlegroups.com.
To unsubscribe from this group, send email to 
django-developers+unsubscr...@googlegroups.com.
For more options, visit this group at 
http://groups.google.com/group/django-developers?hl=en.

Reply via email to