Opened 11 years ago

Closed 4 years ago

#25 closed Bug (fixed)

Filtering interface on ForeignKey <select> boxes

Reported by: Adrian Holovaty Owned by: nobody
Component: contrib.admin Version: master
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 6 years ago.
First run at it
25_screenshot.png (25.4 KB) - added by Chuck Harmston 6 years ago.
Sample screenshot
25_patch.2.diff (8.9 KB) - added by Chuck Harmston 6 years ago.
First run at it
select_filter.diff (12.5 KB) - added by sebleier@… 6 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 6 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 6 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@…> 5 years ago.
Attempted migration to Django 1.4 (un-tested! and possibly not useful :)

Download all attachments as: .zip

Change History (42)

comment:1 Changed 11 years ago by Jacob

milestone: Version 1.1

comment:2 Changed 11 years ago by Adrian Holovaty

priority: normallow

comment:3 Changed 11 years ago by Adrian Holovaty

Type: defectenhancement

comment:4 Changed 10 years ago by (none)

Milestone Version 1.1 deleted

comment:5 Changed 10 years ago by Gary Wilson <gary.wilson@…>

Triage Stage: UnreviewedDesign decision needed

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

comment:6 Changed 9 years ago by Jacob

Triage Stage: Design decision neededAccepted

comment:7 Changed 8 years ago by mrts

milestone: post-1.0

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

comment:8 Changed 8 years ago by (none)

milestone: post-1.0

Milestone post-1.0 deleted

comment:9 Changed 6 years ago by Chuck Harmston

Owner: changed from nobody to Chuck Harmston
Status: newassigned

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

Changed 6 years ago by Chuck Harmston

Attachment: 25_patch.diff added

First run at it

Changed 6 years ago by Chuck Harmston

Attachment: 25_screenshot.png added

Sample screenshot

comment:10 Changed 6 years ago by Chuck Harmston

Has patch: set
milestone: 1.3
Version: SVN

comment:11 Changed 6 years ago by Chuck Harmston

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 Changed 6 years ago by Chuck Harmston

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

Changed 6 years ago by Chuck Harmston

Attachment: 25_patch.2.diff added

First run at it

comment:14 Changed 6 years ago by Eric Holscher

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 Changed 6 years ago by anonymous

Cc: rokclimb15@… added

comment:16 Changed 6 years ago by Eric Holscher

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 Changed 6 years ago by anonymous

Cc: eppsilon added

comment:18 Changed 6 years ago by rasca

Keywords: feature added

comment:19 Changed 6 years ago by Victor Hooi

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 Changed 6 years ago by Luke Plant

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 Changed 6 years ago by Luke Plant

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 Changed 6 years ago by Łukasz Rekucki

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 Changed 6 years ago by Victor Hooi

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 Changed 6 years ago by James Bennett

milestone: 1.3

1.3 is feature-frozen now.

comment:25 Changed 6 years ago by Victor Hooi

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

Changed 6 years ago by sebleier@…

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 Changed 6 years ago by sebleier

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.

Changed 6 years ago by sebleier

Attachment: select_filter.2.diff added

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

Changed 6 years ago by sebleier

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 Changed 6 years ago by Łukasz Rekucki

Severity: minorNormal
Type: enhancementNew feature

comment:28 Changed 5 years ago by Julien Phalip

UI/UX: set

comment:29 Changed 5 years ago by Idan Gazit

Easy pickings: set

comment:30 Changed 5 years ago by Victor Hooi

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 Changed 5 years ago by anonymous

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

comment:32 Changed 5 years ago by jimallman <jim@…>

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 Changed 5 years ago by jimallman <jim@…>

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.

Changed 5 years ago by jimallman <jim@…>

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

comment:34 Changed 4 years ago by agiliq

Easy pickings: unset

comment:35 Changed 4 years ago by Tomek Paczkowski

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