Exemple #1
0
    def test_resolve_transformed_lookups(self):
        """
        Check that chained field transforms are correctly resolved.
        eg, a 'date__year__gte' lookup on an article's 'published' timestamp.
        """
        # Use a DateTimeField, so we can check multiple transforms.
        # eg, date__year__gte
        model_field = Article._meta.get_field('published')

        standard_lookups = [
            'exact',
            'iexact',
            'gte',
            'gt',
            'lte',
            'lt',
        ]

        date_lookups = [
            'year',
            'month',
            'day',
            'week_day',
        ]

        datetime_lookups = date_lookups + [
            'hour',
            'minute',
            'second',
        ]

        # ex: 'date__gt'
        for lookup in standard_lookups:
            field, resolved_lookup = resolve_field(model_field, LOOKUP_SEP.join(['date', lookup]))
            self.assertIsInstance(field, models.DateField)
            self.assertEqual(resolved_lookup, lookup)

        # ex: 'year__iexact'
        for part in datetime_lookups:
            for lookup in standard_lookups:
                field, resolved_lookup = resolve_field(model_field, LOOKUP_SEP.join([part, lookup]))
                self.assertIsInstance(field, models.IntegerField)
                self.assertEqual(resolved_lookup, lookup)

        # ex: 'date__year__lte'
        for part in date_lookups:
            for lookup in standard_lookups:
                field, resolved_lookup = resolve_field(model_field, LOOKUP_SEP.join(['date', part, lookup]))
                self.assertIsInstance(field, models.IntegerField)
                self.assertEqual(resolved_lookup, lookup)
    def __new__(cls, name, bases, attrs):
        new_class = super(FilterSetMetaclass, cls).__new__(cls, name, bases, attrs)

        # Populate our FilterSet fields with all the possible
        # filters for the AllLookupsFilter field.
        for name, filter_ in six.iteritems(new_class.base_filters.copy()):
            if isinstance(filter_, filters.AllLookupsFilter):
                model = new_class._meta.model
                field = filterset.get_model_field(model, filter_.name)

                for lookup_type in django_filters.filters.LOOKUP_TYPES:
                    if isinstance(field, ForeignObjectRel):
                        f = new_class.filter_for_reverse_field(field, filter_.name)
                    else:
                        f = new_class.filter_for_field(field, filter_.name)
                    f.lookup_type = lookup_type
                    f = new_class.fix_filter_field(f)

                    # compute filter name
                    filter_name = name
                    # Don't add "exact" to filter names
                    if lookup_type != 'exact':
                        filter_name = LOOKUP_SEP.join([name, lookup_type])

                    new_class.base_filters[filter_name] = f

            elif name not in new_class.declared_filters:
                new_class.base_filters[name] = new_class.fix_filter_field(filter_)

        return new_class
 def construct_search(self, field_name):
     lookup = self.lookup_prefixes.get(field_name[0])
     if lookup:
         field_name = field_name[1:]
     else:
         lookup = 'icontains'
     return LOOKUP_SEP.join([field_name, lookup])
 def construct_search(self, field_name):
     lookup = self.lookup_prefixes.get(field_name[0])
     if lookup:
         field_name = field_name[1:]
     else:
         lookup = 'icontains'
     return LOOKUP_SEP.join([field_name, lookup])
Exemple #5
0
def reverse_field_path(model, path):
    """ Create a reversed field path.

    E.g. Given (Order, "user__groups"),
    return (Group, "user__order").

    Final field must be a related model, not a data field.

    """
    reversed_path = []
    parent = model
    pieces = path.split(LOOKUP_SEP)
    for piece in pieces:
        field, model, direct, m2m = parent._meta.get_field_by_name(piece)
        # skip trailing data field if extant:
        if len(reversed_path) == len(pieces) - 1:  # final iteration
            try:
                get_model_from_relation(field)
            except NotRelationField:
                break
        if direct:
            related_name = field.related_query_name()
            parent = field.rel.to
        else:
            related_name = field.field.name
            parent = field.model
        reversed_path.insert(0, related_name)
    return (parent, LOOKUP_SEP.join(reversed_path))
Exemple #6
0
def _get_clean_name(name):
    # Get rid of __lt, __gt etc for the currency lookup
    path = name.split(LOOKUP_SEP)
    if path[-1] in QUERY_TERMS:
        return LOOKUP_SEP.join(path[:-1])
    else:
        return name
Exemple #7
0
def reverse_field_path(model, path):
    """ Create a reversed field path.

    E.g. Given (Order, "user__groups"),
    return (Group, "user__order").

    Final field must be a related model, not a data field.
    """
    reversed_path = []
    parent = model
    pieces = path.split(LOOKUP_SEP)
    for piece in pieces:
        field = parent._meta.get_field(piece)
        # skip trailing data field if extant:
        if len(reversed_path) == len(pieces) - 1:  # final iteration
            try:
                get_model_from_relation(field)
            except NotRelationField:
                break

        # Field should point to another model
        if field.is_relation and not (field.auto_created
                                      and not field.concrete):
            related_name = field.related_query_name()
            parent = field.remote_field.model
        else:
            related_name = field.field.name
            parent = field.related_model
        reversed_path.insert(0, related_name)
    return (parent, LOOKUP_SEP.join(reversed_path))
Exemple #8
0
    def filter_related_filtersets(self, queryset):
        """Filter the provided ``queryset`` by the ``related_filtersets``.

        Override this method to change the filtering behavior across relationships.

        Args:
            queryset: The filterset's filtered queryset.

        Returns:
            The ``queryset`` filtered by its related filtersets' querysets.
        """
        for related_name, related_filterset in self.related_filtersets.items():
            # Related filtersets should only be applied if they had data.
            prefix = '%s%s' % (related(self, related_name), LOOKUP_SEP)
            if not any(value.startswith(prefix) for value in self.data):
                continue

            field = self.filters[related_name].field
            to_field_name = getattr(field, 'to_field_name', 'pk') or 'pk'

            field_name = self.filters[related_name].field_name
            lookup_expr = LOOKUP_SEP.join([field_name, 'in'])

            subquery = related_filterset.qs.values(to_field_name)
            queryset = queryset.filter(**{lookup_expr: subquery})

            # handle disinct
            if self.related_filters[related_name].distinct:
                queryset = queryset.distinct()

        return queryset
    def _get_ancestors_path(self, model, levels=None):
        """
        Serves as an opposite to _get_subclasses_recurse, instead walking from
        the Model class up the Model's ancestry and constructing the desired
        select_related string backwards.
        """
        if not issubclass(model, self.model):
            raise ValueError(
                "%r is not a subclass of %r" % (model, self.model))

        ancestry = []
        # should be a OneToOneField or None
        parent_link = model._meta.get_ancestor_link(self.model)
        if levels:
            levels -= 1
        while parent_link is not None:
            related = parent_link.remote_field
            ancestry.insert(0, related.get_accessor_name())
            if levels or levels is None:
                parent_model = related.model
                parent_link = parent_model._meta.get_ancestor_link(
                    self.model)
            else:
                parent_link = None
        return LOOKUP_SEP.join(ancestry)
def lookups_for_transform(transform):
    """
    Generates a list of subsequent lookup expressions for a transform.

    Note:
    Infinite transform recursion is only prevented when the subsequent and
    passed in transforms are the same class. For example, the ``Unaccent``
    transform from ``django.contrib.postgres``.
    There is no cycle detection across multiple transforms. For example,
    ``a__b__a__b`` would continue to recurse. However, this is not currently
    a problem (no builtin transforms exhibit this behavior).

    """
    lookups = []

    for expr, lookup in six.iteritems(class_lookups(transform.output_field)):
        if issubclass(lookup, Transform):

            # type match indicates recursion.
            if type(transform) == lookup:
                continue

            sub_transform = lookup(transform)
            lookups += [
                LOOKUP_SEP.join([expr, sub_expr])
                for sub_expr in lookups_for_transform(sub_transform)
            ]

        else:
            lookups.append(expr)

    return lookups
Exemple #11
0
def _get_related_path(model, base_model):
    """Return path suitable for select related for sublcass."""
    ancestry = []

    if model._meta.proxy:
        for parent in model._meta.get_parent_list():
            if not parent._meta.proxy:
                model = parent
                break

    parent = model._meta.get_ancestor_link(base_model)

    while parent is not None:
        related = parent.remote_field if hasattr(
            parent, 'remote_field') else parent.related

        ancestry.insert(0, related.get_accessor_name())

        if django.VERSION < (1, 8):
            parent_model = related.parent_model
        else:
            parent_model = related.model

        parent = parent_model._meta.get_ancestor_link(base_model)

    return LOOKUP_SEP.join(ancestry)
Exemple #12
0
    def _get_field(self, lookup):
        """
        Return the Django model field for a lookup plus the remainder of the lookup,
        which should be the lookup type.
        """
        model = self.model
        lookup_type = None

        # pk is not an actual field, but an alias for the implicit id field.
        if lookup == "pk":
            key = None
            for field in model._meta.get_fields():
                if getattr(field, "primary_key", False):
                    key = field
            return key, None

        field = None
        bits = lookup.split(LOOKUP_SEP)

        for i, bit in enumerate(bits):
            try:
                field = model._meta.get_field(bit)
            except FieldDoesNotExist:
                lookup_type = LOOKUP_SEP.join(bits[i:])
                break

            if hasattr(field, "remote_field"):
                rel = getattr(field, "remote_field", None)
                model = getattr(rel, "model", model)

        return field, lookup_type
 def __missing__(self, model_key):
     """
     Generate the accessors for this model by recursively generating its
     children accessors and prefixing them.
     """
     owner = self.apps.get_model(*model_key)
     if not issubclass(owner, self.model):
         raise KeyError
     accessors = {owner: EMPTY_ACCESSOR}
     with self.lock:
         for model in self.apps.get_models():
             opts = model._meta
             if opts.proxy and issubclass(
                     model, owner) and (owner._meta.proxy
                                        or opts.concrete_model is owner):
                 accessors[model] = SubclassAccessor((), model, '')
             # Use .get() instead of `in` as proxy inheritance is also
             # stored in _meta.parents as None.
             elif opts.parents.get(owner):
                 part = opts.model_name
                 for child, (
                         parts, proxy,
                         _lookup) in self[self.get_model_key(opts)].items():
                     accessors[child] = SubclassAccessor(
                         (part, ) + parts, proxy,
                         LOOKUP_SEP.join((part, ) + parts))
     return accessors
    def _get_ancestors_path(self, model, levels=None):
        """
        Serves as an opposite to _get_subclasses_recurse, instead walking from
        the Model class up the Model's ancestry and constructing the desired
        select_related string backwards.
        """
        if not issubclass(model, self.model):
            raise ValueError("%r is not a subclass of %r" %
                             (model, self.model))

        ancestry = []
        # should be a OneToOneField or None
        parent_link = model._meta.get_ancestor_link(self.model)
        if levels:
            levels -= 1
        while parent_link is not None:
            ancestry.insert(0, parent_link.related.get_accessor_name())
            if levels or levels is None:
                if django.VERSION < (1, 8):
                    parent_model = parent_link.related.parent_model
                else:
                    parent_model = parent_link.related.model
                parent_link = parent_model._meta.get_ancestor_link(self.model)
            else:
                parent_link = None
        return LOOKUP_SEP.join(ancestry)
def lookups_for_transform(transform):
    """
    Generates a list of subsequent lookup expressions for a transform.

    Note:
    Infinite transform recursion is only prevented when the subsequent and
    passed in transforms are the same class. For example, the ``Unaccent``
    transform from ``django.contrib.postgres``.
    There is no cycle detection across multiple transforms. For example,
    ``a__b__a__b`` would continue to recurse. However, this is not currently
    a problem (no builtin transforms exhibit this behavior).

    """
    lookups = []

    for expr, lookup in six.iteritems(class_lookups(transform.output_field)):
        if issubclass(lookup, Transform):

            # type match indicates recursion.
            if type(transform) == lookup:
                continue

            sub_transform = lookup(transform)
            lookups += [
                LOOKUP_SEP.join([expr, sub_expr]) for sub_expr
                in lookups_for_transform(sub_transform)
            ]

        else:
            lookups.append(expr)

    return lookups
    def build_filters(self, filters=None):
        if filters is None:
            filters = {}

        qs_filters = {}

        if getattr(self._meta, 'queryset', None) is not None:
            # Get the possible query terms from the current QuerySet.
            query_terms = self._meta.queryset.query.query_terms
        else:
            query_terms = QUERY_TERMS

        for filter_expr, value in filters.items():
            filter_bits = filter_expr.split(LOOKUP_SEP)
            field_name = filter_bits.pop(0)
            filter_type = 'exact'

            if not field_name in self.fields:
                # It's not a field we know about. Move along citizen.
                continue

            if len(filter_bits) and filter_bits[-1] in query_terms:
                filter_type = filter_bits.pop()

            lookup_bits = self.check_filtering(field_name, filter_type, filter_bits)
            value = self.filter_value_to_python(value, field_name, filters, filter_expr, filter_type)

            db_field_name = LOOKUP_SEP.join(lookup_bits)
            qs_filter = "%s%s%s" % (db_field_name, LOOKUP_SEP, filter_type)
            qs_filters[qs_filter] = value

        return dict_strip_unicode_keys(qs_filters)
Exemple #17
0
def reverse_field_path(model, path):
    """ Create a reversed field path.

    E.g. Given (Order, "user__groups"),
    return (Group, "user__order").

    Final field must be a related model, not a data field.
    """
    reversed_path = []
    parent = model
    pieces = path.split(LOOKUP_SEP)
    for piece in pieces:
        field = parent._meta.get_field(piece)
        # skip trailing data field if extant:
        if len(reversed_path) == len(pieces) - 1:  # final iteration
            try:
                get_model_from_relation(field)
            except NotRelationField:
                break

        # Field should point to another model
        if field.is_relation and not (field.auto_created and not field.concrete):
            related_name = field.related_query_name()
            parent = field.remote_field.model
        else:
            related_name = field.field.name
            parent = field.related_model
        reversed_path.insert(0, related_name)
    return (parent, LOOKUP_SEP.join(reversed_path))
Exemple #18
0
def related(filterset, filter_name):
    """
    Return a related filter_name, using the filterset relationship if present.
    """
    if not filterset.relationship:
        return filter_name
    return LOOKUP_SEP.join([filterset.relationship, filter_name])
Exemple #19
0
def _get_clean_name(name):
    # Get rid of __lt, __gt etc for the currency lookup
    path = name.split(LOOKUP_SEP)
    if path[-1] in QUERY_TERMS:
        return LOOKUP_SEP.join(path[:-1])
    else:
        return name
    def _expandable_fields(self):
        """
        Get all defined expandable fields with their path within serializers
        """
        components = []
        root = self.root
        f = self
        while f is not root:
            if f.parent is root and isinstance(f.parent,
                                               serializers.ListSerializer):
                break
            if isinstance(f, serializers.ListSerializer):
                f = f.parent
            else:
                components.insert(0, f.field_name)
                f = f.parent

        nt = namedtuple("ExpandableField",
                        ["name", "parts", "path", "replacement"])

        for name, replacement in getattr(self.Meta, "expandable_fields",
                                         {}).items():
            parts = components + [name]
            path = LOOKUP_SEP.join(parts)
            yield nt(name, parts, path, copy.deepcopy(replacement))
Exemple #21
0
def reverse_field_path(model, path):
    """ Create a reversed field path.

    E.g. Given (Order, "user__groups"),
    return (Group, "user__order").

    Final field must be a related model, not a data field.

    """
    reversed_path = []
    parent = model
    pieces = path.split(LOOKUP_SEP)
    for piece in pieces:
        field, model, direct, m2m = parent._meta.get_field_by_name(piece)
        # skip trailing data field if extant:
        if len(reversed_path) == len(pieces) - 1:  # final iteration
            try:
                get_model_from_relation(field)
            except NotRelationField:
                break
        if direct:
            related_name = field.related_query_name()
            parent = field.rel.to
        else:
            related_name = field.field.name
            parent = field.model
        reversed_path.insert(0, related_name)
    return (parent, LOOKUP_SEP.join(reversed_path))
    def _get_all_expandable_fields(self, parents, this, exclude):
        """
        Recursively search for all expandable fields on class
        """
        nt = namedtuple("ExpandableField", ["query_key", "parts", "path"])

        query_key = getattr(getattr(this, "Meta", None),
                            "expandable_query_key", "expand")
        for name in getattr(getattr(this, "Meta", None), "expandable_fields",
                            {}):
            parts = parents + [name]
            path = LOOKUP_SEP.join(parts)
            if path in exclude:
                continue
            yield nt(query_key, parts, path)

        for field_name, field in this.fields.items():
            if not isinstance(field, serializers.BaseSerializer):
                continue
            if isinstance(field, serializers.ListSerializer):
                field = field.child

            for i in self._get_all_expandable_fields(parents=parents +
                                                     [field_name],
                                                     this=field,
                                                     exclude=exclude):
                yield i
Exemple #23
0
def _get_related_path(model, base_model):
    """Return path suitable for select related for sublcass."""
    ancestry = []

    if model._meta.proxy:
        for parent in model._meta.get_parent_list():
            if not parent._meta.proxy:
                model = parent
                break

    parent = model._meta.get_ancestor_link(base_model)

    while parent is not None:
        related = parent.remote_field if hasattr(parent, 'remote_field') else parent.rel

        ancestry.insert(0, related.get_accessor_name())

        if django.VERSION < (1, 8):
            parent_model = related.parent_model
        else:
            parent_model = related.model

        parent = parent_model._meta.get_ancestor_link(base_model)

    return LOOKUP_SEP.join(ancestry)
Exemple #24
0
    def lookup_allowed(self, lookup, value):
    # overriden to allow filter on cell_filter fields
    #        import django.contrib.admin.options
    #        django.contrib.admin.options.QUERY_TERMS.update({'not':'not'})
        original = DjangoModelAdmin.lookup_allowed(self, lookup, value)
        if original:
            return True
        model = self.model
        parts = lookup.split(LOOKUP_SEP)
        if len(parts) > 1 and parts[-1] in QUERY_TERMS:
            parts.pop()

        pk_attr_name = None
        for part in parts[:-1]:
            field, _, _, _ = model._meta.get_field_by_name(part)
            if hasattr(field, 'rel'):
                model = field.rel.to
                pk_attr_name = model._meta.pk.name
            elif isinstance(field, RelatedObject):
                model = field.model
                pk_attr_name = model._meta.pk.name
            else:
                pk_attr_name = None
        if pk_attr_name and len(parts) > 1 and parts[-1] == pk_attr_name:
            parts.pop()
        clean_lookup = LOOKUP_SEP.join(parts)

        flat_filter = [isinstance(v, tuple) and v[0] or v for v in self.list_filter]
        flat_filter.extend([isinstance(v, tuple) and v[0] or v for v in self.cell_filter])
        return clean_lookup in self.extra_allowed_filter or clean_lookup in flat_filter
Exemple #25
0
    def get_filters(self):
        """
        Build a set of filters based on the requested data. The resulting set
        will walk `RelatedFilter`s to recursively build the set of filters.
        """
        # build param data for related filters: {rel: {param: value}}
        related_data = OrderedDict(
            [(name, OrderedDict()) for name in self.__class__.related_filters]
        )
        for param, value in six.iteritems(self.data):
            filter_name, related_param = self.get_related_filter_param(param)

            # skip non lookup/related keys
            if filter_name is None:
                continue

            if filter_name in related_data:
                related_data[filter_name][related_param] = value

        # build the compiled set of all filters
        requested_filters = OrderedDict()
        for filter_name, f in six.iteritems(self.filters):
            exclude_name = '%s!' % filter_name

            # Add plain lookup filters if match. ie, `username__icontains`
            if filter_name in self.data:
                requested_filters[filter_name] = f

            # include exclusion keys
            if exclude_name in self.data:
                f = copy.deepcopy(f)
                f.exclude = not f.exclude
                requested_filters[exclude_name] = f

            # include filters from related subsets
            if isinstance(f, filters.RelatedFilter) and filter_name in related_data:
                subset_data = related_data[filter_name]
                subset_class = f.filterset.get_subset(subset_data)
                filterset = subset_class(data=subset_data)

                # modify filter names to account for relationship
                for related_name, related_f in six.iteritems(filterset.get_filters()):
                    related_name = LOOKUP_SEP.join([filter_name, related_name])
                    related_f.name = LOOKUP_SEP.join([f.name, related_f.name])
                    requested_filters[related_name] = related_f

        return requested_filters
def prepare_polymorphic_model(sender, **kwargs):
    if issubclass(sender, BasePolymorphicModel):
        opts = sender._meta
        try:
            content_type_field_name = getattr(sender, 'CONTENT_TYPE_FIELD')
        except AttributeError:
            raise ImproperlyConfigured(
                '`BasePolymorphicModel` subclasses must '
                'define a `CONTENT_TYPE_FIELD`.'
            )
        else:
            try:
                content_type_field = opts.get_field(content_type_field_name)
            except FieldDoesNotExist:
                raise ImproperlyConfigured(
                    '`%s.%s.CONTENT_TYPE_FIELD` points to an inexistent field "%s".'
                    % (sender.__module__, sender.__name__, content_type_field_name)
                )
            else:
                if (not isinstance(content_type_field, models.ForeignKey) or
                    content_type_field.rel.to is not ContentType):
                    raise ImproperlyConfigured(
                        '`%s.%s.%s` must be a `ForeignKey` to `ContentType`.'
                        % (sender.__module__, sender.__name__, content_type_field_name)
                    )
        setattr(opts, '_subclass_accessors', {})
        parents = [sender]
        proxy = sender if opts.proxy else None
        attrs = []
        while parents:
            parent = parents.pop(0)
            if issubclass(parent, BasePolymorphicModel):
                parent_opts = parent._meta
                # We can't do `select_related` on multiple one-to-one
                # relationships on django < 1.6
                # see https://code.djangoproject.com/ticket/16572 and
                # https://code.djangoproject.com/ticket/13781
                if django.VERSION < (1, 6):
                    lookup = LOOKUP_SEP.join(attrs[0:1])
                else:
                    lookup = LOOKUP_SEP.join(attrs)
                parent_opts._subclass_accessors[sender] = (tuple(attrs), proxy, lookup)
                if parent_opts.proxy:
                    parents.insert(0, parent_opts.proxy_for_model)
                else:
                    attrs.insert(0, model_name(parent_opts))
                    parents = list(parent._meta.parents.keys()) + parents
Exemple #27
0
def prepare_polymorphic_model(sender, **kwargs):
    if issubclass(sender, BasePolymorphicModel):
        opts = sender._meta
        try:
            content_type_field_name = getattr(sender, 'CONTENT_TYPE_FIELD')
        except AttributeError:
            raise ImproperlyConfigured(
                '`BasePolymorphicModel` subclasses must '
                'define a `CONTENT_TYPE_FIELD`.')
        else:
            try:
                content_type_field = opts.get_field(content_type_field_name)
            except FieldDoesNotExist:
                raise ImproperlyConfigured(
                    '`%s.%s.CONTENT_TYPE_FIELD` points to an inexistent field "%s".'
                    % (sender.__module__, sender.__name__,
                       content_type_field_name))
            else:
                if (not isinstance(content_type_field, models.ForeignKey)
                        or content_type_field.rel.to is not ContentType):
                    raise ImproperlyConfigured(
                        '`%s.%s.%s` must be a `ForeignKey` to `ContentType`.' %
                        (sender.__module__, sender.__name__,
                         content_type_field_name))
        setattr(opts, '_subclass_accessors', {})
        parents = [sender]
        proxy = sender if opts.proxy else None
        attrs = []
        while parents:
            parent = parents.pop(0)
            if issubclass(parent, BasePolymorphicModel):
                parent_opts = parent._meta
                # We can't do `select_related` on multiple one-to-one
                # relationships on django < 1.6
                # see https://code.djangoproject.com/ticket/16572 and
                # https://code.djangoproject.com/ticket/13781
                if django.VERSION < (1, 6):
                    lookup = LOOKUP_SEP.join(attrs[0:1])
                else:
                    lookup = LOOKUP_SEP.join(attrs)
                parent_opts._subclass_accessors[sender] = (tuple(attrs), proxy,
                                                           lookup)
                if parent_opts.proxy:
                    parents.insert(0, parent_opts.proxy_for_model)
                else:
                    attrs.insert(0, model_name(parent_opts))
                    parents = list(parent._meta.parents.keys()) + parents
Exemple #28
0
def join_lookup(*args):
    u"""
    Joins Django field lookup path skipping empty parts. For instance:
        join_lookup('foo', None, 'bar', 'bar') -> 'foo__bar__bar'
        join_lookup('foo') -> 'foo'
        join_lookup(None) -> ''
    """
    return LOOKUP_SEP.join(a for a in args if a)
Exemple #29
0
def join_lookup(*args):
    u"""
    Joins Django field lookup path skipping empty parts. For instance:
        join_lookup('foo', None, 'bar', 'bar') -> 'foo__bar__bar'
        join_lookup('foo') -> 'foo'
        join_lookup(None) -> ''
    """
    return LOOKUP_SEP.join(a for a in args if a)
 def get_filter_predicate(self, v):
     name = self.field_name
     if name and self.lookup_expr != 'exact':
         name = LOOKUP_SEP.join([name, self.lookup_expr])
     try:
         return {name: getattr(v, self.field.to_field_name)}
     except (AttributeError, TypeError):
         return {name: v}
Exemple #31
0
    def form_apply_select_related(self, form):
        for related_field in self.list_select_related:
            splitted = related_field.split(LOOKUP_SEP)

            if len(splitted) > 1:
                field = splitted[0]
                related = LOOKUP_SEP.join(splitted[1:])
                form.base_fields[field].queryset = form.base_fields[field].queryset.select_related(related)
Exemple #32
0
 def get_filter_predicate(self, v):
     name = self.field_name
     if name and self.lookup_expr != settings.DEFAULT_LOOKUP_EXPR:
         name = LOOKUP_SEP.join([name, self.lookup_expr])
     try:
         return {name: getattr(v, self.field.to_field_name)}
     except (AttributeError, TypeError):
         return {name: v}
Exemple #33
0
 def __init__(self, **extra):
     self.normalization = extra.pop("normalization", [])
     self.weights = extra.pop("weights", [])
     params = tuple(extra.items())[0]
     self.extra = extra
     lookups, self.rhs = params[0].split(LOOKUP_SEP), params[1]
     self.srt_lookup = lookups[-1]
     self.lookup = LOOKUP_SEP.join(lookups[:-1])
     self._do_checks()
 def to_internal_value(self, data):
     data = super().to_internal_value(data)
     for i in data[:]:
         parts = i.split(LOOKUP_SEP)
         data = list(
             ({LOOKUP_SEP.join(parts[:i]) for i in six.moves.range(1, len(parts))} & set(self.child.choices))
             | set(data)
         )
     return data
Exemple #35
0
 def __init__(self, **extra):
     self.normalization = extra.pop('normalization', [])
     self.weights = extra.pop('weights', [])
     params = tuple(extra.items())[0]
     self.extra, self.rhs = extra, params[1]
     lookups = params[0].split(LOOKUP_SEP)
     self.dictionary, self.srt_lookup = lookups[-2:]
     self.lookup = LOOKUP_SEP.join(lookups[:-2])
     self._do_checks()
Exemple #36
0
 def expanded_filters(self):
     if '_expanded_filters' not in self.__dict__:
         self._expanded_filters = self.base_filters.copy()
         for filter_name, f in self.related_filters.items():
             del self._expanded_filters[filter_name]
             for related_name, related_f in six.iteritems(f.filterset.expanded_filters):
                 related_name = LOOKUP_SEP.join([filter_name, related_name])
                 self._expanded_filters[related_name] = related_f
     return self._expanded_filters
Exemple #37
0
 def __init__(self, **extra):
     self.normalization = extra.pop('normalization', [])
     self.weights = extra.pop('weights', [])
     params = tuple(extra.items())[0]
     self.extra, self.rhs = extra, params[1]
     lookups = params[0].split(LOOKUP_SEP)
     self.dictionary, self.srt_lookup = lookups[-2:]
     self.lookup = LOOKUP_SEP.join(lookups[:-2])
     self._do_checks()
Exemple #38
0
 def filter_method(queryset, name, value):
     q_obj = Q()
     for field in fields:
         lookup = LOOKUP_SEP.join([field, lookup_expr])
         q_obj = q_obj & Q(**{lookup: value})
     if exclude:
         return queryset.exclude(q_obj)
     else:
         return queryset.filter(q_obj)
def lookups_to_text(lookups):
    """
    Givne a set of elements like [
        ('a', 'b', 'c'),
        ('d', 'e'),
    ]
    return something like:
    ('a__b__c', 'd__e')
    """
    return tuple(LOOKUP_SEP.join(lookup) for lookup in lookups)
    def _construct_search(self, field_name):
        lookup = self.lookup_prefixes.get(field_name[0])
        if not lookup:
            lookup = 'icontains'
        elif lookup == 'external_func':
            return None
        else:
            field_name = field_name[1:]

        return LOOKUP_SEP.join([field_name, lookup])
Exemple #41
0
 def filter_at_least(self, queryset, name, value):
     '''
     Evaluates if a proficiency is of at least a certain level
     F > X > P > 0 > 0+ . . . 5
     '''
     value = value.replace("plus", "+")
     index = Proficiency.RANKING.index(value)
     valid_ranks = Proficiency.RANKING[index:]
     lookup = LOOKUP_SEP.join([name, "in"])
     return queryset.filter(Q(**{lookup: valid_ranks}))
 def iteritems(self, lookup_stack=None):
     lookup_stack = [] if lookup_stack is None else lookup_stack
     for component, node in self.children.viewitems():
         if component == LookupComponent.EMPTY:
             yield (LookupComponent(LOOKUP_SEP.join(lookup_stack)),
                    self.value)
         else:
             lookup_stack.append(component)
             for item in node.iteritems(lookup_stack=lookup_stack):
                 yield item
             lookup_stack.pop()
Exemple #43
0
def refs_aggregate(lookup_parts, aggregates):
    """
    A little helper method to check if the lookup_parts contains references
    to the given aggregates set. Because the LOOKUP_SEP is contained in the
    default annotation names we must check each prefix of the lookup_parts
    for match.
    """
    for i in range(len(lookup_parts) + 1):
        if LOOKUP_SEP.join(lookup_parts[0:i]) in aggregates:
            return True
    return False
Exemple #44
0
def refs_aggregate(lookup_parts, aggregates):
    """
    A little helper method to check if the lookup_parts contains references
    to the given aggregates set. Because the LOOKUP_SEP is contained in the
    default annotation names we must check each prefix of the lookup_parts
    for match.
    """
    for i in range(len(lookup_parts) + 1):
        if LOOKUP_SEP.join(lookup_parts[0:i]) in aggregates:
            return True
    return False
 def iteritems(self, lookup_stack=None):
     lookup_stack = [] if lookup_stack is None else lookup_stack
     for component, node in six.viewitems(self.children):
         if component == LookupComponent.EMPTY:
             yield (LookupComponent(LOOKUP_SEP.join(lookup_stack)),
                    self.value)
         else:
             lookup_stack.append(component)
             for item in node.iteritems(lookup_stack=lookup_stack):
                 yield item
             lookup_stack.pop()
Exemple #46
0
def refs_expression(lookup_parts, annotations):
    """
    Check if the lookup_parts contains references to the given annotations set.
    Because the LOOKUP_SEP is contained in the default annotation names, check
    each prefix of the lookup_parts for a match.
    """
    for n in range(1, len(lookup_parts) + 1):
        level_n_lookup = LOOKUP_SEP.join(lookup_parts[0:n])
        if level_n_lookup in annotations and annotations[level_n_lookup]:
            return annotations[level_n_lookup], lookup_parts[n:]
    return False, ()
Exemple #47
0
 def construct_search(self, field_name):
     lookup = self.lookup_prefixes.get(field_name[0])
     if lookup:
         field_name = field_name[1:]
     else:
         lookup = "icontains"
     return LOOKUP_SEP.join([
         field_name,
         "unaccent",
         lookup,
     ])
Exemple #48
0
 def _relate_Q(self, q, relate_to):
     if not q:
         return q
     result = q.clone()
     for i, child in enumerate(result.children):
         if isinstance(child, Q):
             result.children[i] = self._relate_Q(child, relate_to)
         else:
             result.children[i] = (LOOKUP_SEP.join(relate_to + [child[0]]),
                                   child[1])
     return result
def refs_expression(lookup_parts, annotations):
    """
    Check if the lookup_parts contains references to the given annotations set.
    Because the LOOKUP_SEP is contained in the default annotation names, check
    each prefix of the lookup_parts for a match.
    """
    for n in range(1, len(lookup_parts) + 1):
        level_n_lookup = LOOKUP_SEP.join(lookup_parts[0:n])
        if level_n_lookup in annotations and annotations[level_n_lookup]:
            return annotations[level_n_lookup], lookup_parts[n:]
    return False, ()
    def lookup_allowed(self, lookup, value):
        ret = super(AdminExceptionFieldsFilterMixin, self).lookup_allowed(lookup, value)
        if not ret and self.exception_fields_filter:
            parts = lookup.split(LOOKUP_SEP)

            if len(parts) > 1 and parts[-1] in QUERY_TERMS:
                parts.pop()
                clean_lookup = LOOKUP_SEP.join(parts)
                if clean_lookup in self.exception_fields_filter:
                    return True
        return ret
Exemple #51
0
 def form_apply_prefetch_related(self, form):
     for related_field in self.list_prefetch_related:
         splitted = related_field.split(LOOKUP_SEP)
         if len(splitted) > 1:
             field = splitted[0]
             related = LOOKUP_SEP.join(splitted[1:])
             try:
                 form.base_fields[field].queryset = form.base_fields[
                     field].queryset.prefetch_related(related)
             except KeyError:
                 pass
Exemple #52
0
def refs_aggregate(lookup_parts, aggregates):
    """
    A helper method to check if the lookup_parts contains references
    to the given aggregates set. Because the LOOKUP_SEP is contained in the
    default annotation names we must check each prefix of the lookup_parts
    for a match.
    """
    for n in range(len(lookup_parts) + 1):
        level_n_lookup = LOOKUP_SEP.join(lookup_parts[0:n])
        if level_n_lookup in aggregates and aggregates[level_n_lookup].contains_aggregate:
            return aggregates[level_n_lookup], lookup_parts[n:]
    return False, ()
 def get_queryset(self):
     filters = {}
     ancestor_lookups = []
     resource_names_and_lookups = \
         _get_resource_ancestors_and_lookups(flattened_resource)
     for resource_name, lookup in resource_names_and_lookups:
         urlvar_value = self.kwargs[resource_name]
         ancestor_lookups.append(lookup)
         lookup = LOOKUP_SEP.join(ancestor_lookups)
         filters[lookup] = urlvar_value
     queryset = super(NestedViewSet, self).get_queryset()
     queryset = queryset.filter(**filters)
     return queryset
def _all_filters(filterset, prefix=()):
    for name, field in filterset.filters.items():
        if isinstance(field, FilterSet):
            for i in _all_filters(field, prefix=prefix + (name,)):
                yield i

        else:
            yield coreapi.Field(
                name=LOOKUP_SEP.join(prefix + (name,)),
                required=False,
                location="query",
                schema=_field_to_schema(field, field.default_lookup),
            )
            if field.no_lookup:
                continue
            for lookup in field.lookups:
                yield coreapi.Field(
                    name=LOOKUP_SEP.join(prefix + (name, lookup)),
                    required=False,
                    location="query",
                    schema=_field_to_schema(field, lookup),
                )
def expand_lookup(opts, field_name):
    """
    Utility that expands simple multilingual lookup to lookup which can be handled by DJango ORM.
    """
    # Check if field is a translation
    field = _get_proxy_or_none(opts, field_name)
    if field is None:
        # Not a multilingual lookup, return
        return field_name

    # Multilingual field, add 'TranslationRelation' to lookup
    translation_name = '%s_%s' % (TRANSLATION_FIELD_NAME, sanitize_language_code(field.language_code))
    return LOOKUP_SEP.join((translation_name, field.field_name))
Exemple #56
0
    def lookup_allowed(self, lookup, value):
        model = self.model
        # Check FKey lookups that are allowed, so that popups produced by
        # ForeignKeyRawIdWidget, on the basis of ForeignKey.limit_choices_to,
        # are allowed to work.
        for l in model._meta.related_fkey_lookups:
            for k, v in widgets.url_params_from_lookup_dict(l).items():
                if k == lookup and v == value:
                    return True

        parts = lookup.split(LOOKUP_SEP)

        # Last term in lookup is a query term (__exact, __startswith etc)
        # This term can be ignored.
        if len(parts) > 1 and parts[-1] in QUERY_TERMS:
            parts.pop()

        # Special case -- foo__id__exact and foo__id queries are implied
        # if foo has been specifically included in the lookup list; so
        # drop __id if it is the last part. However, first we need to find
        # the pk attribute name.
        rel_name = None
        for part in parts[:-1]:
            try:
                field, _, _, _ = model._meta.get_field_by_name(part)
            except FieldDoesNotExist:
                # Lookups on non-existent fields are ok, since they're ignored
                # later.
                return True
            if hasattr(field, 'rel'):
                if field.rel is None:
                    # This property or relation doesn't exist, but it's allowed
                    # since it's ignored in ChangeList.get_filters().
                    return True
                model = field.rel.to
                rel_name = field.rel.get_related_field().name
            elif isinstance(field, ForeignObjectRel):
                model = field.model
                rel_name = model._meta.pk.name
            else:
                rel_name = None
        if rel_name and len(parts) > 1 and parts[-1] == rel_name:
            parts.pop()

        if len(parts) == 1:
            return True
        clean_lookup = LOOKUP_SEP.join(parts)
        return (
            clean_lookup in self.list_filter
            or clean_lookup == self.date_hierarchy)
    def build_filter(self, filter_expr, branch_negated=False, current_negated=False,
                     can_reuse=None):
        """
        Build filters with respect to the multilingual fields.
        """
        arg, value = filter_expr
        parts = arg.split(LOOKUP_SEP)

        field_name = parts[0]
        new_name = expand_lookup(self.get_meta(), field_name)
        filter_expr = LOOKUP_SEP.join([new_name] + parts[1:]), value

        return super(MultilingualQuery, self).build_filter(filter_expr, branch_negated=branch_negated,
                                                           current_negated=current_negated, can_reuse=can_reuse)
		def _filter_or_exclude(self, negate, *args, **kwargs):
			localized_kwargs = {}
			if self.language:
				for lookup in kwargs:
					parts = lookup.split(LOOKUP_SEP)
					fieldname = parts[0]
					localized_fieldname = fieldname
					if fieldname in getattr(self.model, '_i18n_attributes', ()):
						localized_fieldname = '%s_%s' % (fieldname, self.language)
					localized_lookup = LOOKUP_SEP.join([localized_fieldname] + parts[1:])
					localized_kwargs[localized_lookup] = kwargs[lookup]
			else:
				localized_kwargs = kwargs
			return super(LocalizedQuerySet, self)._filter_or_exclude(negate, *args, **localized_kwargs)
Exemple #59
0
    def get_filter_name(cls, field_name, lookup_expr):
        """
        Combine a field name and lookup expression into a usable filter name.
        Exact lookups are the implicit default, so "exact" is stripped from the
        end of the filter name.
        """
        filter_name = LOOKUP_SEP.join([field_name, lookup_expr])

        # This also works with transformed exact lookups, such as 'date__exact'
        _exact = LOOKUP_SEP + 'exact'
        if filter_name.endswith(_exact):
            filter_name = filter_name[:-len(_exact)]

        return filter_name