Opened 19 years ago

Closed 12 years ago

#25 closed Bug (fixed)

Filtering interface on ForeignKey <select> boxes

Reported by: Adrian Holovaty Owned by: nobody
Component: contrib.admin Version: dev
Severity: Normal Keywords: feature
Cc: rokclimb15@…, eppsilon, Victor Hooi Triage Stage: Accepted
Has patch: yes Needs documentation: no
Needs tests: no Patch needs improvement: yes
Easy pickings: no UI/UX: yes

Description

Select boxes are a pain, and slow, to deal with when there are a lot of values to select from. (Example: datelines on news stories). There should be a generator option, use_filter_interface, available on select boxes. It would add an <input type="text"> next to the select box and allow users to filter the select box that way.

This would make data entry quicker, because folks could just paste in the dateline they want, and it'd be selected for them (assuming it's been entered as a dateline in the system).

Attachments (7)

25_patch.diff (8.5 KB ) - added by Chuck Harmston 14 years ago.
First run at it
25_screenshot.png (25.4 KB ) - added by Chuck Harmston 14 years ago.
Sample screenshot
25_patch.2.diff (8.9 KB ) - added by Chuck Harmston 14 years ago.
First run at it
select_filter.diff (12.5 KB ) - added by sebleier@… 14 years ago.
I modified the previous patch and made it more efficient. Still needs to be tested in browsers other than FF and Chrome.
select_filter.2.diff (12.1 KB ) - added by sebleier 14 years ago.
fixed a bug. Development can be found at https://github.com/sebleier/django/tree/feature/select-filter
select_filter.3.diff (12.1 KB ) - added by sebleier 14 years ago.
fixed a bug. Development can be found at https://github.com/sebleier/django/tree/feature/select-filter
select_filter_for_Django_1_4.diff (8.4 KB ) - added by jimallman <jim@…> 13 years ago.
Attempted migration to Django 1.4 (un-tested! and possibly not useful :)

Download all attachments as: .zip

Change History (42)

comment:1 by Jacob, 19 years ago

milestone: Version 1.1

comment:2 by Adrian Holovaty, 19 years ago

priority: normallow

comment:3 by Adrian Holovaty, 19 years ago

Type: defectenhancement

comment:4 by (none), 18 years ago

Milestone Version 1.1 deleted

comment:5 by Gary Wilson <gary.wilson@…>, 18 years ago

Triage Stage: UnreviewedDesign decision needed

Or even a javascript textbox+dropdown that filters entries as you type.

comment:6 by Jacob, 17 years ago

Triage Stage: Design decision neededAccepted

comment:7 by mrts, 17 years ago

milestone: post-1.0

Marking as post-1.0 as this is not essential for 1.0.

comment:8 by (none), 16 years ago

milestone: post-1.0

Milestone post-1.0 deleted

comment:9 by Chuck Harmston, 14 years ago

Owner: changed from nobody to Chuck Harmston
Status: newassigned

I'm going to give this a go at the DjangoCon sprint.

by Chuck Harmston, 14 years ago

Attachment: 25_patch.diff added

First run at it

by Chuck Harmston, 14 years ago

Attachment: 25_screenshot.png added

Sample screenshot

comment:10 by Chuck Harmston, 14 years ago

Has patch: set
milestone: 1.3
Version: SVN

comment:11 by Chuck Harmston, 14 years ago

I've got something workable. Screenshot and sample patch attached (I'll be submitting through a GitHub pull request). Some notes:

  • It's very slow in large (5000+) sets. Once my changes are applied, I will file another ticket in which I make some performance improvements. I will be porting those performance enhancements (which will change the behavior) to filter_horizontal and filter_vertical as well, for consistency.
  • I used jQuery for the new widget, per Jannis in #django-dev.
  • Tested in IE + Mac browsers.
  • Test and docs included.

If I get a thumbs-up, I'll submit a pull request on GitHub.

comment:12 by Chuck Harmston, 14 years ago

Summary: Allow use_filter_interface on non-multiple select boxesFiltering interface on ForeignKey <select> boxes

by Chuck Harmston, 14 years ago

Attachment: 25_patch.2.diff added

First run at it

comment:14 by Eric Holscher, 14 years ago

This looks like great work. I haven't taken a look at the code yet, but I will check it out during the sprints tomorrow. I'd like to see this get into core soon, as it looks damn useful.

comment:15 by anonymous, 14 years ago

Cc: rokclimb15@… added

comment:16 by Eric Holscher, 14 years ago

Sorry I didn't comment earlier. I looked at this during the sprints, and the code looks good. However, I'm not too comfortable with my javascript abilities, so I didn't want to mark it RFC without knowing it would work across browsers & such.

comment:17 by anonymous, 14 years ago

Cc: eppsilon added

comment:18 by rasca, 14 years ago

Keywords: feature added

comment:19 by Victor Hooi, 14 years ago

Cc: Victor Hooi added

heya,

Just thought I'd chime in that this is awesome =). Can't wait for this to hit trunk - hopefully it'll be soon...haha...any word on that?

Cheers,
Victor

comment:20 by Luke Plant, 14 years ago

Patch needs improvement: set

Victor:

It won't hit in it's current state. The patch needs a fair amount of cleaning up:

  • it doesn't apply to trunk (tests have recently been migrated to unittests)
  • it hard codes a path to '/media'
  • documentation needs to be wrapped to 80 chars

Plus we definitely need some more info about compatibility with different browsers - what versions of Firefox, Internet Explorer, Safari, Chrome and Opera does it work on? From the look of the patch, and having implemented similar things before, the use of jQuery should prevent a lot of problems, but it is very easy for this kind of thing to break in some browsers, or be unusable slow etc.

cpharmston: I'm not sure what kind of thumbs up you are looking for. Since the ticket already exists, it will be easiest just to keep an updated ticket here. Once it is ready, any committer will then be able to commit.

comment:21 by Luke Plant, 14 years ago

Another thing - I personally would drop the 'Available' header - that makes sense for the m2m selects where you have 'Available' and 'Selected', but here it just seems to add vertical space.

comment:22 by Łukasz Rekucki, 14 years ago

This is painfully slow for me right now. I tested this on Chrome 9.x with 2000 objects named "user". After typing in "user" in the filter it took about 3-5 seconds to refresh (on a quite fast machine). Most of the time is spent on re-creating the <option> elements one-by-one. Creating all the HTML in one shot could improve this. Not creating elements again would be probably even better (i.e. keep the option elements in the cache).

comment:23 by Victor Hooi, 14 years ago

heya,

Hmm, that's strange - the Github repository seems to 404 for me. And the cpharmston's user page doesn't exist?

https://github.com/cpharmston/

According to http://status.github.com/, Github is up and fine.

cpharmston - did you change your Github username or something?

Also, I'm curious how people think this compares to the from django-extensions:

http://code.google.com/p/django-command-extensions/

Screenshot:

http://www.flickr.com/photos/msgre/3524424961/

To be honest, I like the solution from cpharmston better, with the select box and search filter. Seems much more usable/intuitive, and also fits better with the rest of the Django admin.

Cheers,
Victor

comment:24 by James Bennett, 14 years ago

milestone: 1.3

1.3 is feature-frozen now.

comment:25 by Victor Hooi, 14 years ago

heya,

Is there any word on this patch, or anybody willing to adopt it?

From a usability POV, I think a patch like this is incredibly useful in the Django admin, particularly when the number of FK's grow large (which they invariably do).

Just like the filter_horizontal select widget, it definitely adds a lot of polish.

Anyhow, I just tried cpharmstron's patch against trunk, when I attempt to use it on an Add form I get:

'str' object has no attribute 'copy'

The full stacktrace:

Environment:


Request Method: GET
Request URL: http://nextgen.victorhooi.com/admin/conferences/attendance/add/

Django Version: 1.3 beta 1 SVN-15400
Python Version: 2.6.6
Installed Applications:
['django.contrib.auth',
 'django.contrib.contenttypes',
 'django.contrib.sessions',
 'django.contrib.sites',
 'django.contrib.messages',
 'django.contrib.staticfiles',
 'django.contrib.admin',
 'allocations',
 'conferences',
 'facilities',
 'nextgensite',
 'people',
 'django_extensions',
 'reversion',
 'south',
 'debug_toolbar']
Installed Middleware:
('django.middleware.common.CommonMiddleware',
 'django.contrib.sessions.middleware.SessionMiddleware',
 'django.middleware.csrf.CsrfViewMiddleware',
 'django.contrib.auth.middleware.AuthenticationMiddleware',
 'django.contrib.messages.middleware.MessageMiddleware',
 'debug_toolbar.middleware.DebugToolbarMiddleware')


Traceback:
File "/sites/.virtualenvs/colloquium/src/django/django/core/handlers/base.py" in get_response
  111.                         response = callback(request, *callback_args, **callback_kwargs)
File "/sites/.virtualenvs/colloquium/src/django/django/contrib/admin/options.py" in wrapper
  312.                 return self.admin_site.admin_view(view)(*args, **kwargs)
File "/sites/.virtualenvs/colloquium/src/django/django/utils/decorators.py" in _wrapped_view
  93.                     response = view_func(request, *args, **kwargs)
File "/sites/.virtualenvs/colloquium/src/django/django/views/decorators/cache.py" in _wrapped_view_func
  79.         response = view_func(request, *args, **kwargs)
File "/sites/.virtualenvs/colloquium/src/django/django/contrib/admin/sites.py" in inner
  190.             return view(request, *args, **kwargs)
File "/sites/.virtualenvs/colloquium/src/django/django/utils/decorators.py" in _wrapper
  28.             return bound_func(*args, **kwargs)
File "/sites/.virtualenvs/colloquium/src/django/django/utils/decorators.py" in _wrapped_view
  93.                     response = view_func(request, *args, **kwargs)
File "/sites/.virtualenvs/colloquium/src/django/django/utils/decorators.py" in bound_func
  24.                 return func(self, *args2, **kwargs2)
File "/sites/.virtualenvs/colloquium/src/django/django/db/transaction.py" in inner
  282.                 res = func(*args, **kwargs)
File "/sites/.virtualenvs/colloquium/src/django/django/contrib/admin/options.py" in add_view
  852.         ModelForm = self.get_form(request)
File "/sites/.virtualenvs/colloquium/src/django/django/contrib/admin/options.py" in get_form
  437.         return modelform_factory(self.model, **defaults)
File "/sites/.virtualenvs/colloquium/src/django/django/forms/models.py" in modelform_factory
  400.     return ModelFormMetaclass(class_name, (form,), form_class_attrs)
File "/sites/.virtualenvs/colloquium/src/django/django/forms/models.py" in __new__
  206.                                       opts.exclude, opts.widgets, formfield_callback)
File "/sites/.virtualenvs/colloquium/src/django/django/forms/models.py" in fields_for_model
  164.             formfield = formfield_callback(f, **kwargs)
File "/sites/.virtualenvs/colloquium/src/django/django/utils/functional.py" in _curried
  55.         return _curried_func(*(args+moreargs), **dict(kwargs, **morekwargs))
File "/sites/.virtualenvs/colloquium/src/django/django/contrib/admin/options.py" in formfield_for_dbfield
  106.                 formfield = self.formfield_for_foreignkey(db_field, request, **kwargs)
File "/sites/.virtualenvs/colloquium/src/django/django/contrib/admin/options.py" in formfield_for_foreignkey
  167.                 db_field.verbose_name, (db_field.name in self.filter_vertical))
File "/sites/.virtualenvs/colloquium/src/django/django/forms/widgets.py" in __init__
  505.         super(Select, self).__init__(attrs)
File "/sites/.virtualenvs/colloquium/src/django/django/forms/widgets.py" in __init__
  147.             self.attrs = attrs.copy()

Exception Type: AttributeError at /admin/conferences/attendance/add/
Exception Value: 'str' object has no attribute 'copy'

Any ideas?

Cheers,
Victor

by sebleier@…, 14 years ago

Attachment: select_filter.diff added

I modified the previous patch and made it more efficient. Still needs to be tested in browsers other than FF and Chrome.

comment:26 by sebleier, 14 years ago

Owner: changed from Chuck Harmston to sebleier
Status: assignednew

I added tests and documentation to the patch. One thing to note is that the previous patch required a fk_filter attribute on the ModelAdmin class to specify which foreignkey fields are rendered using the new filter interface. In this patch, you simply specify which foreignkey field needs the filtering interface in the ModelAdmin filter_vertical list.

by sebleier, 14 years ago

Attachment: select_filter.2.diff added

fixed a bug. Development can be found at https://github.com/sebleier/django/tree/feature/select-filter

by sebleier, 14 years ago

Attachment: select_filter.3.diff added

fixed a bug. Development can be found at https://github.com/sebleier/django/tree/feature/select-filter

comment:27 by Łukasz Rekucki, 14 years ago

Severity: minorNormal
Type: enhancementNew feature

comment:28 by Julien Phalip, 14 years ago

UI/UX: set

comment:29 by Idan Gazit, 13 years ago

Easy pickings: set

comment:30 by Victor Hooi, 13 years ago

heya,

Any update on how close this is to hitting trunk?

I mean, it's flagged "Easy pickings" by Idan *grins*, so surely it's close, right? Are there any showstopppers?

Cheers,
Victor

Btw, I also saw this:

http://harvesthq.github.com/chosen/

Chosen's a JQuery (or Prototype) plugin that basically similar combo-box support, but without the scrollable list underneath.

comment:31 by anonymous, 13 years ago

Owner: changed from sebleier to anonymous
Status: newassigned
Type: New featureBug

comment:32 by jimallman <jim@…>, 13 years ago

Owner: changed from anonymous to jimallman
Status: assignednew

I'm currently trying to adapt sebleier's work for Django 1.4.

Not sure who set the owner to anonymous, but I'm claiming this. (Apologies if this is bad form.)

comment:33 by jimallman <jim@…>, 13 years ago

Owner: changed from jimallman to nobody

I'd like to surrender this ticket. As a relative newcomer to Django, I can't figure out whether this solution (sebleier's patch) belongs in Django 1.4, which already has raw-ID fields and select-filter widgets for this kind of user experience.

by jimallman <jim@…>, 13 years ago

Attempted migration to Django 1.4 (un-tested! and possibly not useful :)

comment:34 by agiliq, 12 years ago

Easy pickings: unset

comment:35 by Tomek Paczkowski, 12 years ago

Resolution: fixed
Status: newclosed

I think raw_id_fields is answer for this ticket and thus it should be closed as already solved.

Note: See TracTickets for help on using tickets.
Back to Top