We (GCap, large commercial radio company in the UK) have been
developing against the newforms-admin branch for a few months now, and
based on that experience I have a number of suggestions for simple
hooks that could be added to make it easier to customise.

1. Provide a custom template for a changelist / change form

You should be able to specify a custom template for those pages in
some way on the ModelAdmin object. At the moment select_template() is
used to allow custom templates to be specified, but that isn't nearly
flexible enough: it forces you to name your templates according to a
certain naming scheme (e.g. admin/events/venue/change_form.html) but
that means that you can't offer two admin interfaces with different
templates for editing a specific thing, which is kind of the whole
point of newforms admin allowing you to set up more than one admin
site. It also forces you to keep your templates in an admin/ hierarchy
which can be a bit limiting.

There are two potential solutions to this. The first is to have a
change_form_template option on the ModelAdmin:

class EventAdmin(ModelAdmin):
    change_form_template = 'foo/bar/event_change_form.html'

The other is to have the template provided by a method which can be
over-ridden:

class EventAdmin(ModelAdmin):
    def change_form_template(self, object=None):
        return select_template(['foo.html', 'bar.html'])

Either look OK to me - the second is probably better as it lets you
run a bit of logic to decide which template to use.

Another benefit of this approach: it makes it easier to extend the
default admin template without fear of running in to the dreaded
template recursion problem.

Custom templates for ModelAdmins is absolutely my number one request
for newforms admin. It would make a huge number of customisations a
great deal easier (we have a UED guy who keeps on coming up with
genuinely good ideas for tweaks to our various admin screens).

2. Better hooks for custom form fields (esp. ForeignKey choices)

Every time I write a formfield_for_dbfield method I want to strangle a
kitten. I am not alone; this is pretty much the consensus among the
developers I work with. There really, really needs to be a better way
of doing per-form-field customisations.

One extremely important example is being able to alter the choices in
a ForeignKey or ManyToMany field, as discussed on this ticket:

http://code.djangoproject.com/ticket/3987

This is critically important because one of the big new features in
newforms-admin is the ability to do row-level permissions, thanks to
the extremely neat has_change_permission / has_change_permission /
has_delete_permission hooks and the ability to over-ride the queryset
for a changelist.

Unfortunately this doesn't go quite far enough. If you're dealing with
row level permissions ("user X can edit article Y") you also need to
be able to restrict foreign key relationships. User X might only be
allowed to assign an article to 4 out of the 30 categories on a site,
for example.

Ticket #3987 solves this in a reasonable way, but I'm not too keen on
the suggested dynamic method name (dynamic_FIELDNAME_choices). I
talked this over a bit with Stuart Langridge and we came up with the
following:

class BookAdmin(ModelAdmin):
    ...
    def choices_for_author(self, request, book=None):
        user = request.user
        if not book:
            # Creating a new book: return queryset for author choices
that
            # the current user is allowed to assign
        else:
            # Editing an existing book; maybe do something a bit
different?

Using choices_for_FIELDNAME feels like it fits better with existing
Django conventions (like clean_FIELDNAME in newforms).

Then we thought, why not take this further? The most common things you
do with formfield_for_dbfield are setting a custom widget and setting
a custom formfield. So why not allow these:

    def widget_for_author(...):
        return CustomWidgetOfSomeSort()

    def formfield_for_title(...):
        return FormFieldOfSomeSort()

But what if you want to reuse the same method for many different
fields? We could provide fallback methods widget_for(self, dbfield),
formfield_for(self, dbfield) and choices_for(self, dbfield) to cover
that.

Yes, this means adding a lot of potential methods to ModelAdmin
(though note that since they are dynamically looked up we don't have
to add any real new methods to the actual class itself). I think
that's fine - it makes for an API that is clean, powerful and
extremely easy to understand.

I realise that some of the above could be mocked up just by writing a
custom formfield_for_dbfield method without patching newforms-admin at
all. I plan to do that as a proof of concept.

3. Make it easier to include custom CSS and JavaScript

By far the easiest way to tweak the admin is with a bit of unobtrusive
CSS and JavaScript. We're using jQuery a lot for this (to great
effect; for example, we've got a really nice drag-and-drop reordering
interface that was added entirely as an unobtrusive enhancement), but
it's still a bit of a pain to add custom CSS / JS. Here's the pattern
at the moment:

class AdminFormWithMedia(forms.ModelForm):
    class Media:
        js = ('blah/blah/blah.js',),
        css = {
            all': ('blah/blah.css',)
        }

class ArticleAdmin(admin.ModelAdmin):
    form = PageFormWithMedia

That's quite a lot of boilerplate just to add some CSS and JS, and
it's weird to be putting it on the form rather than just specifying it
for a template (not to mention this method doesn't let you add custom
CSS/JS to the changelist page).

Solving the custom template problem above would solve this as well.

A few other things we've found difficult:

* Customising the admin homepage (without writing a new one from
scratch)
* Changing the application labels that appear in the admin homepage -
we needed to do this and it ended up being a complete nightmare (our
end users don't want to see an interface full of obscure terms like
gcap_sectional_revisions).
* Making some fields read-only in some admin screens (again,
reasonably well addressed by easier custom widgets above)

The thing is, none of these problems are particularly difficult to
address. As it stands, newforms-admin customisation is 90% of the way
there - adding just a few more hooks would solve almost all of the
above issues.

I would be delighted to produce patches for these, but I thought it
best to air the ideas on the mailing list first.

Cheers,

Simon


--~--~---------~--~----~------------~-------~--~----~
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 [EMAIL PROTECTED]
For more options, visit this group at 
http://groups.google.com/group/django-developers?hl=en
-~----------~----~----~----~------~----~------~--~---

Reply via email to