Esempio n. 1
0
def validate(cls, model):
    """
    Does basic ModelAdmin option validation. Calls custom validation
    classmethod in the end if it is provided in cls. The signature of the
    custom validation classmethod should be: def validate(cls, model).
    """
    # Before we can introspect models, they need to be fully loaded so that
    # inter-relations are set up correctly. We force that here.
    models.get_apps()

    opts = model._meta
    validate_base(cls, model)

    # list_display
    if hasattr(cls, 'list_display'):
        check_isseq(cls, 'list_display', cls.list_display)
        for idx, field in enumerate(cls.list_display):
            if not callable(field):
                if not hasattr(cls, field):
                    if not hasattr(model, field):
                        try:
                            opts.get_field(field)
                        except models.FieldDoesNotExist:
                            raise ImproperlyConfigured("%s.list_display[%d], %r is not a callable or an attribute of %r or found in the model %r."
                                % (cls.__name__, idx, field, cls.__name__, model._meta.object_name))
                    else:
                        # getattr(model, field) could be an X_RelatedObjectsDescriptor
                        f = fetch_attr(cls, model, opts, "list_display[%d]" % idx, field)
                        if isinstance(f, models.ManyToManyField):
                            raise ImproperlyConfigured("'%s.list_display[%d]', '%s' is a ManyToManyField which is not supported."
                                % (cls.__name__, idx, field))

    # list_display_links
    if hasattr(cls, 'list_display_links'):
        check_isseq(cls, 'list_display_links', cls.list_display_links)
        for idx, field in enumerate(cls.list_display_links):
            fetch_attr(cls, model, opts, 'list_display_links[%d]' % idx, field)
            if field not in cls.list_display:
                raise ImproperlyConfigured("'%s.list_display_links[%d]'"
                        "refers to '%s' which is not defined in 'list_display'."
                        % (cls.__name__, idx, field))

    # list_filter
    if hasattr(cls, 'list_filter'):
        check_isseq(cls, 'list_filter', cls.list_filter)
        for idx, fpath in enumerate(cls.list_filter):
            try:
                get_fields_from_path(model, fpath)
            except (NotRelationField, FieldDoesNotExist), e:
                raise ImproperlyConfigured(
                    "'%s.list_filter[%d]' refers to '%s' which does not refer to a Field." % (
                        cls.__name__, idx, fpath
                    )
                )
def addQbeFilterStmt(sFilter, model, JsonField):
    """ Verifica casos especiales y obtiene el QStmt
        retorna un objeto Q
    """
    fieldName = sFilter['property'].replace('.', '__')

    if fieldName.endswith('__pk') or fieldName.endswith('_id') or fieldName == 'pk':
        # Los id por ahora son numericos
        sType = 'int'

    elif fieldName == '__str__':
        # El campo especial __str__ debe ser descompuesto en los seachFields en forma explicita
        return Q()

    elif fieldName.startswith(JsonField + '__'):
        sType = 'string'

    else:
        try:
            # Obtiene el tipo de dato, si no existe la col retorna elimina la condicion
            field = get_fields_from_path(model, fieldName)[-1]
            sType = TypeEquivalence.get(field.__class__.__name__, 'string')
        except :
            return Q()

    QStmt = getQbeStmt(fieldName , sFilter['filterStmt'], sType)

    return QStmt
Esempio n. 3
0
    def __init__(self, request, model, filter_name):
        self.request = request
        self.model = model
        self.field = get_fields_from_path(model, filter_name)[-1]
        self.name = filter_name
        self.type = None

        # Determine the filter type.
        # Relations
        if (hasattr(self.field, 'rel') and bool(self.field.rel) or
            isinstance(self.field, models.related.RelatedObject)):
            self.type = 'relation'

        # Boolean fields
        if (isinstance(self.field, models.BooleanField) or
            isinstance(self.field, models.NullBooleanField)):
            self.type = 'boolean'

        # Choice fields
        if bool(self.field.choices):
            self.type = 'choice'

        # Parse value
        value = self.request.GET.get(self.name, None)
        try:
            if self.type == 'relation':
                self.value = long(value)
            elif self.type == 'boolean':
                self.value = bool(value)
            else:
                self.value = value
        except (ValueError, TypeError):
            self.value = value
Esempio n. 4
0
 def get_filters(self, request, use_distinct=False):
     filter_specs = []
     cleaned_params, use_distinct = self.get_lookup_params(use_distinct)
     if self.list_filter:
         for list_filer in self.list_filter:
             if callable(list_filer):
                 # This is simply a custom list filter class.
                 spec = list_filer(request, cleaned_params,
                     self.model, self.model_admin)
             else:
                 field_path = None
                 if isinstance(list_filer, (tuple, list)):
                     # This is a custom FieldListFilter class for a given field.
                     field, field_list_filter_class = list_filer
                 else:
                     # This is simply a field name, so use the default
                     # FieldListFilter class that has been registered for
                     # the type of the given field.
                     field, field_list_filter_class = list_filer, FieldListFilter.create
                 if not isinstance(field, models.Field):
                     field_path = field
                     field = get_fields_from_path(self.model, field_path)[-1]
                 spec = field_list_filter_class(field, request, cleaned_params,
                     self.model, self.model_admin, field_path=field_path)
             if spec and spec.has_output():
                 filter_specs.append(spec)
     return filter_specs, bool(filter_specs)
Esempio n. 5
0
    def get_filters(self, request):
        lookup_params = self.get_filters_params()
        use_distinct = False

        # Normalize the types of keys
        for key, value in lookup_params.items():
            if not isinstance(key, str):
                # 'key' will be used as a keyword argument later, so Python
                # requires it to be a string.
                del lookup_params[key]
                lookup_params[force_str(key)] = value

            if not self.model_admin.lookup_allowed(key, value):
                raise DisallowedModelAdminLookup("Filtering by %s not allowed" % key)

        filter_specs = []
        if self.list_filter:
            for list_filter in self.list_filter:
                if callable(list_filter):
                    # This is simply a custom list filter class.
                    spec = list_filter(request, lookup_params,
                        self.model, self.model_admin)
                else:
                    field_path = None
                    if isinstance(list_filter, (tuple, list)):
                        # This is a custom FieldListFilter class for a given field.
                        field, field_list_filter_class = list_filter
                    else:
                        # This is simply a field name, so use the default
                        # FieldListFilter class that has been registered for
                        # the type of the given field.
                        field, field_list_filter_class = list_filter, FieldListFilter.create
                    if not isinstance(field, BaseField):
                        field_path = field
                        field = get_fields_from_path(self.model, field_path)[-1]
                    spec = field_list_filter_class(field, request, lookup_params,
                        self.model, self.model_admin, field_path=field_path)
                    # Check if we need to use distinct()
                    use_distinct = (use_distinct or
                                    lookup_needs_distinct(self.lookup_opts,
                                                          field_path))
                if spec and spec.has_output():
                    filter_specs.append(spec)

        # At this point, all the parameters used by the various ListFilters
        # have been removed from lookup_params, which now only contains other
        # parameters passed via the query string. We now loop through the
        # remaining parameters both to ensure that all the parameters are valid
        # fields and to determine if at least one of them needs distinct(). If
        # the lookup parameters aren't real fields, then bail out.
        try:
            for key, value in lookup_params.items():
                lookup_params[key] = prepare_lookup_value(key, value)
                use_distinct = (use_distinct or
                                lookup_needs_distinct(self.lookup_opts, key))
            return filter_specs, bool(filter_specs), lookup_params, use_distinct
        except FieldDoesNotExist as e:
            six.reraise(IncorrectLookupParameters, IncorrectLookupParameters(e), sys.exc_info()[2])
Esempio n. 6
0
    def cell_filters(self):
        lookup_params = self.params.copy() # a dictionary of the query string
        cell_filter_specs = {}
        use_distinct = False

        if self.model_admin.cell_filter:
            for cell_filter in self.model_admin.cell_filter:
                path = field_path = None
                field, field_list_filter_class = cell_filter, FieldCellFilter

                if hasattr(self.model_admin, cell_filter):
                    # if it's a ModelAdmin method get the `admin_filter_field`
                    attr = getattr(self.model_admin, cell_filter)
                    field_path = getattr(attr, 'admin_filter_field', None)
                    if not field_path:
                        continue
                    path = get_fields_from_path(self.model, field_path)
                    field = path[-1]

                if not isinstance(field, models.Field):
                    try:
                        field_path = field
                        field = get_fields_from_path(self.model, field_path)[-1]

                    except FieldDoesNotExist:
                        raise Exception(
                            "Cannot use field `%s` in cell_filter. Only valid Field objects are allowed" % cell_filter)

                if isinstance(field, BooleanField):
                    field_list_filter_class = BooleanCellFilter
                elif hasattr(field, 'rel') and bool(field.rel):
                    field_list_filter_class = RelatedFieldCellFilter
                elif hasattr(field, 'choices'):
                    field_list_filter_class = ChoicesCellFilter
                spec = field_list_filter_class(field, self.request, lookup_params,
                    self.model, self.model_admin, field_path=field_path)

                # Check if we need to use distinct()
                use_distinct = (use_distinct or
                                lookup_needs_distinct(self.lookup_opts,
                                    field_path))
                if spec and spec.has_output():
                    cell_filter_specs[cell_filter] = spec

        return cell_filter_specs
Esempio n. 7
0
 def get_headers(self):
     output = [Header(self, 0, capfirst(
         get_fields_from_path(self.model, field)[-1].verbose_name))
         for field in self.selected_group_by]
     ind = len(output)
     for title in self.annotate_titles:
         output.append(Header(self, ind, title))
         ind += 1
     return output
Esempio n. 8
0
File: main.py Progetto: 9gix/RC-Tech
 def get_filters(self, request):
     filter_specs = []
     if self.list_filter:
         for filter_name in self.list_filter:
             field = get_fields_from_path(self.model, filter_name)[-1]
             spec = FilterSpec.create(field, request, self.params,
                                      self.model, self.model_admin,
                                      field_path=filter_name)
             if spec and spec.has_output():
                 filter_specs.append(spec)
     return filter_specs, bool(filter_specs)
Esempio n. 9
0
 def validate_list_filter(self, cls, model):
     """
     Validate that list_filter is a sequence of one of three options:
         1: 'field' - a basic field filter, possibly w/ relationships (eg, 'field__rel')
         2: ('field', SomeFieldListFilter) - a field-based list filter class
         3: SomeListFilter - a non-field list filter class
     """
     from django.contrib.admin import ListFilter, FieldListFilter
     if hasattr(cls, 'list_filter'):
         check_isseq(cls, 'list_filter', cls.list_filter)
         for idx, item in enumerate(cls.list_filter):
             if callable(item) and not isinstance(item, models.Field):
                 # If item is option 3, it should be a ListFilter...
                 if not issubclass(item, ListFilter):
                     raise ImproperlyConfigured("'%s.list_filter[%d]' is '%s'"
                             " which is not a descendant of ListFilter."
                             % (cls.__name__, idx, item.__name__))
                 # ...  but not a FieldListFilter.
                 if issubclass(item, FieldListFilter):
                     raise ImproperlyConfigured("'%s.list_filter[%d]' is '%s'"
                             " which is of type FieldListFilter but is not"
                             " associated with a field name."
                             % (cls.__name__, idx, item.__name__))
             else:
                 if isinstance(item, (tuple, list)):
                     # item is option #2
                     field, list_filter_class = item
                     if not issubclass(list_filter_class, FieldListFilter):
                         raise ImproperlyConfigured("'%s.list_filter[%d][1]'"
                             " is '%s' which is not of type FieldListFilter."
                             % (cls.__name__, idx, list_filter_class.__name__))
                 else:
                     # item is option #1
                     field = item
                 # Validate the field string
                 try:
                     get_fields_from_path(model, field)
                 except (NotRelationField, FieldDoesNotExist):
                     raise ImproperlyConfigured("'%s.list_filter[%d]' refers to '%s'"
                             " which does not refer to a Field."
                             % (cls.__name__, idx, field))
Esempio n. 10
0
    def get_filters(self, request):
        if self.list_filter:
            new_list = []
            for i, list_filter in enumerate(self.list_filter):
                new_list.append(list_filter)
                if isinstance(list_filter, basestring):
                    field = get_fields_from_path(self.model, list_filter)[-1]
                    if hasattr(field, 'choices'):
                        new_list[i] = list_filter

            self.list_filter = new_list
        return super(IChangeList, self).get_filters(request)
Esempio n. 11
0
    def get_result_headers(self):
        output = {}
        if self.grouper.has_output():
            for field_name in self.grouper.group_value:
                output[field_name] = capfirst(get_fields_from_path(self.model, field_name)[-1].verbose_name)

        annotate, self.annotate_titles = self.split_annotate_titles(self.annotate)
        self.annotate_fields = self.get_annotate_fields(annotate)
        func = lambda x: x[0]
        annotate_map = dict(zip(map(func, self.annotate_fields), self.annotate_titles))
        output.update(annotate_map)
        return output
Esempio n. 12
0
    def get_indexes(self):
        #from hyperadmin.resources.indexes import Index
        from hyperadmin.resources.models.filters import FieldFilter, SearchFilter

        from django.db import models
        from django.contrib.admin.util import get_fields_from_path
        try:
            from django.contrib.admin.util import lookup_needs_distinct
        except ImportError:
            from hyperadmin.resources.models.util import lookup_needs_distinct
        
        indexes = {'primary': ModelIndex('primary', self)}
        
        index = ModelIndex('filter', self)
        indexes['filter'] = index
        
        if self.list_filter:
            for list_filter in self.list_filter:
                use_distinct = False
                if callable(list_filter):
                    # This is simply a custom list filter class.
                    spec = list_filter(index=index)
                else:
                    field_path = None
                    if isinstance(list_filter, (tuple, list)):
                        # This is a custom FieldListFilter class for a given field.
                        field, field_list_filter_class = list_filter
                    else:
                        # This is simply a field name, so use the default
                        # FieldListFilter class that has been registered for
                        # the type of the given field.
                        field, field_list_filter_class = list_filter, FieldFilter.create
                    if not isinstance(field, models.Field):
                        field_path = field
                        field = get_fields_from_path(self.model, field_path)[-1]
                    spec = field_list_filter_class(field, field_path=field_path, index=index)
                    # Check if we need to use distinct()
                    use_distinct = (use_distinct or
                                    lookup_needs_distinct(self.opts,
                                                          field_path))
                if spec:
                    index.filters.append(spec)
        
        if self.search_fields:
            index.register_filter(SearchFilter, search_fields=self.search_fields)
        '''
        date_section = self.register_section('date', FilterSection)
        if self.date_hierarchy:
            pass
        '''
        return indexes
Esempio n. 13
0
    def get_filters(self):
        lookup_params = dict(self.request.GET.items())
        use_distinct = False

        filter_specs = []
        list_filters = self.list_filter
        if list_filters:
            for list_filter in list_filters:
                if callable(list_filter):
                    # This is simply a custom list filter class.
                    spec = list_filter(
                        self.request,
                        lookup_params,
                        self.model_class,
                        self,
                    )
                else:
                    field_path = None
                    if isinstance(list_filter, (tuple, list)):
                        # This is a custom FieldListFilter class for a given
                        # field.
                        field, field_list_filter_class = list_filter
                    else:
                        # This is simply a field name, so use the default
                        # FieldListFilter class that has been registered for
                        # the type of the given field.
                        field, field_list_filter_class = list_filter, FieldListFilter.create
                    if not isinstance(field, models.Field):
                        field_path = field
                        field = get_fields_from_path(self.model_class, field_path)[-1]
                    spec = field_list_filter_class(
                        field,
                        self.request,
                        lookup_params,
                        self.model_class,
                        self,
                        field_path=field_path
                    )
                    # Check if we need to use distinct()
                    use_distinct = (
                        use_distinct or
                        lookup_needs_distinct(
                            self.model_class._meta,
                            field_path
                        )
                    )
                if spec and spec.has_output():
                    filter_specs.append(spec)
        self.filter_specs = filter_specs
        return filter_specs, bool(filter_specs), use_distinct
Esempio n. 14
0
 def get_filters(self, model_admin):
     filter_specs = []
     if self.list_filter:
         #fields = []
         for field_name in self.list_filter:
             try:
                 field = get_fields_from_path(model_admin.model, field_name)[-1]
                 #~ field = self.get_field(field_name)
             except:
                 filter_specs.append(LookupFilterSpec(field_name, self.request, self.params, self.model, model_admin))
                 continue
             spec = FilterSpec.create(field, self.request, self.params, self.model, model_admin, field_name)
             if spec and spec.has_output():
                 filter_specs.append(spec)
     return filter_specs, bool(filter_specs)
Esempio n. 15
0
    def get(self, request, model=None, field_name=None):
        if model is field_name is None:
            return self.render_json_response(
                {'error': "GetFieldChoices view requires 2 arguments"},
                status=400)
        app_label, model_name = model.split('.', 1)
        try:
            model_obj = models.get_model(app_label, model_name)
            field = get_fields_from_path(model_obj, field_name)[-1]
            model_obj = field.model  # use new model if followed a ForeignKey
        except AttributeError as e:
            logger.debug("Invalid kwargs passed to view: %s", e)
            return self.render_json_response(
                {'error': "No installed app/model: %s" % model}, status=400)
        except (LookupError, FieldDoesNotExist) as e:
            logger.debug("Invalid kwargs passed to view: %s", e)
            return self.render_json_response(
                {'error': force_text(e)}, status=400)

        choices = field.choices
        # if no choices, populate with distinct values from instances
        if not choices:
            choices = []
            disabled = getattr(settings, 'ADVANCED_FILTERS_DISABLE_FOR_FIELDS',
                               tuple())
            max_choices = getattr(settings, 'ADVANCED_FILTERS_MAX_CHOICES', 254)
            if field.name in disabled:
                logger.debug('Skipped lookup of choices for disabled fields')
            elif isinstance(field, (models.BooleanField, models.DateField,
                                    models.TimeField)):
                logger.debug('No choices calculated for field %s of type %s',
                             field, type(field))
            else:
                choices = model_obj.objects.values_list(field.name, flat=True)
                if choices.count() < max_choices:
                    choices = set(choices)
                    choices = zip(choices, choices)
                    logger.debug('Choices found for field %s: %s',
                                 field.name, choices)
                else:
                    choices = []

        results = [{'id': c[0], 'text': force_text(c[1])} for c in sorted(
                   choices, key=itemgetter(0))]

        return self.render_json_response({'results': results})
Esempio n. 16
0
    def _parse_query_dict(query_data, model):
        """
        Take a list of query field dict and return data for form initialization
        """
        if query_data['field'] == '_OR':
            query_data['operator'] = 'iexact'
            return query_data

        parts = query_data['field'].split('__')
        if len(parts) < 2:
            field = parts[0]
        else:
            if parts[-1] in dict(AdvancedFilterQueryForm.OPERATORS).keys():
                field = '__'.join(parts[:-1])
            else:
                field = query_data['field']

        query_data['field'] = field
        mfield = get_fields_from_path(model, query_data['field'])
        if not mfield:
            raise Exception('Field path "%s" could not be followed to a field'
                            ' in model %s', query_data['field'], model)
        else:
            mfield = mfield[-1]  # get the field object

        if query_data['value'] is None:
            query_data['operator'] = "isnull"
        elif query_data['value'] is True:
            query_data['operator'] = "istrue"
        elif query_data['value'] is False:
            query_data['operator'] = "isfalse"
        else:
            if isinstance(mfield, DateField):
                # this is a date/datetime field
                query_data['operator'] = "range"  # default
            else:
                query_data['operator'] = "iexact"  # default

        if isinstance(query_data.get('value'),
                      list) and query_data['operator'] == 'range':
            dtfrom = dt.fromtimestamp(query_data.get('value_from', 0))
            dtto = dt.fromtimestamp(query_data.get('value_to', 0))
            query_data['value'] = ','.join([dtfrom.strftime('%Y-%m-%d'),
                                            dtto.strftime('%Y-%m-%d')])

        return query_data
Esempio n. 17
0
    def _parse_query_dict(query_data, model):
        """
        Take a list of query field dict and return data for form initialization
        """
        if query_data["field"] == "_OR":
            query_data["operator"] = "iexact"
            return query_data

        parts = query_data["field"].split("__")
        if len(parts) < 2:
            field = parts[0]
        else:
            if parts[-1] in dict(AdvancedFilterQueryForm.OPERATORS).keys():
                field = "__".join(parts[:-1])
            else:
                field = query_data["field"]

        query_data["field"] = field
        mfield = get_fields_from_path(model, query_data["field"])
        if not mfield:
            raise Exception(
                'Field path "%s" could not be followed to a field' " in model %s", query_data["field"], model
            )
        else:
            mfield = mfield[-1]  # get the field object

        if query_data["value"] is None:
            query_data["operator"] = "isnull"
        elif query_data["value"] is True:
            query_data["operator"] = "istrue"
        elif query_data["value"] is False:
            query_data["operator"] = "isfalse"
        else:
            if isinstance(mfield, DateField):
                # this is a date/datetime field
                query_data["operator"] = "range"  # default
            else:
                query_data["operator"] = "iexact"  # default

        if isinstance(query_data.get("value"), list) and query_data["operator"] == "range":
            dtfrom = dt.fromtimestamp(query_data.get("value_from", 0))
            dtto = dt.fromtimestamp(query_data.get("value_to", 0))
            query_data["value"] = ",".join([dtfrom.strftime("%Y-%m-%d"), dtto.strftime("%Y-%m-%d")])

        return query_data
Esempio n. 18
0
def getTextSearchFields( pSearchFields, model  ) :
#   TODO:  Esto deberia ser un parametro configurable en la pci 
    textSearchFlds = []
    textFilterTypes  = [ 'CharField', 'TextField', 'IntegerField', 'DecimalField', 'FloatField',  ]
    for fName  in pSearchFields:
        try: 
            # Busca el campo en el modelo y joins 
            field = get_fields_from_path( model, fName)[-1]
    
            #field = model._meta.get_field( fName )
            #model = field.rel.to
            #model.famille.field.related.parent_model
        except: continue  
    
        if field.__class__.__name__ in textFilterTypes:
            textSearchFlds.append( fName )   

    return textSearchFlds
Esempio n. 19
0
 def get_filters(self, request):
     # Esto lo modificamos para que en el filtro solo aparezcan opciones con 
     # datos (por ejemplo, en la vista dispositivos solo aparezcan en el 
     # filtro de localidad las localidades que tienen dispositivos
     filter_specs = []
     if self.list_filter:
         for filter_name in self.list_filter:
             field = get_fields_from_path(self.model, filter_name)[-1]
             spec = FilterSpec.create(field, request, self.params,
                                      self.model, self.model_admin,
                                      field_path=filter_name)
             #Salva:
             if isinstance(spec, RelatedFilterSpec) and not '__' in filter_name:
                 spec.lookup_choices = [(x._get_pk_val(),x.__unicode__()) for x in field.rel.to.objects.annotate(num_rel=Count(self.model._meta.verbose_name)).filter(num_rel__gt=0)] #IGNORE:W0212 
             #Fin Modificacion                
             if spec and spec.has_output():
                 filter_specs.append(spec)
     return filter_specs, bool(filter_specs)
Esempio n. 20
0
def get_specs(request, model, model_admin):
    filter_specs = []
    if model_admin.list_filter:
        for list_filter in model_admin.list_filter:
            if callable(list_filter):
                spec = list_filter(request, [], model, model_admin)
            else:
                field_path = None
                if isinstance(list_filter, (tuple, list)):
                    field, field_list_filter_class = list_filter
                else:
                    field, field_list_filter_class = (list_filter,
                    FieldListFilter.create)
                if not isinstance(field, models.Field):
                    field_path = field
                    field = get_fields_from_path(model, field_path)[-1]
                spec = field_list_filter_class(field,
                                               request, [], model, model_admin,
                                               field_path=field_path)
            if spec and spec.has_output():
                filter_specs.append(spec)
    return filter_specs
Esempio n. 21
0
    def get(self, request, model, field_name):
        app_label, model_name = model.split('.', 1)
        model_obj = models.get_model(app_label, model_name)
        if not model_obj:
            return self.render_json_response(
                {'error': 'No model found for %s' % model}, status=400)

        try:
            field = get_fields_from_path(model_obj, field_name)[-1]
            model_obj = field.model  # use new model if followed a ForeignKey
        except FieldDoesNotExist:
            return self.render_json_response(
                {'error': 'No such field %s found in model %s' %
                    (field_name, model)}, status=400)

        choices = field.choices
        # if no choices, populate with distinct values from instances
        if not choices:
            choices = []
            if field.name in DISABLE_FOR_FIELDS:
                logger.debug('Skipped lookup of choices for disabled fields')
            elif isinstance(field, (models.BooleanField, models.DateField,
                                    models.TimeField)):
                logger.debug('No choices calculated for field %s of type %s',
                             field, type(field))
            else:
                choices = set(model_obj.objects.values_list(
                    field.name, flat=True))
                if len(choices) < MAX_CHOICES:
                    choices = zip(choices, choices)
                    logger.debug('Choices found for field %s: %s',
                                 field.name, pformat(choices))
                else:
                    choices = []

        results = [{'id': c[0], 'text': unicode(c[1])} for c in sorted(
                   choices, key=itemgetter(0))]

        return self.render_json_response({'results': results})
Esempio n. 22
0
    def get_fields_from_model(self, model, fields):
        """
        Iterate over given <field> names (in "orm query" notation) and find
        the actual field given the initial <model>.

        If <field> is a tuple of the format ('field_name', 'Verbose name'),
        overwrite the field's verbose name with the given name for display
        purposes.
        """
        model_fields = {}
        for field in fields:
            if isinstance(field, tuple) and len(field) == 2:
                field, verbose_name = field[0], field[1]
            else:
                try:
                    model_field = get_fields_from_path(model, field)[-1]
                    verbose_name = model_field.verbose_name
                except (FieldDoesNotExist, IndexError, TypeError) as e:
                    logger.warn("AdvancedFilterForm: skip invalid field " "- %s", e)
                    continue
            model_fields[field] = verbose_name
        return model_fields
Esempio n. 23
0
    def get_filters(self, request):
        if not request.session.get('use_new_filters'):
            return super(CustomChangeList, self).get_filters(request)

        new_filter, created = CustomFilter.objects.get_or_create(
            user=request.user,
            model_name=self.model.__name__,
            app_name=self.model._meta.app_label,
            default=True)
        form = CustomFilterForm(request.GET.copy(), custom_filter=new_filter)
        if len(request.GET) and form.is_valid():
            form.save()

        self.current_filter = CustomFilter.objects.filter(
            user=request.user, path_info=request.path_info, default=True)

        # loading filter set params into change list, so they will be applied in queryset
        if self.current_filter:
            filter_params, self.exclude_params, self.bundled_params = self.current_filter[
                0].get_filter_params()
            self.params.update(**filter_params)

        lookup_params = self.params.copy()  # a dictionary of the query string
        use_distinct = False

        # Remove all the parameters that are globally and systematically
        # ignored.
        for ignored in IGNORED_PARAMS:
            if ignored in lookup_params:
                del lookup_params[ignored]

        # Normalize the types of keys
        for key, value in lookup_params.items():
            if not isinstance(key, str):
                # 'key' will be used as a keyword argument later, so Python
                # requires it to be a string.
                del lookup_params[key]
                lookup_params[smart_str(key)] = value

            if not self.model_admin.lookup_allowed(key, value):
                raise SuspiciousOperation("Filtering by %s not allowed" % key)

        filter_specs = []
        if self.list_filter:
            for list_filter in self.list_filter:
                if callable(list_filter):
                    # This is simply a custom list filter class.
                    spec = list_filter(request, lookup_params, self.model,
                                       self.model_admin)
                else:
                    field_path = None
                    if isinstance(list_filter, (tuple, list)):
                        # This is a custom FieldListFilter class for a given field.
                        field, field_list_filter_class = list_filter
                    else:
                        # This is simply a field name, so use the default
                        # FieldListFilter class that has been registered for
                        # the type of the given field.
                        field, field_list_filter_class = list_filter, FieldListFilter.create
                    if not isinstance(field, models.Field):
                        field_path = field
                        field = get_fields_from_path(self.model,
                                                     field_path)[-1]
                    spec = field_list_filter_class(field,
                                                   request,
                                                   lookup_params,
                                                   self.model,
                                                   self.model_admin,
                                                   field_path=field_path)
                    # Check if we need to use distinct()
                    use_distinct = (use_distinct or lookup_needs_distinct(
                        self.lookup_opts, field_path))
                if spec and spec.has_output():
                    filter_specs.append(spec)

        # At this point, all the parameters used by the various ListFilters
        # have been removed from lookup_params, which now only contains other
        # parameters passed via the query string. We now loop through the
        # remaining parameters both to ensure that all the parameters are valid
        # fields and to determine if at least one of them needs distinct(). If
        # the lookup parameters aren't real fields, then bail out.

        for key, value in lookup_params.items():
            lookup_params[key] = prepare_lookup_value(key, value)
            try:
                use_distinct = (use_distinct or lookup_needs_distinct(
                    self.lookup_opts, key))
            except FieldDoesNotExist, e:
                lookup_params.pop(key)
 def __init__(self, f, request, params, model, model_admin):
     field = get_fields_from_path(model, f)[-1]
     FilterSpec.__init__(self, field, request, params, model, model_admin, field_path=f)
     self.model = model
     self.lookup_val = request.GET.get(f, None)
Esempio n. 25
0
def validate(cls, model):
    """
    Does basic ModelAdmin option validation. Calls custom validation
    classmethod in the end if it is provided in cls. The signature of the
    custom validation classmethod should be: def validate(cls, model).
    """
    # Before we can introspect models, they need to be fully loaded so that
    # inter-relations are set up correctly. We force that here.
    models.get_apps()

    opts = model._meta
    validate_base(cls, model)

    # list_display
    if hasattr(cls, 'list_display'):
        check_isseq(cls, 'list_display', cls.list_display)
        for idx, field in enumerate(cls.list_display):
            if not callable(field):
                if not hasattr(cls, field):
                    if not hasattr(model, field):
                        try:
                            opts.get_field(field)
                        except models.FieldDoesNotExist:
                            raise ImproperlyConfigured("%s.list_display[%d], %r is not a callable or an attribute of %r or found in the model %r."
                                % (cls.__name__, idx, field, cls.__name__, model._meta.object_name))
                    else:
                        # getattr(model, field) could be an X_RelatedObjectsDescriptor
                        f = fetch_attr(cls, model, opts, "list_display[%d]" % idx, field)
                        if isinstance(f, models.ManyToManyField):
                            raise ImproperlyConfigured("'%s.list_display[%d]', '%s' is a ManyToManyField which is not supported."
                                % (cls.__name__, idx, field))

    # list_display_links
    if hasattr(cls, 'list_display_links'):
        check_isseq(cls, 'list_display_links', cls.list_display_links)
        for idx, field in enumerate(cls.list_display_links):
            if field not in cls.list_display:
                raise ImproperlyConfigured("'%s.list_display_links[%d]' "
                        "refers to '%s' which is not defined in 'list_display'."
                        % (cls.__name__, idx, field))

    # list_filter
    if hasattr(cls, 'list_filter'):
        check_isseq(cls, 'list_filter', cls.list_filter)
        for idx, item in enumerate(cls.list_filter):
            # There are three options for specifying a filter:
            #   1: 'field' - a basic field filter, possibly w/ relationships (eg, 'field__rel')
            #   2: ('field', SomeFieldListFilter) - a field-based list filter class
            #   3: SomeListFilter - a non-field list filter class
            if callable(item) and not isinstance(item, models.Field):
                # If item is option 3, it should be a ListFilter...
                if not issubclass(item, ListFilter):
                    raise ImproperlyConfigured("'%s.list_filter[%d]' is '%s'"
                            " which is not a descendant of ListFilter."
                            % (cls.__name__, idx, item.__name__))
                # ...  but not a FieldListFilter.
                if issubclass(item, FieldListFilter):
                    raise ImproperlyConfigured("'%s.list_filter[%d]' is '%s'"
                            " which is of type FieldListFilter but is not"
                            " associated with a field name."
                            % (cls.__name__, idx, item.__name__))
            else:
                if isinstance(item, (tuple, list)):
                    # item is option #2
                    field, list_filter_class = item
                    if not issubclass(list_filter_class, FieldListFilter):
                        raise ImproperlyConfigured("'%s.list_filter[%d][1]'"
                            " is '%s' which is not of type FieldListFilter."
                            % (cls.__name__, idx, list_filter_class.__name__))
                else:
                    # item is option #1
                    field = item
                # Validate the field string
                try:
                    get_fields_from_path(model, field)
                except (NotRelationField, FieldDoesNotExist):
                    raise ImproperlyConfigured("'%s.list_filter[%d]' refers to '%s'"
                            " which does not refer to a Field."
                            % (cls.__name__, idx, field))

    # list_per_page = 100
    if hasattr(cls, 'list_per_page') and not isinstance(cls.list_per_page, int):
        raise ImproperlyConfigured("'%s.list_per_page' should be a integer."
                % cls.__name__)

    # list_max_show_all
    if hasattr(cls, 'list_max_show_all') and not isinstance(cls.list_max_show_all, int):
        raise ImproperlyConfigured("'%s.list_max_show_all' should be an integer."
                % cls.__name__)

    # list_editable
    if hasattr(cls, 'list_editable') and cls.list_editable:
        check_isseq(cls, 'list_editable', cls.list_editable)
        for idx, field_name in enumerate(cls.list_editable):
            try:
                field = opts.get_field_by_name(field_name)[0]
            except models.FieldDoesNotExist:
                raise ImproperlyConfigured("'%s.list_editable[%d]' refers to a "
                    "field, '%s', not defined on %s.%s."
                    % (cls.__name__, idx, field_name, model._meta.app_label, model.__name__))
            if field_name not in cls.list_display:
                raise ImproperlyConfigured("'%s.list_editable[%d]' refers to "
                    "'%s' which is not defined in 'list_display'."
                    % (cls.__name__, idx, field_name))
            if field_name in cls.list_display_links:
                raise ImproperlyConfigured("'%s' cannot be in both '%s.list_editable'"
                    " and '%s.list_display_links'"
                    % (field_name, cls.__name__, cls.__name__))
            if not cls.list_display_links and cls.list_display[0] in cls.list_editable:
                raise ImproperlyConfigured("'%s.list_editable[%d]' refers to"
                    " the first field in list_display, '%s', which can't be"
                    " used unless list_display_links is set."
                    % (cls.__name__, idx, cls.list_display[0]))
            if not field.editable:
                raise ImproperlyConfigured("'%s.list_editable[%d]' refers to a "
                    "field, '%s', which isn't editable through the admin."
                    % (cls.__name__, idx, field_name))

    # search_fields = ()
    if hasattr(cls, 'search_fields'):
        check_isseq(cls, 'search_fields', cls.search_fields)

    # date_hierarchy = None
    if cls.date_hierarchy:
        f = get_field(cls, model, opts, 'date_hierarchy', cls.date_hierarchy)
        if not isinstance(f, (models.DateField, models.DateTimeField)):
            raise ImproperlyConfigured("'%s.date_hierarchy is "
                    "neither an instance of DateField nor DateTimeField."
                    % cls.__name__)

    # ordering = None
    if cls.ordering:
        check_isseq(cls, 'ordering', cls.ordering)
        for idx, field in enumerate(cls.ordering):
            if field == '?' and len(cls.ordering) != 1:
                raise ImproperlyConfigured("'%s.ordering' has the random "
                        "ordering marker '?', but contains other fields as "
                        "well. Please either remove '?' or the other fields."
                        % cls.__name__)
            if field == '?':
                continue
            if field.startswith('-'):
                field = field[1:]
            # Skip ordering in the format field1__field2 (FIXME: checking
            # this format would be nice, but it's a little fiddly).
            if '__' in field:
                continue
            get_field(cls, model, opts, 'ordering[%d]' % idx, field)

    if hasattr(cls, "readonly_fields"):
        check_readonly_fields(cls, model, opts)

    # list_select_related = False
    # save_as = False
    # save_on_top = False
    for attr in ('list_select_related', 'save_as', 'save_on_top'):
        if not isinstance(getattr(cls, attr), bool):
            raise ImproperlyConfigured("'%s.%s' should be a boolean."
                    % (cls.__name__, attr))


    # inlines = []
    if hasattr(cls, 'inlines'):
        check_isseq(cls, 'inlines', cls.inlines)
        for idx, inline in enumerate(cls.inlines):
            if not issubclass(inline, BaseModelAdmin):
                raise ImproperlyConfigured("'%s.inlines[%d]' does not inherit "
                        "from BaseModelAdmin." % (cls.__name__, idx))
            if not inline.model:
                raise ImproperlyConfigured("'model' is a required attribute "
                        "of '%s.inlines[%d]'." % (cls.__name__, idx))
            if not issubclass(inline.model, models.Model):
                raise ImproperlyConfigured("'%s.inlines[%d].model' does not "
                        "inherit from models.Model." % (cls.__name__, idx))
            validate_base(inline, inline.model)
            validate_inline(inline, cls, model)
Esempio n. 26
0
    def get_filters(self, request):
        lookup_params = self.get_filters_params()
        use_distinct = False

        # Normalize the types of keys
        for key, value in lookup_params.items():
            if not isinstance(key, str):
                # 'key' will be used as a keyword argument later, so Python
                # requires it to be a string.
                del lookup_params[key]
                lookup_params[force_str(key)] = value

            if not self.model_admin.lookup_allowed(key, value):
                raise SuspiciousOperation("Filtering by %s not allowed" % key)

        filter_specs = []
        if self.list_filter:
            for list_filter in self.list_filter:
                if callable(list_filter):
                    # This is simply a custom list filter class.
                    spec = list_filter(request, lookup_params, self.model,
                                       self.model_admin)
                else:
                    field_path = None
                    if isinstance(list_filter, (tuple, list)):
                        # This is a custom FieldListFilter class for a given field.
                        field, field_list_filter_class = list_filter
                    else:
                        # This is simply a field name, so use the default
                        # FieldListFilter class that has been registered for
                        # the type of the given field.
                        field, field_list_filter_class = list_filter, FieldListFilter.create
                    if not isinstance(field, models.Field):
                        field_path = field
                        field = get_fields_from_path(self.model,
                                                     field_path)[-1]
                    spec = field_list_filter_class(field,
                                                   request,
                                                   lookup_params,
                                                   self.model,
                                                   self.model_admin,
                                                   field_path=field_path)
                    # Check if we need to use distinct()
                    use_distinct = (use_distinct or lookup_needs_distinct(
                        self.lookup_opts, field_path))
                if spec and spec.has_output():
                    filter_specs.append(spec)

        # At this point, all the parameters used by the various ListFilters
        # have been removed from lookup_params, which now only contains other
        # parameters passed via the query string. We now loop through the
        # remaining parameters both to ensure that all the parameters are valid
        # fields and to determine if at least one of them needs distinct(). If
        # the lookup parameters aren't real fields, then bail out.
        try:
            for key, value in lookup_params.items():
                lookup_params[key] = prepare_lookup_value(key, value)
                use_distinct = (use_distinct or lookup_needs_distinct(
                    self.lookup_opts, key))
            return filter_specs, bool(
                filter_specs), lookup_params, use_distinct
        except FieldDoesNotExist as e:
            raise IncorrectLookupParameters(e)
Esempio n. 27
0
    def get_filters(self, request):
        lookup_params = self.params.copy() # a dictionary of the query string
        use_distinct = False

        # Remove all the parameters that are globally and systematically
        # ignored.
        for ignored in IGNORED_PARAMS:
            if ignored in lookup_params:
                del lookup_params[ignored]

        # Normalize the types of keys
        for key, value in lookup_params.items():
            if not isinstance(key, str):
                # 'key' will be used as a keyword argument later, so Python
                # requires it to be a string.
                del lookup_params[key]
                lookup_params[smart_str(key)] = value

            if not self.model_admin.lookup_allowed(key, value):
                raise SuspiciousOperation("Filtering by %s not allowed" % key)

        filter_specs = []
        if self.list_filter:
            for list_filter in self.list_filter:
                if callable(list_filter):
                    # This is simply a custom list filter class.
                    spec = list_filter(request, lookup_params,
                        self.model, self.model_admin)
                else:
                    field_path = None
                    if isinstance(list_filter, (tuple, list)):
                        # This is a custom FieldListFilter class for a given field.
                        field, field_list_filter_class = list_filter
                    else:
                        # This is simply a field name, so use the default
                        # FieldListFilter class that has been registered for
                        # the type of the given field.
                        field, field_list_filter_class = list_filter, FieldListFilter.create
                    if not isinstance(field, models.Field):
                        field_path = field
                        field = get_fields_from_path(self.model, field_path)[-1]
                    spec = field_list_filter_class(field, request, lookup_params,
                        self.model, self.model_admin, field_path=field_path)
                    # Check if we need to use distinct()
                    use_distinct = (use_distinct or
                                    lookup_needs_distinct(self.lookup_opts,
                                                          field_path))
                if spec and spec.has_output():
                    filter_specs.append(spec)

        # At this point, all the parameters used by the various ListFilters
        # have been removed from lookup_params, which now only contains other
        # parameters passed via the query string. We now loop through the
        # remaining parameters both to ensure that all the parameters are valid
        # fields and to determine if at least one of them needs distinct().
        for key, value in lookup_params.items():
            lookup_params[key] = prepare_lookup_value(key, value)
            use_distinct = (use_distinct or
                            lookup_needs_distinct(self.lookup_opts, key))

        return filter_specs, bool(filter_specs), lookup_params, use_distinct
Esempio n. 28
0
    def get_filters(self, request):
        if not request.session.get('use_new_filters'):
            return super(CustomChangeList, self).get_filters(request)

        new_filter, created = CustomFilter.objects.get_or_create(user=request.user, model_name=self.model.__name__, app_name=self.model._meta.app_label, default=True)
        form = CustomFilterForm(request.GET.copy(), custom_filter=new_filter)
        if len(request.GET) and form.is_valid():
            form.save()

        self.current_filter = CustomFilter.objects.filter(user=request.user, path_info=request.path_info, default=True)

        # loading filter set params into change list, so they will be applied in queryset
        if self.current_filter:
            filter_params, self.exclude_params, self.bundled_params = self.current_filter[0].get_filter_params()
            self.params.update(**filter_params)

        lookup_params = self.params.copy() # a dictionary of the query string
        use_distinct = False

        # Remove all the parameters that are globally and systematically
        # ignored.
        for ignored in IGNORED_PARAMS:
            if ignored in lookup_params:
                del lookup_params[ignored]

        # Normalize the types of keys
        for key, value in lookup_params.items():
            if not isinstance(key, str):
                # 'key' will be used as a keyword argument later, so Python
                # requires it to be a string.
                del lookup_params[key]
                lookup_params[smart_str(key)] = value

            if not self.model_admin.lookup_allowed(key, value):
                raise SuspiciousOperation("Filtering by %s not allowed" % key)

        filter_specs = []
        if self.list_filter:
            for list_filter in self.list_filter:
                if callable(list_filter):
                    # This is simply a custom list filter class.
                    spec = list_filter(request, lookup_params,
                        self.model, self.model_admin)
                else:
                    field_path = None
                    if isinstance(list_filter, (tuple, list)):
                        # This is a custom FieldListFilter class for a given field.
                        field, field_list_filter_class = list_filter
                    else:
                        # This is simply a field name, so use the default
                        # FieldListFilter class that has been registered for
                        # the type of the given field.
                        field, field_list_filter_class = list_filter, FieldListFilter.create
                    if not isinstance(field, models.Field):
                        field_path = field
                        field = get_fields_from_path(self.model, field_path)[-1]
                    spec = field_list_filter_class(field, request, lookup_params,
                        self.model, self.model_admin, field_path=field_path)
                    # Check if we need to use distinct()
                    use_distinct = (use_distinct or
                                    lookup_needs_distinct(self.lookup_opts,
                                                          field_path))
                if spec and spec.has_output():
                    filter_specs.append(spec)

        # At this point, all the parameters used by the various ListFilters
        # have been removed from lookup_params, which now only contains other
        # parameters passed via the query string. We now loop through the
        # remaining parameters both to ensure that all the parameters are valid
        # fields and to determine if at least one of them needs distinct(). If
        # the lookup parameters aren't real fields, then bail out.

        for key, value in lookup_params.items():
            lookup_params[key] = prepare_lookup_value(key, value)
            try:
                use_distinct = (use_distinct or lookup_needs_distinct(self.lookup_opts, key))
            except FieldDoesNotExist, e:
                lookup_params.pop(key)
Esempio n. 29
0
def validate(cls, model):
    """
    Does basic ModelAdmin option validation. Calls custom validation
    classmethod in the end if it is provided in cls. The signature of the
    custom validation classmethod should be: def validate(cls, model).
    """
    # Before we can introspect models, they need to be fully loaded so that
    # inter-relations are set up correctly. We force that here.
    models.get_apps()

    opts = model._meta
    validate_base(cls, model)

    # list_display
    if hasattr(cls, 'list_display'):
        check_isseq(cls, 'list_display', cls.list_display)
        for idx, field in enumerate(cls.list_display):
            if not callable(field):
                if not hasattr(cls, field):
                    if not hasattr(model, field):
                        try:
                            opts.get_field(field)
                        except models.FieldDoesNotExist:
                            raise ImproperlyConfigured("%s.list_display[%d], %r is not a callable or an attribute of %r or found in the model %r."
                                % (cls.__name__, idx, field, cls.__name__, model._meta.object_name))
                    else:
                        # getattr(model, field) could be an X_RelatedObjectsDescriptor
                        f = fetch_attr(cls, model, opts, "list_display[%d]" % idx, field)
                        if isinstance(f, models.ManyToManyField):
                            raise ImproperlyConfigured("'%s.list_display[%d]', '%s' is a ManyToManyField which is not supported."
                                % (cls.__name__, idx, field))

    # list_display_links
    if hasattr(cls, 'list_display_links'):
        check_isseq(cls, 'list_display_links', cls.list_display_links)
        for idx, field in enumerate(cls.list_display_links):
            if field not in cls.list_display:
                raise ImproperlyConfigured("'%s.list_display_links[%d]' "
                        "refers to '%s' which is not defined in 'list_display'."
                        % (cls.__name__, idx, field))

    # list_filter
    if hasattr(cls, 'list_filter'):
        check_isseq(cls, 'list_filter', cls.list_filter)
        for idx, item in enumerate(cls.list_filter):
            # There are three options for specifying a filter:
            #   1: 'field' - a basic field filter, possibly w/ relationships (eg, 'field__rel')
            #   2: ('field', SomeFieldListFilter) - a field-based list filter class
            #   3: SomeListFilter - a non-field list filter class
            if callable(item) and not isinstance(item, models.Field):
                # If item is option 3, it should be a ListFilter...
                if not issubclass(item, ListFilter):
                    raise ImproperlyConfigured("'%s.list_filter[%d]' is '%s'"
                            " which is not a descendant of ListFilter."
                            % (cls.__name__, idx, item.__name__))
                # ...  but not a FieldListFilter.
                if issubclass(item, FieldListFilter):
                    raise ImproperlyConfigured("'%s.list_filter[%d]' is '%s'"
                            " which is of type FieldListFilter but is not"
                            " associated with a field name."
                            % (cls.__name__, idx, item.__name__))
            else:
                try:
                    # Check for option #2 (tuple)
                    field, list_filter_class = item
                except (TypeError, ValueError):
                    # item is option #1
                    field = item
                else:
                    # item is option #2
                    if not issubclass(list_filter_class, FieldListFilter):
                        raise ImproperlyConfigured("'%s.list_filter[%d][1]'"
                            " is '%s' which is not of type FieldListFilter."
                            % (cls.__name__, idx, list_filter_class.__name__))
                # Validate the field string
                try:
                    get_fields_from_path(model, field)
                except (NotRelationField, FieldDoesNotExist):
                    raise ImproperlyConfigured("'%s.list_filter[%d]' refers to '%s'"
                            " which does not refer to a Field."
                            % (cls.__name__, idx, field))

    # list_per_page = 100
    if hasattr(cls, 'list_per_page') and not isinstance(cls.list_per_page, int):
        raise ImproperlyConfigured("'%s.list_per_page' should be a integer."
                % cls.__name__)

    # list_editable
    if hasattr(cls, 'list_editable') and cls.list_editable:
        check_isseq(cls, 'list_editable', cls.list_editable)
        for idx, field_name in enumerate(cls.list_editable):
            try:
                field = opts.get_field_by_name(field_name)[0]
            except models.FieldDoesNotExist:
                raise ImproperlyConfigured("'%s.list_editable[%d]' refers to a "
                    "field, '%s', not defined on %s."
                    % (cls.__name__, idx, field_name, model.__name__))
            if field_name not in cls.list_display:
                raise ImproperlyConfigured("'%s.list_editable[%d]' refers to "
                    "'%s' which is not defined in 'list_display'."
                    % (cls.__name__, idx, field_name))
            if field_name in cls.list_display_links:
                raise ImproperlyConfigured("'%s' cannot be in both '%s.list_editable'"
                    " and '%s.list_display_links'"
                    % (field_name, cls.__name__, cls.__name__))
            if not cls.list_display_links and cls.list_display[0] in cls.list_editable:
                raise ImproperlyConfigured("'%s.list_editable[%d]' refers to"
                    " the first field in list_display, '%s', which can't be"
                    " used unless list_display_links is set."
                    % (cls.__name__, idx, cls.list_display[0]))
            if not field.editable:
                raise ImproperlyConfigured("'%s.list_editable[%d]' refers to a "
                    "field, '%s', which isn't editable through the admin."
                    % (cls.__name__, idx, field_name))

    # search_fields = ()
    if hasattr(cls, 'search_fields'):
        check_isseq(cls, 'search_fields', cls.search_fields)

    # date_hierarchy = None
    if cls.date_hierarchy:
        f = get_field(cls, model, opts, 'date_hierarchy', cls.date_hierarchy)
        if not isinstance(f, (models.DateField, models.DateTimeField)):
            raise ImproperlyConfigured("'%s.date_hierarchy is "
                    "neither an instance of DateField nor DateTimeField."
                    % cls.__name__)

    # ordering = None
    if cls.ordering:
        check_isseq(cls, 'ordering', cls.ordering)
        for idx, field in enumerate(cls.ordering):
            if field == '?' and len(cls.ordering) != 1:
                raise ImproperlyConfigured("'%s.ordering' has the random "
                        "ordering marker '?', but contains other fields as "
                        "well. Please either remove '?' or the other fields."
                        % cls.__name__)
            if field == '?':
                continue
            if field.startswith('-'):
                field = field[1:]
            # Skip ordering in the format field1__field2 (FIXME: checking
            # this format would be nice, but it's a little fiddly).
            if '__' in field:
                continue
            get_field(cls, model, opts, 'ordering[%d]' % idx, field)

    if hasattr(cls, "readonly_fields"):
        check_readonly_fields(cls, model, opts)

    # list_select_related = False
    # save_as = False
    # save_on_top = False
    for attr in ('list_select_related', 'save_as', 'save_on_top'):
        if not isinstance(getattr(cls, attr), bool):
            raise ImproperlyConfigured("'%s.%s' should be a boolean."
                    % (cls.__name__, attr))


    # inlines = []
    if hasattr(cls, 'inlines'):
        check_isseq(cls, 'inlines', cls.inlines)
        for idx, inline in enumerate(cls.inlines):
            if not issubclass(inline, BaseModelAdmin):
                raise ImproperlyConfigured("'%s.inlines[%d]' does not inherit "
                        "from BaseModelAdmin." % (cls.__name__, idx))
            if not inline.model:
                raise ImproperlyConfigured("'model' is a required attribute "
                        "of '%s.inlines[%d]'." % (cls.__name__, idx))
            if not issubclass(inline.model, models.Model):
                raise ImproperlyConfigured("'%s.inlines[%d].model' does not "
                        "inherit from models.Model." % (cls.__name__, idx))
            validate_base(inline, inline.model)
            validate_inline(inline, cls, model)