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 }