Autocomplete in Django #2

[Update 14/09/11 : If you’re using Django 1.3 you can also skip point -4- below, as the ‘cut’ filter is included in Django by default now!]
[Update 15/2/10 : I added a small example that shows how to make this work with Inlines too, see point 6 below…]
[Update 18/10/09 : please note that the code has been tested on django1.1! Check the comments below if you’re running 1.0…]

In a previous post I was talking about using autocomplete fields in django’s admin, and how this feature was missing for inlines. I sorted this out and put together an essential bunch of files you can easily include in your project to that purpose. Nothing final or too wonderful but just a hack that’ll get you going…

You can download it here (in the image below you can see the autocomplete for Inline fields in action).

Picture 2

In order to use it, here’re a few simple steps:

1. Put the autocomplete_admin.py file somewhere in your application folder

2. Add the ‘autocomplete’ folder with the media files to your usual media folder

3. Add the ‘admin/autocomplete’ folder to your templates folder

4. [Only if you use a version of django less recent than 1.3] Add the extrafilters.py file in the templatetags directory of your application (or just add its contents to your custom template tags if you already have some). All is needed is the ‘cut’ filter, for making the code used in the inline-autocomplete form javascript-friendly. Basically the automatically generated code in the case of inlines wasn’t valid javascript because of the use of dashes which in js are interpreted as minus signs. There can be lots of solutions for this problem, but that’s what worked better for me (moreover the cut filter can be used elsewhere).

5. When defining your models admin, import the relevant admin and use it:

.....
from myproject.mypackage.autocomplete_admin import FkAutocompleteAdmin
 .....
 .....
class Admin (FkAutocompleteAdmin):
    related_search_fields = { 'person': ('name',)}
 .....

6. Mind that if you’re using inlines and want the autocomplete to work there too, you’ve got to make sure that you’re subclassing an AutocompleteInline class on both a) the inline admin class, and b) the main admin class of the model the inline is attached to. Example:

class Document(someUpperClass):
    """a usual model """
    authors = models.ManyToManyField(Person, through='AssocDocPerson',)

    # ********************************************
    # if you want the related inline autocomplete to work, the following admin must be one of
    # ForeignKeyAutocompleteAdmin or AutocompleteModelAdmin or NoLookupsForeignKeyAutocompleteAdmin
    # ********************************************
    class Admin (AutocompleteModelAdmin):

        inlines = (AssocPersonDocInline, )

        fieldsets = [
            ('Administration',
                {'fields':
                    ['editedrecord', 'review', 'internal_notes', ('created_at', 'created_by'),
                      ('updated_at', 'updated_by')
                     ],
                'classes': ['collapse']
                }),
        # etc. etc.

class AssocPersonDocument(someUpperClass):
    document = models.ForeignKey('Document')
    person = models.ForeignKey('Person')
    # etc. etc.

class AssocPersonDocInline(InlineAutocompleteAdmin):

    model = AssocPersonDocument
    extra = 4
    related_search_fields = {  'person': ('persondisplayname',), }

 

Share/Bookmark






35 Responses to “Autocomplete in Django #2”

What is a pencil next to glass or plus sign?
And thanx for autocomplete, which works great :)

Addas added these pithy words on Oct 14 09 at 11:10 pm

that’s just a link that takes directly to the change-form page for that item – you can get the hack at djangosinppets.com ! cheers

magicrebirth added these pithy words on Oct 15 09 at 3:44 pm

Hello. This looks great, and the code is well organized.
Unfortunately I can’t make it work, seeing in terminal
“GET /admin/dbadm/attribute/foreignkey_autocomplete/?search_fields=category_title%2Ccategory_full_title&app_label=dbadm&model_name=category&object_pk=16700 HTTP/1.1” 404 1947

Python is 2.5.4 and Django is 1.1.0

Eugene Mirotin added these pithy words on Oct 16 09 at 8:28 am

Also it says “GET /media_files/autocomplete/css/img/indicator.gif/ HTTP/1.1” 404 1834
though css clearly states ‘../img’

Eugene Mirotin added these pithy words on Oct 16 09 at 9:13 am

sorry it’s a bit hard to help you without testing the app myself. But you’re right, the get statements is wrong. Mine is like this: “GET /dj_app_media/autocomplete/img/indicator.gif HTTP/1.1” 304 0.

You should be able to access the media files directly through the browser, by entering the /media_files/ location in the url-bar : does that work? [also, you must have ‘show_indexes’: True in your URL specs].

Another place you can possibly get some info is this (that’s where I took most of Leidel’s code from):
http://code.google.com/p/django-command-extensions/issues/list

hope it helps..

magicrebirth added these pithy words on Oct 16 09 at 10:50 am

yes, I see that you have reused Leidel’s code, but your code is organized a bit different
I have not found the similar problem in the issues list…

what about media – yes, I can browse the files, they are served well, and the gif is in its place. The problem is that for some unknown reason the “../” in css is ignored…

Eugene Mirotin added these pithy words on Oct 16 09 at 7:44 pm

Okay, seems I have understood (and fixed) the img issue.
It is really-really strange, but look here:
16/Oct/2009 13:46:14] “GET /media_files/autocomplete/css/jquery.autocomplete.css/ HTTP/1.1” 200 836
[16/Oct/2009 13:46:14] “GET /media_files/autocomplete/js/jquery.bgiframe.min.js HTTP/1.1” 301 0
[16/Oct/2009 13:46:14] “GET /media_files/autocomplete/js/jquery.ajaxQueue.js HTTP/1.1” 301 0
[16/Oct/2009 13:46:14] “GET /media_files/autocomplete/js/jquery.autocomplete.js HTTP/1.1” 301 0
[16/Oct/2009 13:46:14] “GET /media_files/autocomplete/js/jquery.ajaxQueue.js/ HTTP/1.1” 304 0
[16/Oct/2009 13:46:14] “GET /media_files/autocomplete/js/jquery.bgiframe.min.js/ HTTP/1.1” 304 0
[16/Oct/2009 13:46:14] “GET /media_files/autocomplete/js/jquery.autocomplete.js/ HTTP/1.1” 304 0

Though jquery.autocomplete.css is a file, it’s served by the URL with trailing slash. And this trailing slash is “eating” the “..”. So I have added one more level-up dots pair and now the gif is displayed during the server request.

The main problem is still there

Eugene Mirotin added these pithy words on Oct 16 09 at 7:50 pm

ok, I’m stupid, I’ve copied the dev-environment media-files urlconf snippet from somewhere with the trailing slash after the path, arrrghhh

sorry for flooding in your blog ;)

Eugene Mirotin added these pithy words on Oct 16 09 at 7:59 pm

Hmm, might be interesting for you
I have commented your get_urls and uncommented __call__
This made autocompletion work

Eugene Mirotin added these pithy words on Oct 16 09 at 8:09 pm

no prob Eugene – glad you sorted things out. Regarding your last comment, I suppose you’re using Django 1.0. I forgot to specify that the code was tailored to django 1.1 ! [more info here: http://code.google.com/p/django-command-extensions/issues/detail?id=103]

magicrebirth added these pithy words on Oct 18 09 at 11:43 am

Haven’t checked the comments for some time.
Nope, I’m using Django 1.1.0 at dev server

Eugene Mirotin added these pithy words on Oct 23 09 at 3:09 pm

Hi,
Could you please post an example of your admin file?
I cant seem to get it to work with an admin inline.

Thank you

lzantal

lzantal added these pithy words on Nov 29 09 at 10:57 am

mmm maybe you can try this: if you’re using the inline-autocompletion, make sure that the main admin class the inline belong to is a subclass FkAutocompleteAdmin. I thought I wrote this somewhere in the code.. but maybe not. Let me know how it goes..

magicrebirth added these pithy words on Nov 30 09 at 10:07 pm

Good work, your articles are very interesting, i am glad that i googled your blog

resveratrol added these pithy words on Jan 29 10 at 9:49 pm

So can you post an example of using this on an inline? It works great on models but I can’t find, from your code or from your comment above, how to make this work on an inline. Thanks!

Kenneth added these pithy words on Feb 10 10 at 3:53 am

hi kenneth, I updated the post with a short example that should clarify what I meant, hope it helps :-)

magicrebirth added these pithy words on Feb 15 10 at 5:53 am

Hi. Thanks for this wonderful example. I did your tutorial and the autocomplete is working fine. But there is one problem. The id field with plus sign is not filled automatically when I select a name from left. What may be the problem? In your example, it shows William and next to that 2884. Mine is empty.

Asim added these pithy words on Apr 13 10 at 9:52 pm

I’m having trouble configuring inline autocompletion.. running Django trunk (r13004)
This is what I have in my admin.py:
http://gist.github.com/372399

For ActorAdmin, the foreign key lookup works, but for the ActorInline as part of Film, it still renders a selectbox..

Any ideas? Thx

Gijs added these pithy words on Apr 20 10 at 2:04 pm

I think you dont have raw_id_fields=…. in your actorinline

Asim added these pithy words on Apr 25 10 at 6:32 pm

Hi

The inline does not seem to be working; I end up with two very similar GET Requests being generated – one from parent and one from inline; the former works and the latter does not e.g.

GET /admin/edit/selection/foreignkey_autocomplete/?q=ag&limit=100&timestamp=1287585113125&search_fields=%5Ename&app_label=edit&model_name=selection HTTP/1.1″ 200 18221

GET /admin/edit/ipagreement/foreignkey_autocomplete/?q=ag&limit=100&timestamp=1287585191595&search_fields=%5Ename&app_label=edit&model_name=selection HTTP/1.1″ 404 1946

Derek added these pithy words on Oct 20 10 at 2:41 pm

Michele, would love to get this working but the link to download the file is dead!

http://www.box.net/shared/ugyoeqrdae

Do you think you could update it please?
Thanks!

Meirion added these pithy words on Dec 13 10 at 9:32 pm

Hey Merion – sorry about that, the server hosting service I’m using must have been down… looks like it’s ok now though.

mike added these pithy words on Dec 14 10 at 10:49 am

So it is, that was lucky. Got it working in no time.
That’s amazing, thanks Mike.

Meirion added these pithy words on Dec 14 10 at 1:55 pm

Great Article! Thank you so much for sharing this code. It works perfectly on Models and on Inlines!

Tracey added these pithy words on Dec 21 10 at 2:25 pm

Awesome, man! I will give it a try! Thanks by now.

Vinicius Massuchetto added these pithy words on May 24 11 at 1:25 pm

Thank you so much for this! I had tried two other autocomplete solutions and they were very complicated and I couldn’t get them to work. This one was so much more straight-forward and works great.

I do have one issue with it, though … It works just like it’s supposed to on the change_form page, but when I make the ForeignKey an list_editable, it doesn’t display properly on the change_list. It shows the box on the right (and you can type the id in that and it will work), but it doesn’t display the box on the left that you can type the word in, which is what I actually need.

Any idea on how I might fix that?

Karen McNeil added these pithy words on Aug 13 11 at 3:42 am

@Karen: I haven’t tried to replicate the error but it looks like a conflict between the autocomplete module and django’s list_editable widget. This autocomplete solution was developed on django 1.1 – so it may well be that on 1.3 errors like this will crop up… A workaround could be forcing the list_editable widget *not* to be the autocomplete one, as discussed here: http://stackoverflow.com/questions/7065982/list-editable-and-widgets

mike added these pithy words on Sep 14 11 at 3:08 pm

Just a quick note: with Django 1.3 the extrafilter templatetag can be removed: the “cut” filter already exists in the built-in tag library.

Thank you!

Tecnosegugio added these pithy words on Sep 08 11 at 10:27 pm

Another small fix: in autocomplete_admin.py, line 117: the ‘&’ should be changed into ‘&’ otherwise the browser doesn’t understand the URL and ignore the parameters.

Tecnosegugio added these pithy words on Sep 12 11 at 2:57 pm

Whoops…forgot to edit the rows 195 and 271 with the same change: from ‘&’ to ‘&’. Sorry.

Tecnosegugio added these pithy words on Sep 13 11 at 1:07 pm

@tecnosegugio Thanks for the tips; however I can’t understand exactly what you mean because (I guess) wordpress has transformed some your characters into html…. did you mean “& amp ;” ? (note the spaces between characters to avoid wordpress to pick it up as html)

mike added these pithy words on Sep 14 11 at 2:56 pm

How can I change width of that field? It’s too small for my needs. Thanks!

Rawr added these pithy words on Nov 24 11 at 4:17 pm

@mike: sorry for the late answer.
Yes I mean the ‘& amp;’ should be changed into ‘&’.

Now I’m looking how to solve another bug: if I put for a mistake a “non numeric” char in the ID field, the one next the ‘plus’ icon, I get a 500 error:
“Caught ValueError while rendering: invalid literal for int() with base 10: ‘alpha'”.
Looks like there is no validation for that field.

tecnosegugio added these pithy words on Feb 24 12 at 8:55 pm

I’m happily using your module for autocomplete in inlines, but for an unknown reason, I’m unable to have autocomplete fkeys in the parent modeladmin, derived from FKAutocompleteAdmin.
So I use django-extensions ForeignKeyAutocompleteAdmin to do this, that’s not DRY at all, but for now it’s the solution I have …

Dominique Guardiola added these pithy words on Apr 30 12 at 9:28 am

When i upgrade to django 1.5.2 (from 1.2.3), this widget is not working. Got the following error in UI (when debug is True):
django widgets.py ‘NoneType’ object has no attribute ‘_registry’

Django has introduced admin_site as one of the arguments for ForeignKeyRawIdWidget __init__() method.

This is the cause for the failure. To fix this, we need to do the following code change:

1. Add admin_site as one of the arugment for FkSearchInput class. Refer line 103:

def __init__(self, rel, admin_site, search_fields, attrs=None):
self.search_fields = search_fields
super(FkSearchInput, self).__init__(rel, admin_site, attrs)

2. Do the above change for NoLookupsForeignKeySearchInput (line no. 181) and InlineSearchInput class (line no. 257) also.

def __init__(self, rel, admin_site, search_fields, attrs=None):
self.search_fields = search_fields
super(NoLookupsForeignKeySearchInput, self).__init__(rel, admin_site, attrs)

def __init__(self, rel, admin_site, search_fields, attrs=None):
self.search_fields = search_fields
super(InlineSearchInput, self).__init__(rel, admin_site, attrs)

3. While calling the widget pass “self.admin_site” as one of the argument in formfield_for_dbfield method.

Changes for FkAutocompleteAdmin class as follows (line no: 439):

kwargs[‘widget’] = FkSearchInput(db_field.rel, self.admin_site, self.related_search_fields[db_field.name])

4. Do the same for NoLookupsForeignKeyAutocompleteAdmin and InlineAutocompleteAdmin class, formfield_for_dbfield method

Once the changes are done, the autocomplete widget will work.

5. In the UI, search icon will be missing because of the admin_media_prefix tag. This tag needs to be replaced with static keyword in all the three (fk, inline, nolookups) html files as follows:

Thats it.

shiv609 added these pithy words on Nov 27 13 at 2:53 pm