Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    primarykey
    data
    text
    <p>The solution involves adding your FilterSpec and as you said implementing your own ChangeList. As the filter name is validated, you must name your filter with a model field name. Below you will see a hack allowing to use the default filter for the same field.</p> <p>You add your FilterSpec before the standard FilterSpecs.</p> <p>Below is a working implementation running on Django 1.3</p> <pre><code>from django.contrib.admin.views.main import * from django.contrib import admin from django.db.models.fields import Field from django.contrib.admin.filterspecs import FilterSpec from django.db.models import F from models import Transport, Area from django.contrib.admin.util import get_fields_from_path from django.utils.translation import ugettext as _ # Our filter spec class InAreaFilterSpec(FilterSpec): def __init__(self, f, request, params, model, model_admin, field_path=None): super(InAreaFilterSpec, self).__init__( f, request, params, model, model_admin, field_path=field_path) self.lookup_val = request.GET.get('in_area', None) def title(self): return 'Area' def choices(self, cl): del self.field._in_area yield {'selected': self.lookup_val is None, 'query_string': cl.get_query_string({}, ['in_area']), 'display': _('All')} for pk_val, val in (('1', 'In Area'), ('0', 'Trans Area')): yield {'selected': self.lookup_val == pk_val, 'query_string': cl.get_query_string({'in_area' : pk_val}), 'display': val} def filter(self, params, qs): if 'in_area' in params: if params['in_area'] == '1': qs = qs.filter(start_area=F('finish_area')) else: qs = qs.exclude(start_area=F('finish_area')) del params['in_area'] return qs def in_area_test(field): # doing this so standard filters can be added with the same name if field.name == 'start_area' and not hasattr(field, '_in_area'): field._in_area = True return True return False # we add our special filter before standard ones FilterSpec.filter_specs.insert(0, (in_area_test, InAreaFilterSpec)) # Defining my own change list for transport class TransportChangeList(ChangeList): # Here we are doing our own initialization so the filters # are initialized when we request the data def __init__(self, request, model, list_display, list_display_links, list_filter, date_hierarchy, search_fields, list_select_related, list_per_page, list_editable, model_admin): #super(TransportChangeList, self).__init__(request, model, list_display, list_display_links, list_filter, date_hierarchy, search_fields, list_select_related, list_per_page, list_editable, model_admin) self.model = model self.opts = model._meta self.lookup_opts = self.opts self.root_query_set = model_admin.queryset(request) self.list_display = list_display self.list_display_links = list_display_links self.list_filter = list_filter self.date_hierarchy = date_hierarchy self.search_fields = search_fields self.list_select_related = list_select_related self.list_per_page = list_per_page self.model_admin = model_admin # Get search parameters from the query string. try: self.page_num = int(request.GET.get(PAGE_VAR, 0)) except ValueError: self.page_num = 0 self.show_all = ALL_VAR in request.GET self.is_popup = IS_POPUP_VAR in request.GET self.to_field = request.GET.get(TO_FIELD_VAR) self.params = dict(request.GET.items()) if PAGE_VAR in self.params: del self.params[PAGE_VAR] if TO_FIELD_VAR in self.params: del self.params[TO_FIELD_VAR] if ERROR_FLAG in self.params: del self.params[ERROR_FLAG] if self.is_popup: self.list_editable = () else: self.list_editable = list_editable self.order_field, self.order_type = self.get_ordering() self.query = request.GET.get(SEARCH_VAR, '') self.filter_specs, self.has_filters = self.get_filters(request) self.query_set = self.get_query_set() self.get_results(request) self.title = (self.is_popup and ugettext('Select %s') % force_unicode(self.opts.verbose_name) or ugettext('Select %s to change') % force_unicode(self.opts.verbose_name)) self.pk_attname = self.lookup_opts.pk.attname # To be able to do our own filter, # we need to override this def get_query_set(self): qs = self.root_query_set params = self.params.copy() # now we pass the parameters and the query set # to each filter spec that may change it # The filter MUST delete a parameter that it uses if self.has_filters: for filter_spec in self.filter_specs: if hasattr(filter_spec, 'filter'): qs = filter_spec.filter(params, qs) # Now we call the parent get_query_set() # method to apply subsequent filters sav_qs = self.root_query_set sav_params = self.params self.root_query_set = qs self.params = params qs = super(TransportChangeList, self).get_query_set() self.root_query_set = sav_qs self.params = sav_params return qs class TransportAdmin(admin.ModelAdmin): list_filter = ('start_area','start_area') def get_changelist(self, request, **kwargs): """ Overriden from ModelAdmin """ return TransportChangeList admin.site.register(Transport, TransportAdmin) admin.site.register(Area) </code></pre>
    singulars
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. VO
      singulars
      1. This table or related slice is empty.
    2. VO
      singulars
      1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload