def add_filter(self, filter_expr, connector=AND, negate=False, trim=False,
            can_reuse=None, process_extras=True, force_having=False):
        """
        Add a single filter to the query. The 'filter_expr' is a pair:
        (filter_string, value). E.g. ('name__contains', 'fred')

        If 'negate' is True, this is an exclude() filter. It's important to
        note that this method does not negate anything in the where-clause
        object when inserting the filter constraints. This is because negated
        filters often require multiple calls to add_filter() and the negation
        should only happen once. So the caller is responsible for this (the
        caller will normally be add_q(), so that as an example).

        If 'trim' is True, we automatically trim the final join group (used
        internally when constructing nested queries).

        If 'can_reuse' is a set, we are processing a component of a
        multi-component filter (e.g. filter(Q1, Q2)). In this case, 'can_reuse'
        will be a set of table aliases that can be reused in this filter, even
        if we would otherwise force the creation of new aliases for a join
        (needed for nested Q-filters). The set is updated by this method.

        If 'process_extras' is set, any extra filters returned from the table
        joining process will be processed. This parameter is set to False
        during the processing of extra filters to avoid infinite recursion.
        """
        arg, value = filter_expr
        parts = arg.split(LOOKUP_SEP)
        if not parts:
            raise FieldError("Cannot parse keyword query %r" % arg)

        # Work out the lookup type and remove it from the end of 'parts',
        # if necessary.
        lookup_type = 'exact' # Default lookup type
        num_parts = len(parts)
        if (len(parts) > 1 and parts[-1] in self.query_terms
            and arg not in self.aggregates):
            # Traverse the lookup query to distinguish related fields from
            # lookup types.
            lookup_model = self.model
            for counter, field_name in enumerate(parts):
                try:
                    lookup_field = lookup_model._meta.get_field(field_name)
                except FieldDoesNotExist:
                    # Not a field. Bail out.
                    lookup_type = parts.pop()
                    break
                # Unless we're at the end of the list of lookups, let's attempt
                # to continue traversing relations.
                if (counter + 1) < num_parts:
                    try:
                        lookup_model = lookup_field.rel.to
                    except AttributeError:
                        # Not a related field. Bail out.
                        lookup_type = parts.pop()
                        break

        # By default, this is a WHERE clause. If an aggregate is referenced
        # in the value, the filter will be promoted to a HAVING
        having_clause = False

        # Interpret '__exact=None' as the sql 'is NULL'; otherwise, reject all
        # uses of None as a query value.
        if value is None:
            if lookup_type != 'exact':
                raise ValueError("Cannot use None as a query value")
            lookup_type = 'isnull'
            value = True
        elif callable(value):
            value = value()
        elif isinstance(value, ExpressionNode):
            # If value is a query expression, evaluate it
            value = SQLEvaluator(value, self, reuse=can_reuse)
            having_clause = value.contains_aggregate

        for alias, aggregate in self.aggregates.items():
            if alias in (parts[0], LOOKUP_SEP.join(parts)):
                entry = self.where_class()
                entry.add((aggregate, lookup_type, value), AND)
                if negate:
                    entry.negate()
                self.having.add(entry, connector)
                return

        opts = self.get_meta()
        alias = self.get_initial_alias()
        allow_many = trim or not negate

        try:
            field, target, opts, join_list, last, extra_filters = self.setup_joins(
                    parts, opts, alias, True, allow_many, allow_explicit_fk=True,
                    can_reuse=can_reuse, negate=negate,
                    process_extras=process_extras)
        except MultiJoin as e:
            self.split_exclude(filter_expr, LOOKUP_SEP.join(parts[:e.level]),
                    can_reuse)
            return

        table_promote = False
        join_promote = False

        if (lookup_type == 'isnull' and value is True and not negate and
                len(join_list) > 1):
            # If the comparison is against NULL, we may need to use some left
            # outer joins when creating the join chain. This is only done when
            # needed, as it's less efficient at the database level.
            self.promote_joins(join_list)
            join_promote = True

        # Process the join list to see if we can remove any inner joins from
        # the far end (fewer tables in a query is better).
        nonnull_comparison = (lookup_type == 'isnull' and value is False)
        col, alias, join_list = self.trim_joins(target, join_list, last, trim,
                nonnull_comparison)

        if connector == OR:
            # Some joins may need to be promoted when adding a new filter to a
            # disjunction. We walk the list of new joins and where it diverges
            # from any previous joins (ref count is 1 in the table list), we
            # make the new additions (and any existing ones not used in the new
            # join list) an outer join.
            join_it = iter(join_list)
            table_it = iter(self.tables)
            next(join_it), next(table_it)
            unconditional = False
            for join in join_it:
                table = next(table_it)
                # Once we hit an outer join, all subsequent joins must
                # also be promoted, regardless of whether they have been
                # promoted as a result of this pass through the tables.
                unconditional = (unconditional or
                    self.alias_map[join].join_type == self.LOUTER)
                if join == table and self.alias_refcount[join] > 1:
                    # We have more than one reference to this join table.
                    # This means that we are dealing with two different query
                    # subtrees, so we don't need to do any join promotion.
                    continue
                join_promote = join_promote or self.promote_joins([join], unconditional)
                if table != join:
                    table_promote = self.promote_joins([table])
                # We only get here if we have found a table that exists
                # in the join list, but isn't on the original tables list.
                # This means we've reached the point where we only have
                # new tables, so we can break out of this promotion loop.
                break
            self.promote_joins(join_it, join_promote)
            self.promote_joins(table_it, table_promote or join_promote)

        if having_clause or force_having:
            if (alias, col) not in self.group_by:
                self.group_by.append((alias, col))
            self.having.add((Constraint(alias, col, field), lookup_type, value),
                connector)
        else:
            self.where.add((Constraint(alias, col, field), lookup_type, value),
                connector)

        if negate:
            self.promote_joins(join_list)
            if lookup_type != 'isnull':
                if len(join_list) > 1:
                    for j_alias in join_list:
                        if self.alias_map[j_alias].join_type == self.LOUTER:
                            j_col = self.alias_map[j_alias].rhs_join_col
                            # The join promotion logic should never produce
                            # a LOUTER join for the base join - assert that.
                            assert j_col is not None
                            entry = self.where_class()
                            entry.add(
                                (Constraint(j_alias, j_col, None), 'isnull', True),
                                AND
                            )
                            entry.negate()
                            self.where.add(entry, AND)
                            break
                if self.is_nullable(field):
                    # In SQL NULL = anyvalue returns unknown, and NOT unknown
                    # is still unknown. However, in Python None = anyvalue is False
                    # (and not False is True...), and we want to return this Python's
                    # view of None handling. So we need to specifically exclude the
                    # NULL values, and because we are inside NOT branch they will
                    # be included in the final resultset. We are essentially creating
                    # SQL like this here: NOT (col IS NOT NULL), where the first NOT
                    # is added in upper layers of the code.
                    self.where.add((Constraint(alias, col, None), 'isnull', False), AND)

        if can_reuse is not None:
            can_reuse.update(join_list)
        if process_extras:
            for filter in extra_filters:
                self.add_filter(filter, negate=negate, can_reuse=can_reuse,
                        process_extras=False)
dataset/ETHPy150Open AppScale/appscale/AppServer/lib/django-1.5/django/db/models/sql/query.py/Query.add_filter/original