Code

Opened 4 years ago

Last modified 15 months ago

#14370 new New feature

Adding support for Autocomplete in contrib.admin

Reported by: tyrion Owned by: nobody
Component: contrib.admin Version: master
Severity: Normal Keywords: autocomplete, jquery, javascript, widgets, admin
Cc: subsume, tyrion, sehmaschine@…, istruble, eduardocereto, thomas.schwaerzl@…, andreterra@…, djangoproject.com@…, thijs.triemstra@…, hv@…, 4glitch@… Triage Stage: Accepted
Has patch: yes Needs documentation: yes
Needs tests: no Patch needs improvement: yes
Easy pickings: no UI/UX: yes

Description

I've tried to implement Autocomplete for contrib.admin using jQuery UI Autocomplete.
Here's the code: http://bitbucket.org/tyrion/django
Here's a live demo: http://djangoac.tyrion.mx/admin/ (login with test/test).
(It supports both ForeignKey and ManyToMany).

I don't know if I should attach the complete patch here. It's kinda big (I included jquery-ui), however you can see it online at http://bitbucket.org/tyrion/django/changeset/04488ec05e92 ).

Now it's implemented using an "autocomplete_fields" attribute which is a dict (field:related_fields):

class MyModelAdmin(admin.ModelAdmin):
    autocomplete_fields = {'user': ('username', 'email')}


But because I've been asked:

<jezdez> tyrion-mx: what about making the autocomplete_fields a dict of dicts, to be able to specify additional options for the autocompletion, e.g. number of search results or a custom label function?

I've written this patch (for my code) http://dpaste.com/hold/251220/
that let's you control the "value" (what is displayed in the input), "label" (what is displayed in the dropdown) and "limit" (max number of results) properties.

With it a modeladmin could look something like this:

class DummyAdmin(admin.ModelAdmin):
    autocomplete_fields = dict(
        user1 = dict(
            fields = ('username', 'email'),
            value = 'username',
            limit = 10,
        ),
        friends = dict(
            fields = ('username', 'email'),
            label = u'%(first_name)s %(last_name)s',
            value = 'email',
        ),
    )

In that case "value" and "label" can be either a function, a fieldname or a string like u'%(username)s "%(email)s"'.

Attachments (1)

ticket-14730.diff (92.3 KB) - added by istruble 3 years ago.

Download all attachments as: .zip

Change History (29)

comment:1 Changed 4 years ago by tyrion

  • Has patch set
  • Needs documentation unset
  • Needs tests unset
  • Patch needs improvement unset

comment:2 Changed 4 years ago by subsume

  • Cc subsume added

comment:3 Changed 4 years ago by subsume

Would it be reasonable to deprecate raw_id_fields in favor of this?

comment:4 Changed 4 years ago by tyrion

Now the autocomplete feature can be used with any type of field.
i.e. (email is an EmailField)

class MyModelAdmin(admin.ModelAdmin):
    autocomplete_fields = dict(
        email = dict(
            queryset = User.objects.all(),
            fields = ('^email', '^username'),
            id = 'email',
            value = 'email',
        ),
    )

comment:5 Changed 3 years ago by anonymous

  • Cc tyrion added

comment:6 Changed 3 years ago by jezdez

  • Triage Stage changed from Unreviewed to Accepted

Marking this accepted after the discussions on IRC and the mailing list.

comment:7 Changed 3 years ago by robhudson

A couple notes after trying to get this to work on an existing project...

  1. This definitely needs documentation on how to enable these widgets. I took what seemed like the obvious approach and tried adding the MultipleAutocompleteWidget to an existing m2m field and got an error that the __init__ takes 2 arguments and only 1 was given. After perusing the source I see it takes a settings dict so I passed in an empty one that seemed to make it happy. Personally I think an empty dict should be a default along with default settings so the user only has to override via:
    formfield_overrides = {
        models.ManyToManyField: {'widget': MultipleAutocompleteWidget}
    }
  1. It looks like the jquery-ui.min.js isn't loaded anywhere. I get an error in the console that $.widget is not a function. If I add jquery-ui to the list of inner class Media it moves me past this error to another one...
  1. (void 0) is undefined on line 15 of jquery-ui.js, which is the $.ui = $.ui || {}; line. This is about where I stopped. I tried changing jquery-ui to load django.jQuery rather than jQuery as a test and still got the error. Not sure about this one.

Hope that feedback helps some. I'm happy to continue trying and poking at this.

comment:8 Changed 3 years ago by tyrion

  1. The documentation is at the top of the page. You can't use formfield_overrides with autocomplete_fields.
  2. jquery-ui.min.js is loaded in ModelAdmin._media.
  3. You shouldn't get any js error if you use it as documented.

Let me know if you manage to make it work :)

comment:9 Changed 3 years ago by robhudson

  1. I should have caught the above code sample when trying to hook this up, but this will need docs in the patch as part of the Django docs before this is committed. That's what I was looking for and referring to.

2 & 3. Ignore. Apologies.

OK, so now that I have it working a few comments...

  1. Looks like it could use a little CSS touch-up work. I didn't see any CSS changes or additions on the bitbucket changes.
  1. I think some reasonable defaults should be considered so not all keys of the dict need to be specified. e.g. if queryset isn't specified assume an .all() query?
  1. Django docs.
  1. Have you considered how we might test this? It would probably be pretty easy to test that the admin hooked up the view that the autocomplete calls. Testing the JS itself would prove a bit tougher but jezdez and I have mentioned that we probably need to figure this out eventually (QUnit?).

comment:10 Changed 3 years ago by anonymous

Sure, some documentation should be added.

  1. I am not good with CSS, In my local copy I included the jquery lightness theme, with some improvements for contrib.admin...
  1. There are already some "reasonable" defaults, the queryset is required only for non fk/m2m fields.

For fk/m2m fields the queryset if not specified is taken from the field (with respect to limit_choices_to).
The only required key should be "fields" (which maybe should be renamed to "search_fields").

  1. I don't know how the javascript could be tested. Do other Admin widgets have javascript tests?

comment:11 Changed 3 years ago by jezdez

  • Needs documentation set

It would be great if you could attach a diff of the current state to this ticket.

comment:12 Changed 3 years ago by anonymous

  • Cc sehmaschine@… added

comment:13 Changed 3 years ago by sehmaschine@…

I´ve just tested the patch and I think it´s great.

there´s just one minor issue: I´d still show the lookup-icon, because in some (rare) cases you won´t find an object without.

comment:14 Changed 3 years ago by jezdez

Would making that an option per autocomplete field option make sense?

comment:15 Changed 3 years ago by sehmaschine@…

I personally wouldn´t make that an option because of coherence (the raw-id-field also shows the lookup-icon).
however, if the icon is there by default and I´m having the option to disable it ... why not. the main point is that the lookup-icon is needed.

just to clarify: with showing the lookup-icon, I don´t mean to show the input-field for the object-id as well.

comment:16 Changed 3 years ago by jezdez

Ah, ok, that'd make sense indeed, agreed.

comment:17 Changed 3 years ago by istruble

  • Cc istruble added

I have added the lookup/search icon, a splash of CSS, a pinch of documentation and a sprinkling of testing.

No automated javascript testing at this point. Based on manual testing, I do know that IE6 and IE7 do not work with the current code. FF, Safari and Chrome seem like they are good to go. It would be great to hear from someone with IE8 or greater what the experience is like.

Patch file attached to the ticket based on django-trunk within the last few days.

Changed 3 years ago by istruble

comment:18 Changed 3 years ago by istruble

Performed a jslint cleanup of the autocomplete.js and found some trailing commas that were breaking things for IE. IE6 and IE7 now work. IE8 and up should also work.

comment:19 Changed 3 years ago by eduardocereto

  • Cc eduardocereto added

is jqueryUI really needed? If that dependency is removed I think this is more likely to be accepted. Since jqueryUI is quite large and there's no reason to use it at all.

comment:20 Changed 3 years ago by PF_tschwaerzl

  • Cc thomas.schwaerzl@… added
  • Severity set to Normal
  • Type set to Uncategorized

comment:21 follow-up: Changed 3 years ago by airstrike

  • Cc andreterra@… added
  • Keywords autocomplete, jquery, javascript, widgets, admin added; autocomplete removed
  • Patch needs improvement set
  • Type changed from Uncategorized to New feature
  • Version changed from 1.2 to SVN

could we possibly get a "real" patch for this? 1.3 has been released and the bitbucket repo now differs greatly from trunk, plus some of code was on dpaste (?) and is now gone, so it's extra hard to dive into the issue at the moment.

i'd like to help with this and make it "official" as soon as possible. in a worst case biggest noob scenario i'll test and write docs!

comment:22 in reply to: ↑ 21 Changed 3 years ago by tyrion

Replying to airstrike:

could we possibly get a "real" patch for this? 1.3 has been released and the bitbucket repo now differs greatly from trunk, plus some of code was on dpaste (?) and is now gone, so it's extra hard to dive into the issue at the moment.

If you look at contrib.admin in my django bb repo, you can get an idea of how it was implemented.
In the mean time I used that code to rewrite django-autocomplete. Now it's far more customizable than the initial patch in this ticket (but it is implemented as a generic app, not as a patch to contrib.admin, since I thought that other apps could benefit of the code too).

  • Is tying a generic AutocompleteWidget that could be used by other apps to contrib.admin a good thing to do?
  • Should we also add the "add another" link?

If we're satisfied with the current implementation, updating it to the trunk shouldn't be too difficult.

comment:23 Changed 3 years ago by haras

  • Cc djangoproject.com@… added
  • Easy pickings unset

comment:24 Changed 3 years ago by julien

  • UI/UX set

comment:25 Changed 2 years ago by Thijs Triemstra <thijs.triemstra@…>

  • Cc thijs.triemstra@… added

comment:26 Changed 2 years ago by etienned

I just want to let you know that I did a fork of the excellent tyrion's django-autocomplete that add a little bit more integration with the Django Admin and other things:

  • Highlight (put in bold the search term in the results list)
  • Auto Focus (automatically select the first result of the list) need jQuery UI >= 1.8.11
  • Zebra (colorize list rows in alternance)
  • Simple Cache (cache each different query)
  • Add button (the green plus to add a new item for a Relation Field)
  • Lookup button (the loupe like in a RawIdField to select from the complete list)
  • Multiterms (possibility to have completion on many terms in one field separated by a delimiter, for example: a tag field)
  • Distinct result (get only distinct results for all fields excepted Relation fields)

Maybe something there could help doing the integration to the Django Admin. Here's a screenshot of it in action.

Last edited 2 years ago by etienned (previous) (diff)

comment:27 Changed 19 months ago by guettli

  • Cc hv@… added

comment:28 Changed 15 months ago by 4glitch@…

  • Cc 4glitch@… added

Add Comment

Modify Ticket

Change Properties
<Author field>
Action
as new
The owner will be changed from nobody to anonymous. Next status will be 'assigned'
as The resolution will be set. Next status will be 'closed'
Author


E-mail address and user name can be saved in the Preferences.

 
Note: See TracTickets for help on using tickets.