예제 #1
0
파일: checks.py 프로젝트: Brian-Rono/django
    def _check_list_filter_item(self, obj, model, item, label):
        """
        Check one item of `list_filter`, i.e. check if it is one of three options:
        1. 'field' -- a basic field filter, possibly w/ relationships (e.g.
           '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 callable(item) and not isinstance(item, models.Field):
            # If item is option 3, it should be a ListFilter...
            if not issubclass(item, ListFilter):
                return must_inherit_from(parent='ListFilter', option=label,
                                         obj=obj, id='admin.E113')
            # ...  but not a FieldListFilter.
            elif issubclass(item, FieldListFilter):
                return [
                    checks.Error(
                        "The value of '%s' must not inherit from 'FieldListFilter'." % label,
                        hint=None,
                        obj=obj.__class__,
                        id='admin.E114',
                    )
                ]
            else:
                return []
        elif isinstance(item, (tuple, list)):
            # item is option #2
            field, list_filter_class = item
            if not issubclass(list_filter_class, FieldListFilter):
                return must_inherit_from(parent='FieldListFilter', option='%s[1]' % label,
                                         obj=obj, id='admin.E115')
            else:
                return []
        else:
            # item is option #1
            field = item

            # Validate the field string
            try:
                get_fields_from_path(model, field)
            except (NotRelationField, FieldDoesNotExist):
                return [
                    checks.Error(
                        "The value of '%s' refers to '%s', which does not refer to a Field." % (label, field),
                        hint=None,
                        obj=obj.__class__,
                        id='admin.E116',
                    )
                ]
            else:
                return []
예제 #2
0
파일: checks.py 프로젝트: rhyep/django_site
    def _check_list_filter_item(self, obj, model, item, label):
        """
        Check one item of `list_filter`, i.e. check if it is one of three options:
        1. 'field' -- a basic field filter, possibly w/ relationships (e.g.
           '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 callable(item) and not isinstance(item, models.Field):
            # If item is option 3, it should be a ListFilter...
            if not issubclass(item, ListFilter):
                return must_inherit_from(parent='ListFilter', option=label,
                                         obj=obj, id='admin.E113')
            # ...  but not a FieldListFilter.
            elif issubclass(item, FieldListFilter):
                return [
                    checks.Error(
                        "The value of '%s' must not inherit from 'FieldListFilter'." % label,
                        obj=obj.__class__,
                        id='admin.E114',
                    )
                ]
            else:
                return []
        elif isinstance(item, (tuple, list)):
            # item is option #2
            field, list_filter_class = item
            if not issubclass(list_filter_class, FieldListFilter):
                return must_inherit_from(parent='FieldListFilter', option='%s[1]' % label, obj=obj, id='admin.E115')
            else:
                return []
        else:
            # item is option #1
            field = item

            # Validate the field string
            try:
                get_fields_from_path(model, field)
            except (NotRelationField, FieldDoesNotExist):
                return [
                    checks.Error(
                        "The value of '%s' refers to '%s', which does not refer to a Field." % (label, field),
                        obj=obj.__class__,
                        id='admin.E116',
                    )
                ]
            else:
                return []
        def __init__(self, request, model, field_path, *args, **kwargs):
            self.field_path = field_path
            value = kwargs.get('data').get(self.field_path)
            fields = get_fields_from_path(model, self.field_path)
            is_relation = fields[0].is_relation
            url = 'filter_model_autocomplete' if is_relation else 'filter_list_autocomplete'

            super(AutocompleteForm, self).__init__(*args, **kwargs)
            url = reverse(
                url,
                kwargs={
                    'app': model._meta.app_label,
                    'model': model._meta.model_name,
                    'field_path': self.field_path
                }
            )
            if request.GET:
                url = '%s?%s' % (url, request.GET.urlencode())

            if is_relation:
                related_model = get_model_from_relation(fields[-1])
                qs = related_model._default_manager.all()
                if value:
                    qs = qs.filter(pk=value)
                self.fields[self.field_path] = forms.ModelChoiceField(
                    queryset=qs, required=False, widget=ModelSelect2(url=url)
                )
            else:
                choices = [(value, value)] if value else []
                self.fields[self.field_path] = forms.ChoiceField(
                    choices=choices, required=False, widget=ListSelect2(url=url),
                )
예제 #4
0
    def _check_date_hierarchy(self, obj):
        """ Check that date_hierarchy refers to DateField or DateTimeField. """

        if obj.date_hierarchy is None:
            return []
        else:
            try:
                field = get_fields_from_path(obj.model, obj.date_hierarchy)[-1]
            except (NotRelationField, FieldDoesNotExist):
                return [
                    checks.Error(
                        "The value of 'date_hierarchy' refers to '%s', which "
                        "does not refer to a Field." % obj.date_hierarchy,
                        obj=obj.__class__,
                        id='admin.E127',
                    )
                ]
            else:
                if not isinstance(field,
                                  (models.DateField, models.DateTimeField)):
                    return must_be('a DateField or DateTimeField',
                                   option='date_hierarchy',
                                   obj=obj,
                                   id='admin.E128')
                else:
                    return []
 def get_widget_instance(self):
     rel = get_fields_from_path(self.model,
                                self.field_name)[-1].remote_field
     return AutocompleteSelect(
         rel,
         self.model_admin.admin_site,
     )
예제 #6
0
 def get_filter_for_field(self, f, request):
     field = get_fields_from_path(self.model, f)[-1]
     if hasattr(field, 'rel') and hasattr(field.rel, 'to') or hasattr(field, 'remote_field') and hasattr(field.remote_field, 'model'):
         present_list_filter_fields = getattr(self, 'present_list_filter_fields', [])
         if f in present_list_filter_fields:
             return RelatedFieldPresentListFilter
         return RelatedFieldVisibleListFilter
예제 #7
0
    def get(self, request, model=None, field_name=None):
        search = request.GET.get('search', '')
        page = request.GET.get('page', 1)
        has_next = False
        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 = apps.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
        choices = sorted(choices)
        # if no choices, populate with distinct values from instances
        if not choices:
            choices = []
            disabled = getattr(settings, 'ADVANCED_FILTERS_DISABLE_FOR_FIELDS',
                               tuple())
            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:
                # the order_by() avoids ambiguity with values() and distinct()
                filter_kwargs = {
                    "{}__icontains".format(field.name): search,
                    "{}__isnull".format(field.name): False
                }
                queryset = model_obj.objects.filter(**filter_kwargs).order_by(
                    field.name).values_list(field.name, flat=True).distinct()
                page_size = getattr(settings, 'ADVANCED_FILTERS_PAGE_SIZE', 20)
                paginator = Paginator(queryset, page_size)
                try:
                    page = paginator.page(page)
                    choices = zip(page, page)
                    has_next = page.has_next()
                except EmptyPage:
                    choices = []
                    has_next = False

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

        return self.render_json_response({
            'results': results,
            "more": has_next
        })
    def get_rendered_widget(self):
        rel = get_fields_from_path(self.model,
                                   self.field_name)[-1].remote_field
        widget = AutocompleteSelect(
            rel,
            self.model_admin.admin_site,
        )
        FieldClass = self.get_form_field()
        field = FieldClass(
            queryset=self.get_queryset_for_field(),
            widget=widget,
            required=False,
        )

        self._add_media(self.model_admin, widget)

        attrs = self.widget_attrs.copy()
        attrs["id"] = "id-%s-autocomplete-filter" % self.field_name
        attrs["class"] = f'{attrs.get("class", "")} select-filter'.strip()

        return field.widget.render(
            name=self.parameter_name,
            value=self.used_parameters.get(self.parameter_name, ""),
            attrs=attrs,
        )
예제 #9
0
def translate_relation(model, relation):
    """Transforms Django-style related field lookup (foo__bar)
    into attrgetter instance that can be called with an object
    to retrieve the object at the end of defined relation chain.

    :param relation: Django-style field lookup
    """
    fields = get_fields_from_path(model, relation)
    last_field = fields[-1]
    if not issubclass(last_field.related_model, Site):
        raise ImproperlyConfigured(
            'Relation "{}" does not point to Site model (it targets {} instead).'
            .format(
                relation,
                "{}.{}".format(
                    last_field.related_model._meta.app_label,
                    last_field.related_model.__name__,
                ),
            ))

    def get_next_field(obj, field):
        return getattr(obj, field.name)

    def inner(obj):
        obj = reduce(get_next_field, fields, obj)
        if last_field.many_to_many:
            return obj.all()
        return [obj]

    return inner
예제 #10
0
    def get_filters(self):
        self.filter_specs = {}
        for list_filter, *settings in self._filters:
            try:
                settings = dict(settings)
            except ValueError:
                settings = {}

            field_path = None
            field, field_list_filter_class = list_filter, FieldListFilter.create
            if not isinstance(field, models.Field):
                # For annotated data you have to specify the type
                if 'field_type' in settings:
                    # No path for annotated fields
                    field_path = list_filter
                    field = settings['field_type']()
                else:
                    field_path = field
                    field = get_fields_from_path(self.model, field_path)[-1]

            spec = field_list_filter_class(
                field,
                self.model,
                field_path=field_path,
                **settings,
            )
            if spec and spec.has_output():
                self.filter_specs[list_filter] = spec

        return self.filter_specs.values()
예제 #11
0
        def __init__(self, *args, **kwargs):
            model = kwargs.pop('model')
            request = kwargs.pop('request')
            self.field_path = kwargs.pop('field_path')
            value = kwargs.get('data').get(self.field_path)
            fields = get_fields_from_path(model, self.field_path)
            url = 'filter_model_autocomplete' if fields[0].is_relation else 'filter_list_autocomplete'
            is_relation = url == 'filter_model_autocomplete'

            if value:
                choices = [(value, value)]
            else:
                choices = []

            super(AutocompleteForm, self).__init__(*args, **kwargs)
            url = reverse(
                url,
                kwargs={
                    'app': model._meta.app_label,
                    'model': model._meta.model_name,
                    'field_path': self.field_path
                }
            )
            if request.GET:
                url = '%s?%s' % (url, request.GET.urlencode())

            if is_relation:
                self.fields[self.field_path] = forms.ModelChoiceField(
                    queryset=model._default_manager.none(), required=False, widget=ModelSelect2(url=url)
                )
            else:
                self.fields[self.field_path] = forms.ChoiceField(
                    choices=choices, required=False, widget=ListSelect2(url=url),
                )
예제 #12
0
    def __init__(self, field, request, params, hidden_params, model,
                 model_admin, field_path):
        super(ForeignKeyFilter,
              self).__init__(field, request, params, hidden_params, model,
                             model_admin, field_path)

        if self.filter_queryset is None:
            # check if there is some lookup field in field_path
            # and get proper QuerySet
            target_model = model
            fields = get_fields_from_path(self.model, field_path)
            if len(fields) > 1:
                target_model = get_model_from_relation(fields[-2])

            self.filter_queryset = getattr(target_model,
                                           self.field.name).get_queryset()

        field = forms.ModelChoiceField(
            queryset=self.filter_queryset,
            required=False,
            empty_label='',
            widget=autocomplete.ModelSelect2Multiple(
                url=self.autocomplete_url, ))

        self._add_media(model_admin)

        attrs = self.widget_attrs.copy()
        attrs['id'] = 'id-%s-dal-filter' % self.field_path
        attrs['data-placeholder'] = self.title

        rendered_widget = field.widget.render(name=self._parameters[0],
                                              value=self._values[0],
                                              attrs=attrs)

        self.context.update({'rendered_widget': rendered_widget})
예제 #13
0
 def get(self, request, app, model, field_path, *args, **kwargs):
     self.model = self.get_model(app, model)
     self.fields = get_fields_from_path(self.model, field_path)
     self.related_model = get_model_from_relation(self.fields[-1])
     self.field_path = field_path
     self.query_string = get_query_string(request.GET, remove=[field_path, 'q'])
     return super(FilterModelAutocomplete, self).get(request, *args, **kwargs)
예제 #14
0
    def get_filters(self, request):
        lookup_params = self.get_filters_params()
        use_distinct = False

        for key, value in lookup_params.items():
            if not self.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 = list_filter
                        field_list_filter_class = 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.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.opts, key))
            return (filter_specs, bool(filter_specs), lookup_params,
                    use_distinct)
        except FieldDoesNotExist as e:
            raise IncorrectLookupParameters from e
예제 #15
0
파일: main.py 프로젝트: brabadu/django
    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, 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:
            six.reraise(IncorrectLookupParameters, IncorrectLookupParameters(e), sys.exc_info()[2])
예제 #16
0
    def get_related_field_ajax_list_filter_params(self):
        model = RelatedToTestModel
        field_path = 'field'
        field = get_fields_from_path(model, field_path)[-1]
        lookup_params = {}
        model_admin = admin.site._registry.get(model)

        return field, lookup_params, model, model_admin, field_path
예제 #17
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))
예제 #18
0
 def get(self, request, app, model, field_path, *args, **kwargs):
     self.model = self.get_model(app, model)
     self.fields = get_fields_from_path(self.model, field_path)
     self.related_model = get_model_from_relation(self.fields[-1])
     self.field_path = field_path
     self.query_string = get_query_string(request.GET,
                                          remove=[field_path, 'q'])
     return super(FilterModelAutocomplete,
                  self).get(request, *args, **kwargs)
예제 #19
0
파일: helpers.py 프로젝트: yxl201908/ralph
def get_field_by_relation_path(model, field_path):
    """
    Returns field for `model` referenced by `field_path`.

    E.g. calling:
        get_field_by_relation_path(BackOfficeAsset, 'model__manufacturer__name')
    returns:
        <django.db.models.fields.CharField: name>
    """
    return get_fields_from_path(model, field_path)[-1]
예제 #20
0
    def get_related_field_ajax_list_filter_params(self):
        class ModelAdmin(admin.ModelAdmin):
            pass

        model = RelatedToTestModel
        field_path = 'field'
        field = get_fields_from_path(model, field_path)[-1]
        lookup_params = {}
        model_admin = ModelAdmin

        return field, lookup_params, model, model_admin, field_path
예제 #21
0
    def get_related_field_ajax_list_filter_params(self):
        class ModelAdmin(admin.ModelAdmin):
            pass

        model = RelatedToTestModel
        field_path = 'field'
        field = get_fields_from_path(model, field_path)[-1]
        lookup_params = {}
        model_admin = ModelAdmin

        return field, lookup_params, model, model_admin, field_path
예제 #22
0
 def get(self, request, model=None, field_name=None):
     if model is field_name is None:
         return self.render_json_response(
             {'error': "GetOperatorChoices view requires 2 arguments"},
             status=400)
     app_label, model_name = model.split('.', 1)
     try:
         model_obj = apps.get_model(app_label, model_name)
         field = get_fields_from_path(model_obj, field_name)[-1]
         model_obj = field.model
         internal_type = field.get_internal_type()
         disabled = getattr(settings, 'ADVANCED_FILTERS_DISABLE_FOR_FIELDS',
                            tuple())
         if field.name in disabled:
             logger.debug('Skipped lookup of operators for disabled fields')
             choices = []
         else:
             af_options = dict(AdvancedFilterQueryForm.OPERATORS)
             choices = []
             field_options = []
             if (internal_type == 'CharField'
                     or internal_type == 'EmailField'
                     or internal_type == 'URLField'):
                 field_options = ["iexact", "icontains", "iregex", "isnull"]
             elif internal_type == 'BooleanField':
                 field_options = ["istrue", "isfalse", "isnull"]
             elif (internal_type == 'PositiveIntegerField'
                   or internal_type == 'SmallIntegerField'
                   or internal_type == 'PositiveSmallIntegerField'
                   or internal_type == 'BigIntegerField'
                   or internal_type == 'IntegerField'
                   or internal_type == 'FloatField'
                   or internal_type == 'DecimalField'):
                 field_options = ["lt", "gt", "lte", "gte", "isnull"]
             elif (internal_type == 'DateTimeField'
                   or internal_type == 'DateField'):
                 field_options = [
                     "range", "lt", "gt", "lte", "gte", "isnull"
                 ]
             else:
                 field_options = af_options
             choices = [{
                 'key': option,
                 'value': af_options[option]
             } for option in field_options]
         return self.render_json_response({'results': choices})
     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)
예제 #23
0
파일: main.py 프로젝트: saruddle/GANPFSite
    def get_filters(self, request):
        lookup_params = self.get_filters_params()
        use_distinct = False

        for key, value in lookup_params.items():
            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, models.Field):
                        field_path = field
                        field = get_fields_from_path(self.model, field_path)[-1]

                    lookup_params_count = len(lookup_params)
                    spec = field_list_filter_class(
                        field, request, lookup_params,
                        self.model, self.model_admin, field_path=field_path
                    )
                    # field_list_filter_class removes any lookup_params it
                    # processes. If that happened, check if distinct() is
                    # needed to remove duplicate results.
                    if lookup_params_count > len(lookup_params):
                        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) from e
예제 #24
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))
예제 #25
0
파일: views.py 프로젝트: fredericowu/nodeps
    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 = apps.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_str(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:
                # the order_by() avoids ambiguity with values() and distinct()
                choices = model_obj.objects.order_by(field.name).values_list(
                    field.name, flat=True).distinct()
                # additional query is ok to avoid fetching too many values
                if choices.count() <= max_choices:
                    choices = zip(choices, choices)
                    logger.debug('Choices found for field %s: %s', field.name,
                                 choices)
                else:
                    choices = []

        results = [{
            'id': c[0],
            'text': force_str(c[1])
        } for c in sorted(choices, key=lambda x: (x[0] is not None, x[0]))]

        return self.render_json_response({'results': results})
예제 #26
0
    def get_filters(self):
        params = dict(self.request.GET.items())
        opts = self.model._meta
        use_distinct = False
        list_filters = self.get_list_filters()
        new_params = {}
        has_filters = False

        # Normalize the types of keys
        list_names = [f if isinstance(f, str) else f.parameter_name for f in list_filters]
        for key, value in params.items():
            # ignore keys not in list_filters
            if key.startswith(tuple(list_names)):
                new_params[force_str(key)] = value

        has_filters = bool(new_params)
        filter_specs = []
        for list_filter in list_filters:
            if callable(list_filter):
                # This is simply a custom list filter class.
                spec = list_filter(self.request, new_params, self.model, None)
            else:
                field_path = None
                if isinstance(list_filter, (tuple, list)):
                    # Custom FieldListFilter class for a given field.
                    field, field_list_filter_class = list_filter
                else:
                    # Field name, so use the default registered FieldListFilter
                    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]
                model_admin = admin.ModelAdmin(self.model, admin.site)
                spec = field_list_filter_class(field, self.request, new_params, self.model, model_admin, field_path=field_path)
                # Check if we need to use distinct()
                use_distinct = (use_distinct or lookup_needs_distinct(opts, field_path))
            if spec and spec.has_output():
                filter_specs.append(spec)

        # All the parameters used by the various ListFilters have been removed
        # lookup_params, 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 new_params.items():
                new_params[key] = prepare_lookup_value(key, value)
                use_distinct = (use_distinct or lookup_needs_distinct(opts, key))
            return filter_specs, has_filters, use_distinct
        except FieldDoesNotExist as e:
            raise IncorrectLookupParameters from e
예제 #27
0
파일: helpers.py 프로젝트: yxl201908/ralph
def get_field_title_by_relation_path(model, field_path):
    """
    Return field verbose name

    If field path is nested (using __), returned name is one before last field
    verbose name.
    """
    fields = get_fields_from_path(model, field_path)
    if len(fields) > 1:
        field = fields[-2]
    else:
        field = fields[-1]
    return field.verbose_name
예제 #28
0
    def _parse_query_dict(query_data, model):
        """
        Take a list of query field dict and return data for form initialization
        """
        operator = 'iexact'
        if query_data['field'] == '_OR':
            query_data['operator'] = operator
            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])
                operator = 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'] = operator  # 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
예제 #29
0
    def get_list_display_columns(cls) -> List[str]:
        """Returns the column names for this model for use in the table"""

        display_columns = []

        for fname in cls.list_display:
            try:
                field = get_fields_from_path(cls, fname)[-1]
                display_columns.append(field.verbose_name)
            except FieldDoesNotExist:
                # Field is property/method
                display_columns.append(fname.replace("_", " "))

        return display_columns
예제 #30
0
def get_model_field(model, field_name):
    """
    Returns the `Field` instance belonging to `field_name` on a `Model`
    instance or class. This works for related fields.

    Example::

        >>> get_model_field(Zaak, 'zaaktype__zaaktypeomschrijving')
        <django.db.models.fields.CharField: zaaktypeomschrijving>

    """
    from zaakmagazijn.rgbz_mapping.base import ModelProxy
    if issubclass(model, ModelProxy):
        return model.get_field(field_name)
    return get_fields_from_path(model, field_name)[-1]
예제 #31
0
def get_model_field(model, field_name):
    """
    Returns the `Field` instance belonging to `field_name` on a `Model`
    instance or class. This works for related fields.

    Example::

        >>> get_model_field(Zaak, 'zaaktype__zaaktypeomschrijving')
        <django.db.models.fields.CharField: zaaktypeomschrijving>

    """
    from zaakmagazijn.rgbz_mapping.base import ModelProxy
    if issubclass(model, ModelProxy):
        return model.get_field(field_name)
    return get_fields_from_path(model, field_name)[-1]
예제 #32
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 = apps.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:
                # the order_by() avoids ambiguity with values() and distinct()
                choices = model_obj.objects.order_by(field.name).values_list(
                    field.name, flat=True).distinct()
                # additional query is ok to avoid fetching too many values
                if choices.count() <= max_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})
예제 #33
0
파일: forms.py 프로젝트: UTMediaCAT/Voyage
    def _parse_query_dict(query_data, model):
        """
        Take a list of query field dict and return data for form initialization
        """
        operator = 'iexact'
        if query_data['field'] == '_OR':
            query_data['operator'] = operator
            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])
                operator = 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'] = operator  # 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
예제 #34
0
    def get_filter_classes(self):
        lookup_params = self.get_data()

        # 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["{}".format(key)] = value

        request = FakeRequest(self.request, GET=self.get_data())

        filter_specs = []
        list_filters = self.get_list_filters()
        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, 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):
                        from django.contrib.admin.utils import get_fields_from_path
                        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, field_path=field_path)

                if spec and spec.has_output():
                    filter_specs.append(spec)

        return filter_specs
예제 #35
0
    def get_field_values(self, field_names: List[str]) -> List[Tuple[str, Any]]:
        """Returns a tuple of field names and values for the given fields"""

        field_values = []

        for fname in field_names:
            try:
                field_values.append(
                    (
                        get_fields_from_path(self._meta.model, fname)[-1].verbose_name,
                        get_field_value(self, fname),
                    )
                )
            except FieldDoesNotExist:
                value = getattr(self, fname)

                if callable(value):
                    value = value()
                field_values.append((fname, value))

        return field_values
예제 #36
0
    def _check_date_hierarchy(self, obj):
        """ Check that date_hierarchy refers to DateField or DateTimeField. """

        if obj.date_hierarchy is None:
            return []
        else:
            try:
                field = get_fields_from_path(obj.model, obj.date_hierarchy)[-1]
            except (NotRelationField, FieldDoesNotExist):
                return [
                    checks.Error(
                        "The value of 'date_hierarchy' refers to '%s', which "
                        "does not refer to a Field." % obj.date_hierarchy,
                        obj=obj.__class__,
                        id='admin.E127',
                    )
                ]
            else:
                if not isinstance(field, (models.DateField, models.DateTimeField)):
                    return must_be('a DateField or DateTimeField', option='date_hierarchy', obj=obj, id='admin.E128')
                else:
                    return []
예제 #37
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
예제 #38
0
# -*- coding: utf-8 -*-
예제 #39
0
    def get_filters(self, request):
        lookup_params = self.get_filters_params()
        use_distinct = False

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

        filter_specs = []
        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]

                lookup_params_count = len(lookup_params)
                spec = field_list_filter_class(
                    field,
                    request,
                    lookup_params,
                    self.model,
                    self.model_admin,
                    field_path=field_path,
                )
                # field_list_filter_class removes any lookup_params it
                # processes. If that happened, check if distinct() is needed to
                # remove duplicate results.
                if lookup_params_count > len(lookup_params):
                    use_distinct = use_distinct or lookup_needs_distinct(
                        self.lookup_opts, field_path)
            if spec and spec.has_output():
                filter_specs.append(spec)

        if self.date_hierarchy:
            # Create bounded lookup parameters so that the query is more
            # efficient.
            year = lookup_params.pop('%s__year' % self.date_hierarchy, None)
            if year is not None:
                month = lookup_params.pop('%s__month' % self.date_hierarchy,
                                          None)
                day = lookup_params.pop('%s__day' % self.date_hierarchy, None)
                try:
                    from_date = datetime(
                        int(year),
                        int(month if month is not None else 1),
                        int(day if day is not None else 1),
                    )
                except ValueError as e:
                    raise IncorrectLookupParameters(e) from e
                if settings.USE_TZ:
                    from_date = make_aware(from_date)
                if day:
                    to_date = from_date + timedelta(days=1)
                elif month:
                    # In this branch, from_date will always be the first of a
                    # month, so advancing 32 days gives the next month.
                    to_date = (from_date + timedelta(days=32)).replace(day=1)
                else:
                    to_date = from_date.replace(year=from_date.year + 1)
                lookup_params.update({
                    '%s__gte' % self.date_hierarchy: from_date,
                    '%s__lt' % self.date_hierarchy: to_date,
                })

        # 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) from e
예제 #40
0
파일: main.py 프로젝트: ArcTanSusan/django
    def get_filters(self, request):
        lookup_params = self.get_filters_params()
        use_distinct = False

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

        filter_specs = []
        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]

                lookup_params_count = len(lookup_params)
                spec = field_list_filter_class(
                    field, request, lookup_params,
                    self.model, self.model_admin, field_path=field_path,
                )
                # field_list_filter_class removes any lookup_params it
                # processes. If that happened, check if distinct() is needed to
                # remove duplicate results.
                if lookup_params_count > len(lookup_params):
                    use_distinct = use_distinct or lookup_needs_distinct(self.lookup_opts, field_path)
            if spec and spec.has_output():
                filter_specs.append(spec)

        if self.date_hierarchy:
            # Create bounded lookup parameters so that the query is more
            # efficient.
            year = lookup_params.pop('%s__year' % self.date_hierarchy, None)
            if year is not None:
                month = lookup_params.pop('%s__month' % self.date_hierarchy, None)
                day = lookup_params.pop('%s__day' % self.date_hierarchy, None)
                try:
                    from_date = datetime(
                        int(year),
                        int(month if month is not None else 1),
                        int(day if day is not None else 1),
                    )
                except ValueError as e:
                    raise IncorrectLookupParameters(e) from e
                if settings.USE_TZ:
                    from_date = make_aware(from_date)
                if day:
                    to_date = from_date + timedelta(days=1)
                elif month:
                    # In this branch, from_date will always be the first of a
                    # month, so advancing 32 days gives the next month.
                    to_date = (from_date + timedelta(days=32)).replace(day=1)
                else:
                    to_date = from_date.replace(year=from_date.year + 1)
                lookup_params.update({
                    '%s__gte' % self.date_hierarchy: from_date,
                    '%s__lt' % self.date_hierarchy: to_date,
                })

        # 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) from e
예제 #41
0
def date_hierarchy(cl):
    """
    Displays the date hierarchy for date drill-down functionality.
    """
    if cl.date_hierarchy:
        field_name = cl.date_hierarchy
        field = get_fields_from_path(cl.model, field_name)[-1]
        dates_or_datetimes = 'datetimes' if isinstance(field, models.DateTimeField) else 'dates'
        year_field = '%s__year' % field_name
        month_field = '%s__month' % field_name
        day_field = '%s__day' % field_name
        field_generic = '%s__' % field_name
        year_lookup = cl.params.get(year_field)
        month_lookup = cl.params.get(month_field)
        day_lookup = cl.params.get(day_field)

        link = lambda filters: cl.get_query_string(filters, [field_generic])

        if not (year_lookup or month_lookup or day_lookup):
            # select appropriate start level
            date_range = cl.queryset.aggregate(first=models.Min(field_name),
                                               last=models.Max(field_name))
            if date_range['first'] and date_range['last']:
                if date_range['first'].year == date_range['last'].year:
                    year_lookup = date_range['first'].year
                    if date_range['first'].month == date_range['last'].month:
                        month_lookup = date_range['first'].month
        if year_lookup and month_lookup and day_lookup:
            day = datetime.date(int(year_lookup), int(month_lookup), int(day_lookup))
            return {
                'field_name': field.verbose_name,
                'show': True,
                'back': {
                    'link': link({year_field: year_lookup, month_field: month_lookup}),
                    'title': capfirst(formats.date_format(day, 'YEAR_MONTH_FORMAT'))
                },
                'choices': [{'title': capfirst(formats.date_format(day, 'MONTH_DAY_FORMAT'))}]
            }
        elif year_lookup and month_lookup:
            days = cl.queryset.filter(**{year_field: year_lookup, month_field: month_lookup})
            days = getattr(days, dates_or_datetimes)(field_name, 'day')
            return {
                'show': True,
                'field_name': field.verbose_name,
                'current_filter': capfirst(MONTHS.get(int(month_lookup), 'UNKNOWN')),
                'back': {
                    'link': link({year_field: year_lookup}),
                    'title': str(year_lookup)
                },
                'choices': [{
                    'link': link({year_field: year_lookup, month_field: month_lookup, day_field: day.day}),
                    'title': capfirst(formats.date_format(day, 'MONTH_DAY_FORMAT'))
                } for day in days]
            }
        elif year_lookup:
            months = cl.queryset.filter(**{year_field: year_lookup})
            months = getattr(months, dates_or_datetimes)(field_name, 'month')
            return {
                'show': True,
                'field_name': field.verbose_name,
                'current_filter': year_lookup,
                'back': {
                    'link': link({}),
                    'title': _('All dates')
                },
                'choices': [{
                    'link': link({year_field: year_lookup, month_field: month.month}),
                    'title': capfirst(formats.date_format(month, 'YEAR_MONTH_FORMAT'))
                } for month in months]
            }
        else:
            years = getattr(cl.queryset, dates_or_datetimes)(field_name, 'year')
            return {
                'show': True,
                'current_filter': _('All'),
                'field_name': field.verbose_name,
                'choices': [{
                    'link': link({year_field: str(year.year)}),
                    'title': str(year.year),
                } for year in years]
            }
def date_hierarchy(cl):
    """Displays the date hierarchy for date drill-down functionality.

    This tag overrides Django Admin date_hierarchy template tag at
    django/contrib/admin/templatetags/admin_list.py -> date_hierarchy

    The tag prevents additional queries used for generating the date hierarchy.
    The default tag performs a query on the filtered queryset to find the dates
    for which there is data for the level in the hierarchy. On large tables
    this query can be very expensive.

    The additional query is prevented by setting date_hierarchy_drilldown = False
    on the model admin. When drilldown is disabled the tag will generate a default
    range of dates based only on the selected hierarchy level without performing a
    query.

    Hierarchy levels:
        Month - all days of the month.
        Year - All months of year.
        None - +-3 years from current year.

    When date_hierarchy_drilldown = True or when not set the default behaviour
    is preserved.

    Usage:
        class MyModelAdmin(admin.ModelAdmin):
            date_hierarchy = 'created'
            date_hierarchy_drilldown = False
    """
    if cl.date_hierarchy:
        field_name = cl.date_hierarchy
        field = get_fields_from_path(cl.model, field_name)[-1]
        dates_or_datetimes = 'datetimes' if isinstance(field, models.DateTimeField) else 'dates'
        year_field = '%s__year' % field_name
        month_field = '%s__month' % field_name
        day_field = '%s__day' % field_name
        field_generic = '%s__' % field_name
        year_lookup = cl.params.get(year_field)
        month_lookup = cl.params.get(month_field)
        day_lookup = cl.params.get(day_field)

        def link(filters):
            return cl.get_query_string(filters, [field_generic])

        date_hierarchy_drilldown = getattr(cl.model_admin, 'date_hierarchy_drilldown', True)
        date_hierarchy_drilldown_fn = getattr(
            cl.model_admin,
            'get_date_hierarchy_drilldown',
            default_date_hierarchy_drilldown,
        )

        if not (year_lookup or month_lookup or day_lookup):

            # Select appropriate start level.
            if date_hierarchy_drilldown:
                date_range = cl.queryset.aggregate(first=models.Min(field_name), last=models.Max(field_name))
                if date_range['first'] and date_range['last']:
                    if date_range['first'].year == date_range['last'].year:
                        year_lookup = date_range['first'].year
                        if date_range['first'].month == date_range['last'].month:
                            month_lookup = date_range['first'].month

        if year_lookup and month_lookup and day_lookup:
            day = datetime.date(int(year_lookup), int(month_lookup), int(day_lookup))
            return {
                'show': True,
                'back': {
                    'link': link({year_field: year_lookup, month_field: month_lookup}),
                    'title': capfirst(formats.date_format(day, 'YEAR_MONTH_FORMAT'))
                },
                'choices': [{'title': capfirst(formats.date_format(day, 'MONTH_DAY_FORMAT'))}]
            }

        elif year_lookup and month_lookup:

            if date_hierarchy_drilldown:
                days = cl.queryset.filter(**{year_field: year_lookup, month_field: month_lookup})
                days = getattr(days, dates_or_datetimes)(field_name, 'day')

            else:
                days = date_hierarchy_drilldown_fn(int(year_lookup), int(month_lookup))

            return {
                'show': True,
                'back': {
                    'link': link({year_field: year_lookup}),
                    'title': str(year_lookup)
                },
                'choices': [{
                    'link': link({year_field: year_lookup, month_field: month_lookup, day_field: day.day}),
                    'title': capfirst(formats.date_format(day, 'MONTH_DAY_FORMAT'))
                } for day in days]
            }

        elif year_lookup:

            if date_hierarchy_drilldown:
                months = cl.queryset.filter(**{year_field: year_lookup})
                months = getattr(months, dates_or_datetimes)(field_name, 'month')

            else:
                months = date_hierarchy_drilldown_fn(int(year_lookup), None)

            return {
                'show': True,
                'back': {
                    'link': link({}),
                    'title': _('All dates')
                },
                'choices': [{
                    'link': link({year_field: year_lookup, month_field: month.month}),
                    'title': capfirst(formats.date_format(month, 'YEAR_MONTH_FORMAT'))
                } for month in months]
            }

        else:

            if date_hierarchy_drilldown:
                years = getattr(cl.queryset, dates_or_datetimes)(field_name, 'year')

            else:
                years = date_hierarchy_drilldown_fn(None, None)

            return {
                'show': True,
                'choices': [{
                    'link': link({year_field: str(year.year)}),
                    'title': str(year.year),
                } for year in years]
            }
예제 #43
0
파일: filters.py 프로젝트: xypisces/python
    def get_list_queryset(self, queryset):
        lookup_params = dict([(smart_str(k)[len(FILTER_PREFIX):], v) for k, v in self.admin_view.params.items()
                              if smart_str(k).startswith(FILTER_PREFIX) and v != ''])
        for p_key, p_val in lookup_params.iteritems():
            if p_val == "False":
                lookup_params[p_key] = False
        use_distinct = False

        # for clean filters
        self.admin_view.has_query_param = bool(lookup_params)
        self.admin_view.clean_query_url = self.admin_view.get_query_string(remove=
                                                                           [k for k in self.request.GET.keys() if k.startswith(FILTER_PREFIX)])

        # Normalize the types of keys
        if not self.free_query_filter:
            for key, value in lookup_params.items():
                if not self.lookup_allowed(key, value):
                    raise SuspiciousOperation(
                        "Filtering by %s not allowed" % key)

        self.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(self.request, lookup_params,
                                       self.model, self)
                else:
                    field_path = None
                    field_parts = []
                    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, filter_manager.create
                    if not isinstance(field, models.Field):
                        field_path = field
                        field_parts = get_fields_from_path(
                            self.model, field_path)
                        field = field_parts[-1]
                    spec = field_list_filter_class(
                        field, self.request, lookup_params,
                        self.model, self.admin_view, field_path=field_path)

                    if len(field_parts)>1:
                        # Add related model name to title
                        spec.title = "%s %s"%(field_parts[-2].name,spec.title)

                    # Check if we need to use distinct()
                    use_distinct = (use_distinct or
                                    lookup_needs_distinct(self.opts, field_path))
                if spec and spec.has_output():
                    try:
                        new_qs = spec.do_filte(queryset)
                    except ValidationError, e:
                        new_qs = None
                        self.admin_view.message_user(_("<b>Filtering error:</b> %s") % e.messages[0], 'error')
                    if new_qs is not None:
                        queryset = new_qs

                    self.filter_specs.append(spec)
예제 #44
0
def date_hierarchy(cl):
    """
    Displays the date hierarchy for date drill-down functionality.
    """
    if cl.date_hierarchy:
        field_name = cl.date_hierarchy
        field = get_fields_from_path(cl.model, field_name)[-1]
        dates_or_datetimes = 'datetimes' if isinstance(
            field, models.DateTimeField) else 'dates'
        year_field = '%s__year' % field_name
        month_field = '%s__month' % field_name
        day_field = '%s__day' % field_name
        field_generic = '%s__' % field_name
        year_lookup = cl.params.get(year_field)
        month_lookup = cl.params.get(month_field)
        day_lookup = cl.params.get(day_field)

        def link(filters):
            return cl.get_query_string(filters, [field_generic])

        if not (year_lookup or month_lookup or day_lookup):
            # select appropriate start level
            date_range = cl.queryset.aggregate(first=models.Min(field_name),
                                               last=models.Max(field_name))
            if date_range['first'] and date_range['last']:
                if date_range['first'].year == date_range['last'].year:
                    year_lookup = date_range['first'].year
                    if date_range['first'].month == date_range['last'].month:
                        month_lookup = date_range['first'].month

        if year_lookup and month_lookup and day_lookup:
            day = datetime.date(int(year_lookup), int(month_lookup),
                                int(day_lookup))
            return {
                'show':
                True,
                'back': {
                    'link':
                    link({
                        year_field: year_lookup,
                        month_field: month_lookup
                    }),
                    'title':
                    capfirst(formats.date_format(day, 'YEAR_MONTH_FORMAT'))
                },
                'choices': [{
                    'title':
                    capfirst(formats.date_format(day, 'MONTH_DAY_FORMAT'))
                }]
            }
        elif year_lookup and month_lookup:
            days = cl.queryset.filter(**{
                year_field: year_lookup,
                month_field: month_lookup
            })
            days = getattr(days, dates_or_datetimes)(field_name, 'day')
            return {
                'show':
                True,
                'back': {
                    'link': link({year_field: year_lookup}),
                    'title': str(year_lookup)
                },
                'choices': [{
                    'link':
                    link({
                        year_field: year_lookup,
                        month_field: month_lookup,
                        day_field: day.day
                    }),
                    'title':
                    capfirst(formats.date_format(day, 'MONTH_DAY_FORMAT'))
                } for day in days]
            }
        elif year_lookup:
            months = cl.queryset.filter(**{year_field: year_lookup})
            months = getattr(months, dates_or_datetimes)(field_name, 'month')
            return {
                'show':
                True,
                'back': {
                    'link': link({}),
                    'title': _('All dates')
                },
                'choices': [{
                    'link':
                    link({
                        year_field: year_lookup,
                        month_field: month.month
                    }),
                    'title':
                    capfirst(formats.date_format(month, 'YEAR_MONTH_FORMAT'))
                } for month in months]
            }
        else:
            years = getattr(cl.queryset, dates_or_datetimes)(field_name,
                                                             'year')
            return {
                'show':
                True,
                'choices': [{
                    'link': link({year_field: str(year.year)}),
                    'title': str(year.year),
                } for year in years]
            }
예제 #45
0
    def get_list_queryset(self, queryset):
        lookup_params = dict([
            (smart_str(k)[len(FILTER_PREFIX):], v)
            for k, v in self.admin_view.params.items()
            if smart_str(k).startswith(FILTER_PREFIX) and v != ''
        ])
        for p_key, p_val in iteritems(lookup_params):
            if p_val == "False":
                lookup_params[p_key] = False
        use_distinct = False

        # for clean filters
        self.admin_view.has_query_param = bool(lookup_params)
        self.admin_view.clean_query_url = self.admin_view.get_query_string(
            remove=[
                k for k in self.request.GET.keys()
                if k.startswith(FILTER_PREFIX)
            ])

        # Normalize the types of keys
        if not self.free_query_filter:
            for key, value in lookup_params.items():
                if not self.lookup_allowed(key, value):
                    raise SuspiciousOperation("Filtering by %s not allowed" %
                                              key)

        self.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(self.request, lookup_params, self.model,
                                       self)
                else:
                    field_path = None
                    field_parts = []
                    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, filter_manager.create
                    if not isinstance(field, models.Field):
                        field_path = field
                        field_parts = get_fields_from_path(
                            self.model, field_path)
                        field = field_parts[-1]
                    spec = field_list_filter_class(field,
                                                   self.request,
                                                   lookup_params,
                                                   self.model,
                                                   self.admin_view,
                                                   field_path=field_path)

                    if len(field_parts) > 1:
                        # Add related model name to title
                        spec.title = "%s %s" % (field_parts[-2].name,
                                                spec.title)

                    # Check if we need to use distinct()
                    use_distinct = (use_distinct or lookup_needs_distinct(
                        self.opts, field_path))
                if spec and spec.has_output():
                    try:
                        new_qs = spec.do_filte(queryset)
                    except ValidationError as e:
                        new_qs = None
                        self.admin_view.message_user(
                            _("<b>Filtering error:</b> %s") % e.messages[0],
                            'error')
                    if new_qs is not None:
                        queryset = new_qs

                    self.filter_specs.append(spec)

        self.has_filters = bool(self.filter_specs)
        self.admin_view.filter_specs = self.filter_specs
        obj = filter(lambda f: f.is_used, self.filter_specs)
        if six.PY3:
            obj = list(obj)
        self.admin_view.used_filter_num = len(obj)

        try:
            for key, value in lookup_params.items():
                use_distinct = (use_distinct
                                or lookup_needs_distinct(self.opts, key))
        except FieldDoesNotExist as e:
            raise IncorrectLookupParameters(e)

        try:
            # fix a bug by david: In demo, quick filter by IDC Name() cannot be used.
            if isinstance(queryset, models.query.QuerySet) and lookup_params:
                new_lookup_parames = dict()
                for k, v in lookup_params.iteritems():
                    list_v = v.split(',')
                    if len(list_v) > 0:
                        new_lookup_parames.update({k: list_v})
                    else:
                        new_lookup_parames.update({k: v})
                queryset = queryset.filter(**new_lookup_parames)
        except (SuspiciousOperation, ImproperlyConfigured):
            raise
        except Exception as e:
            raise IncorrectLookupParameters(e)
        else:
            if not isinstance(queryset, models.query.QuerySet):
                pass

        query = self.request.GET.get(SEARCH_VAR, '')

        # Apply keyword searches.
        def construct_search(field_name):
            if field_name.startswith('^'):
                return "%s__istartswith" % field_name[1:]
            elif field_name.startswith('='):
                return "%s__iexact" % field_name[1:]
            elif field_name.startswith('@'):
                return "%s__search" % field_name[1:]
            else:
                return "%s__icontains" % field_name

        if self.search_fields and query:
            orm_lookups = [
                construct_search(str(search_field))
                for search_field in self.search_fields
            ]
            for bit in query.split():
                or_queries = [
                    models.Q(**{orm_lookup: bit}) for orm_lookup in orm_lookups
                ]
                queryset = queryset.filter(reduce(operator.or_, or_queries))
            if not use_distinct:
                for search_spec in orm_lookups:
                    if lookup_needs_distinct(self.opts, search_spec):
                        use_distinct = True
                        break
            self.admin_view.search_query = query

        if use_distinct:
            return queryset.distinct()
        else:
            return queryset
예제 #46
0
파일: filters.py 프로젝트: jdk6979/django
    def get_list_queryset(self, queryset):
        lookup_params = dict([(smart_str(k)[len(FILTER_PREFIX):], v) for k, v in self.admin_view.params.items()
                              if smart_str(k).startswith(FILTER_PREFIX) and v != ''])
        for p_key, p_val in iteritems(lookup_params):
            if p_val == "False":
                lookup_params[p_key] = False
        use_distinct = False

        # for clean filters
        self.admin_view.has_query_param = bool(lookup_params)
        self.admin_view.clean_query_url = self.admin_view.get_query_string(remove=[k for k in self.request.GET.keys() if
                                                                                   k.startswith(FILTER_PREFIX)])

        # Normalize the types of keys
        if not self.free_query_filter:
            for key, value in lookup_params.items():
                if not self.lookup_allowed(key, value):
                    raise SuspiciousOperation(
                        "Filtering by %s not allowed" % key)

        self.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(self.request, lookup_params,
                                       self.model, self)
                else:
                    field_path = None
                    field_parts = []
                    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, filter_manager.create
                    if not isinstance(field, models.Field):
                        field_path = field
                        field_parts = get_fields_from_path(
                            self.model, field_path)
                        field = field_parts[-1]
                    spec = field_list_filter_class(
                        field, self.request, lookup_params,
                        self.model, self.admin_view, field_path=field_path)

                    if len(field_parts) > 1:
                        # Add related model name to title
                        spec.title = "%s %s" % (field_parts[-2].name, spec.title)

                    # Check if we need to use distinct()
                    use_distinct = (use_distinct or
                                    lookup_needs_distinct(self.opts, field_path))
                if spec and spec.has_output():
                    try:
                        new_qs = spec.do_filte(queryset)
                    except ValidationError as e:
                        new_qs = None
                        self.admin_view.message_user(_("<b>Filtering error:</b> %s") % e.messages[0], 'error')
                    if new_qs is not None:
                        queryset = new_qs

                    self.filter_specs.append(spec)

        self.has_filters = bool(self.filter_specs)
        self.admin_view.filter_specs = self.filter_specs
        obj = filter(lambda f: f.is_used, self.filter_specs)
        if six.PY3:
            obj = list(obj)
        self.admin_view.used_filter_num = len(obj)

        try:
            for key, value in lookup_params.items():
                use_distinct = (
                    use_distinct or lookup_needs_distinct(self.opts, key))
        except FieldDoesNotExist as e:
            raise IncorrectLookupParameters(e)

        try:
            # fix a bug by david: In demo, quick filter by IDC Name() cannot be used.
            if isinstance(queryset, models.query.QuerySet) and lookup_params:
                new_lookup_parames = dict()
                for k, v in lookup_params.items():
                    list_v = v.split(',')
                    if len(list_v) > 0:
                        new_lookup_parames.update({k: list_v})
                    else:
                        new_lookup_parames.update({k: v})
                queryset = queryset.filter(**new_lookup_parames)
        except (SuspiciousOperation, ImproperlyConfigured):
            raise
        except Exception as e:
            raise IncorrectLookupParameters(e)
        else:
            if not isinstance(queryset, models.query.QuerySet):
                pass

        query = self.request.GET.get(SEARCH_VAR, '')

        # Apply keyword searches.
        def construct_search(field_name):
            if field_name.startswith('^'):
                return "%s__istartswith" % field_name[1:]
            elif field_name.startswith('='):
                return "%s__iexact" % field_name[1:]
            elif field_name.startswith('@'):
                return "%s__search" % field_name[1:]
            else:
                return "%s__icontains" % field_name

        if self.search_fields and query:
            orm_lookups = [construct_search(str(search_field))
                           for search_field in self.search_fields]
            for bit in query.split():
                or_queries = [models.Q(**{orm_lookup: bit})
                              for orm_lookup in orm_lookups]
                queryset = queryset.filter(reduce(operator.or_, or_queries))
            if not use_distinct:
                for search_spec in orm_lookups:
                    if lookup_needs_distinct(self.opts, search_spec):
                        use_distinct = True
                        break
            self.admin_view.search_query = query

        if use_distinct:
            return queryset.distinct()
        else:
            return queryset