Login

Advanced Search in django admin

Author:
visik7
Posted:
January 14, 2011
Language:
Python
Version:
1.2
Score:
5 (after 5 ratings)

This is an example on how to create a custom advanced search (like the google advanced search page) in the admin app instead of the basic search field.

you need to override 2 template of the admin so in your templates/admin folder copy the html files from the original admin app as follow:

change_list.html:

add the name of the module of the templatetag at the top where there is the load command

from:

{% load adminmedia admin_list i18n %}

to:

{% load adminmedia admin_list custom_search_form i18n %}

and on line 87 (circa) you need to load our custom template tag something like:

{% block search %}{% advanced_search_form cl %}{% endblock %}

search_form.html:

put your form inside the

<form> tags with {{asf}} should be enough (I have also removed cl.value from the input text field because would be to complex to reload form values too )

probably would be better to create 2 new clean template and extend them but I'll leave that as an exercise for the reader :)

many thanks to Peter Baumgartner to get me in the right direction after his post

Currently ordering in the admin panel doesn't work if you find a way to get it work please write a comment

</form>
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
class FormForAdvancedSearch(forms.Form):
    #you can put any field here this is an example so only 1 simple CharField
    form_field1 = forms.CharField()

class MyModelAdmin(admin.ModelAdmin):
    # the auxiliary search form
    advanced_search_form = FormForAdvancedSearch()
    # a dictionary of key that will be removed from the GET QueryDict
    # this is necessary otherwise ChangeList will complain for malformed
    # query string 
    other_search_fields={}
    # standard search 
    search_fields = ['field1','field2']
    
    def lookup_allowed(self, lookup):
        if lookup in self.advanced_search_form.fields.keys():
            return True
        return super(MyModelAdmin, self).lookup_allowed(lookup)

    def queryset(self, request):
        qs = super(MyModelAdmin, self).queryset(request)
        # probably there is a better way to extract this value this is just 
        # an example and depends on the type of the form field 
        form_field1_value = search_fields.get("form_field1",[""])[0] 
        qs.filter(field3__icontains==form_field1_value)
        return qs
   
    def changelist_view(self, request, extra_context=None, **kwargs):
        # we need to reset on every request otherwise it will survive and we 
        # don't want that
        self.other_search_fields = {} 
        extra_context = {'asf':self.advanced_search_form}
        
        # we now need to remove the elements coming from the form
        # and save in the other_search_fields dict but it's not allowed
        # to do that in place so we need to temporary enable mutability ( I don't think     
        # it will cause any complicance but maybe someone more exeprienced on how 
        # QueryDict works could explain it better) 
        request.GET._mutable=True
        
        for key in asf.fields.keys():
            try:
                temp = request.GET.pop(key)
            except KeyError:
                pass # there is no field of the form in the dict so we don't remove it
            else:
                if temp!=['']: #there is a field but it's empty so it's useless
                    self.other_search_fields[key] = temp 
                
        request.GET_mutable=False
        return super(MyModelAdmin, self)\
               .changelist_view(request, extra_context=extra_context)


admin.site.register(MyModel, MyModelAdmin)



# you need a templatetag to rewrite the standard search_form tag because the default   
# templatetag to render the search form doesn't handle context so here it is:
# remember to put it inside a source file (in my case is custom_search_form.py) that  
# lives in project/myapp/templatetags otherwise will not be found by the template engine 

from django.contrib.admin.views.main import SEARCH_VAR

from django.template import Library

register = Library()

@register.inclusion_tag('admin/search_form.html', takes_context=True)
def advanced_search_form(context, cl):
    """
    Displays a search form for searching the list.
    """
    return {
        'asf' : context.get('asf'),
        'cl': cl,
        'show_result_count': cl.result_count != cl.full_result_count,
        'search_var': SEARCH_VAR
    }

More like this

  1. Template tag - list punctuation for a list of items by shapiromatron 10 months, 1 week ago
  2. JSONRequestMiddleware adds a .json() method to your HttpRequests by cdcarter 10 months, 2 weeks ago
  3. Serializer factory with Django Rest Framework by julio 1 year, 5 months ago
  4. Image compression before saving the new model / work with JPG, PNG by Schleidens 1 year, 6 months ago
  5. Help text hyperlinks by sa2812 1 year, 6 months ago

Comments

blueblade (on February 7, 2011):

Is there something missing in this snippet? I assume that "from hrar.forms import CandidatoSearchForm" is not needed.

#

visik7 (on February 12, 2011):

something missing? I don't think and yes that import is a copypasta error from my app

#

visik7 (on February 12, 2011):

maybe django 1.2.5 break this snippets feedback are wellcome

#

jsujar (on May 24, 2012):

is possible that this snippet doesn't work on django 1.0?, i have troubles getting data from the form.

Thanks

#

altar2 (on June 4, 2012):

looks like search parameters not showing in pagination links.

#

Please login first before commenting.