Index: django/db/models/sql/where.py
===================================================================
--- django/db/models/sql/where.py	(revision 8450)
+++ django/db/models/sql/where.py	(working copy)
@@ -26,7 +26,7 @@
     relabel_aliases() methods.
     """
     default = AND
-
+    
     def add(self, data, connector):
         """
         Add a node to the where-tree. If the data is a list or tuple, it is
@@ -43,6 +43,23 @@
             return
 
         alias, col, field, lookup_type, value = data
+
+        #If the object defined its own value trust it's sql fragment to allow
+        #not inclusion of columns and avoid quoting
+        #import pdb; pdb.set_trace()
+        if hasattr(value, 'make_value'):
+            self.fragment, params = value.as_sql()
+            db_type = None
+        elif field:
+            params = field.get_db_prep_lookup(lookup_type, value)
+            db_type = field.db_type()
+        else:
+            # This is possible when we add a comparison to NULL sometimes (we
+            # don't really need to waste time looking up the associated field
+            # object).
+            params = Field().get_db_prep_lookup(lookup_type, value)
+            db_type = None
+
         try:
             if field:
                 params = field.get_db_prep_lookup(lookup_type, value)
@@ -59,14 +76,16 @@
             # match.
             super(WhereNode, self).add(NothingNode(), connector)
             return
+
         if isinstance(value, datetime.datetime):
             annotation = datetime.datetime
         else:
             annotation = bool(value)
+
         super(WhereNode, self).add((alias, col, db_type, lookup_type,
                 annotation, params), connector)
 
-    def as_sql(self, qn=None):
+    def as_sql(self, qn=None, trust_content=False):
         """
         Returns the SQL version of the where clause and the value to be
         substituted in. Returns None, None if this node is empty.
@@ -83,12 +102,21 @@
         result_params = []
         empty = True
         for child in self.children:
+            #import pdb; pdb.set_trace()
             try:
                 if hasattr(child, 'as_sql'):
-                    sql, params = child.as_sql(qn=qn)
+                    try:
+                        sql, params = child.as_sql(qn=qn,
+                                                   trust_content=hasattr(self, 'fragment')
+                                                   or trust_content)
+                    except:
+                        sql, params = child.as_sql(qn=qn)
                 else:
                     # A leaf node in the tree.
-                    sql, params = self.make_atom(child, qn)
+                    sql, params = self.make_atom(child, qn,
+                                                 trust_content=hasattr(self, 'fragment')
+                                                 or trust_content)
+
             except EmptyResultSet:
                 if self.connector == AND and not self.negated:
                     # We can bail out early in this particular case (only).
@@ -106,6 +134,9 @@
                 if self.negated:
                     empty = True
                 continue
+            if hasattr(self, 'fragment') and '%s' in sql:
+                sql = sql % self.fragment
+                
             empty = False
             if sql:
                 result.append(sql)
@@ -122,7 +153,7 @@
                 sql_string = '(%s)' % sql_string
         return sql_string, result_params
 
-    def make_atom(self, child, qn):
+    def make_atom(self, child, qn, trust_content=False):
         """
         Turn a tuple (table_alias, column_name, db_type, lookup_type,
         value_annot, params) into valid SQL.
@@ -141,13 +172,17 @@
             cast_sql = connection.ops.datetime_cast_sql()
         else:
             cast_sql = '%s'
-
+            
         if isinstance(params, QueryWrapper):
             extra, params = params.data
         else:
             extra = ''
 
+        if trust_content:
+            extra = ''
+
         if lookup_type in connection.operators:
+            #REm0ove %s
             format = "%s %%s %s" % (connection.ops.lookup_cast(lookup_type),
                     extra)
             return (format % (field_sql,
@@ -175,6 +210,7 @@
 
         raise TypeError('Invalid lookup_type: %r' % lookup_type)
 
+
     def relabel_aliases(self, change_map, node=None):
         """
         Relabels the alias values of any children. 'change_map' is a dictionary
Index: django/db/models/sql/expressions.py
===================================================================
--- django/db/models/sql/expressions.py	(revision 0)
+++ django/db/models/sql/expressions.py	(revision 0)
@@ -0,0 +1,152 @@
+from copy import deepcopy
+from datetime import datetime
+
+from django.utils import tree
+from django.core.exceptions import FieldError
+from django.db import connection
+from django.db.models.fields import Field, FieldDoesNotExist
+from django.db.models.query_utils import QueryWrapper
+from constants import LOOKUP_SEP
+
+class Expression(object):
+    """
+    Base class for all sql expressions, expected by QuerySet.update.
+    """
+    # Arithmetic connection types
+    ADD = '+'
+    SUB = '-'
+    MUL = '*'
+    DIV = '/'
+    MOD = '%%'
+
+    # Bitwise connection types
+    AND = '&'
+    OR = '|'
+
+    def _combine(self, other, conn, reversed, node=None):
+        if reversed:
+            obj = ExpressionNode([other], conn)
+            obj.add(node or self, conn)
+        else:
+            obj = node or ExpressionNode([self], conn)
+            if isinstance(other, Expression):
+                obj.add(other, conn)
+            else:
+                obj.add(other, conn)
+        return obj
+
+    def __add__(self, other):
+        return self._combine(other, self.ADD, False)
+
+    def __sub__(self, other):
+        return self._combine(other, self.SUB, False)
+
+    def __mul__(self, other):
+        return self._combine(other, self.MUL, False)
+
+    def __div__(self, other):
+        return self._combine(other, self.DIV, False)
+
+    def __mod__(self, other):
+        return self._combine(other, self.MOD, False)
+
+    def __and__(self, other):
+        return self._combine(other, self.AND, False)
+
+    def __or__(self, other):
+        return self._combine(other, self.OR, False)
+
+    def __radd__(self, other):
+        return self._combine(other, self.ADD, True)
+
+    def __rsub__(self, other):
+        return self._combine(other, self.SUB, True)
+
+    def __rmul__(self, other):
+        return self._combine(other, self.MUL, True)
+
+    def __rdiv__(self, other):
+        return self._combine(other, self.DIV, True)
+
+    def __rmod__(self, other):
+        return self._combine(other, self.MOD, True)
+
+    def __rand__(self, other):
+        return self._combine(other, self.AND, True)
+
+    def __ror__(self, other):
+        return self._combine(other, self.OR, True)
+
+    def as_sql(self, prep_func=None, qn=None):
+        raise NotImplementedError
+
+class ExpressionNode(Expression, tree.Node):
+    default = None
+
+    def __init__(self, children=None, connector=None, negated=False):
+        if children is not None and len(children) > 1 and connector is None:
+            raise TypeError('You have to specify a connector.')
+        super(ExpressionNode, self).__init__(children, connector, negated)
+
+    def _combine(self, *args, **kwargs):
+        return super(ExpressionNode, self)._combine(node=deepcopy(self), *args, **kwargs)
+
+    def make_value(self, data, qn=None):
+        opts, select = data
+
+        if not qn:
+            qn = connection.ops.quote_name
+
+        result = []
+        result_params = []
+        for child in self.children:
+            if hasattr(child, 'as_sql'):
+                child.make_value(data)
+                sql, params = child.as_sql(None, qn)
+            else:
+                try:
+                    sql, params = qn(child), []
+                except:
+                    sql, params = str(child), []
+                    
+            if hasattr(child, 'children') > 1:
+                format = '(%s)'
+            else:
+                format = '%s'
+
+
+            if sql:
+                result.append(format % sql)
+                result_params.extend(params)
+        conn = ' %s ' % self.connector
+        self.sql_value = conn.join(result)
+        self.result_params = result_params
+    
+    def as_sql(self, prep_func=None, qn=None):
+        return self.sql_value, tuple(self.result_params)
+
+class F(Expression):
+    """
+    An expression representing the value of the given field.
+    """
+    def __init__(self, name):
+        self.name = name
+        self.sql_value = ''
+
+    def make_value(self, data, qn=None):
+        opts, select = data
+
+        if not qn:
+            qn = connection.ops.quote_name
+
+        try:
+            column = opts.get_field(self.name).column
+            self.sql_value = '%s.%s' % (qn(opts.db_table), qn(column))
+        except FieldDoesNotExist:
+            raise FieldError("Cannot resolve keyword %r into field. "
+                             "Choices are: %s" % (self.name,
+                                                  [f.name for f in opts.fields]))
+            
+
+    def as_sql(self, prep_func=None, qn=None):
+        return self.sql_value, ()
Index: django/db/models/sql/query.py
===================================================================
--- django/db/models/sql/query.py	(revision 8450)
+++ django/db/models/sql/query.py	(working copy)
@@ -1039,7 +1039,7 @@
         opts = self.get_meta()
         alias = self.get_initial_alias()
         allow_many = trim or not negate
-
+        
         try:
             field, target, opts, join_list, last = self.setup_joins(parts, opts,
                     alias, True, allow_many, can_reuse=can_reuse)
@@ -1114,8 +1114,11 @@
                 if self.promote_alias(table, table_promote):
                     table_promote = True
 
+        #Manage special objects through their make_value attribute
+        if hasattr(value, 'make_value'):
+            value.make_value((opts, self.select))
         self.where.add((alias, col, field, lookup_type, value), connector)
-
+        
         if negate:
             for alias in join_list:
                 self.promote_alias(alias)
@@ -1137,7 +1140,7 @@
                     entry.add((alias, col, None, 'isnull', True), AND)
                     entry.negate()
                     self.where.add(entry, AND)
-
+                    
         if can_reuse is not None:
             can_reuse.update(join_list)
 
@@ -1625,6 +1628,7 @@
                 return
 
         cursor = self.connection.cursor()
+        #import pdb; pdb.set_trace()
         cursor.execute(sql, params)
 
         if not result_type:
Index: django/db/models/sql/subqueries.py
===================================================================
--- django/db/models/sql/subqueries.py	(revision 8450)
+++ django/db/models/sql/subqueries.py	(working copy)
@@ -137,7 +137,8 @@
         for name, val, placeholder in self.values:
             if val is not None:
                 values.append('%s = %s' % (qn(name), placeholder))
-                update_params.append(val)
+                if not hasattr(val, 'make_value'):
+                    update_params.append(val)
             else:
                 values.append('%s = NULL' % qn(name))
         result.append(', '.join(values))
@@ -239,6 +240,7 @@
         saving models.
         """
         from django.db.models.base import Model
+        #import pdb; pdb.set_trace()
         for field, model, val in values_seq:
             # FIXME: Some sort of db_prep_* is probably more appropriate here.
             if field.rel and isinstance(val, Model):
@@ -250,6 +252,11 @@
             else:
                 placeholder = '%s'
 
+            if hasattr(val, 'make_value'):
+                val.make_value((self.get_meta(),self.select))
+                fragment, _ = val.as_sql()
+                placeholder = placeholder % fragment
+                
             if model:
                 self.add_related_update(model, field.column, val, placeholder)
             else:
Index: django/db/models/__init__.py
===================================================================
--- django/db/models/__init__.py	(revision 8450)
+++ django/db/models/__init__.py	(working copy)
@@ -4,6 +4,7 @@
 from django.db import connection
 from django.db.models.loading import get_apps, get_app, get_models, get_model, register_models
 from django.db.models.query import Q
+from django.db.models.sql.expressions import F
 from django.db.models.manager import Manager
 from django.db.models.base import Model
 from django.db.models.fields import *
Index: django/db/models/query_utils.py
===================================================================
--- django/db/models/query_utils.py	(revision 8450)
+++ django/db/models/query_utils.py	(working copy)
@@ -6,7 +6,7 @@
 """
 
 from copy import deepcopy
-
+from django.db import connection
 from django.utils import tree
 
 class QueryWrapper(object):
Index: tests/modeltests/expressions/__init__.py
===================================================================
Index: tests/modeltests/expressions/models.py
===================================================================
--- tests/modeltests/expressions/models.py	(revision 0)
+++ tests/modeltests/expressions/models.py	(revision 0)
@@ -0,0 +1,125 @@
+"""
+Tests for the update() queryset method that allows in-place, multi-object
+updates.
+"""
+
+from django.db import models
+
+#
+# Model for testing arithmetic expressions.
+#
+
+class Number(models.Model):
+    integer = models.IntegerField()
+    float = models.FloatField(null=True)
+
+    def __unicode__(self):
+        return u'%i, %.3f' % (self.integer, self.float)
+
+#
+# A more ordinary use case.
+#
+
+class Employee(models.Model):
+    firstname = models.CharField(max_length=50)
+    lastname = models.CharField(max_length=50)
+
+    def __unicode__(self):
+        return u'%s %s' % (self.firstname, self.lastname)
+
+class Company(models.Model):
+    name = models.CharField(max_length=100)
+    num_employees = models.PositiveIntegerField()
+    num_chairs = models.PositiveIntegerField()
+    ceo = models.ForeignKey(
+        Employee,
+        related_name='company_ceo_set')
+    point_of_contact = models.ForeignKey(
+        Employee,
+        related_name='company_point_of_contact_set',
+        null=True)
+
+    def __unicode__(self):
+        return self.name
+
+
+__test__ = {'API_TESTS': """
+>>> from django.db.models import F
+
+>>> Number(integer=-1).save()
+>>> Number(integer=42).save()
+>>> Number(integer=1337).save()
+
+We can fill a value in all objects with an other value of the same object.
+
+>>> Number.objects.update(float=F('integer'))
+3
+>>> Number.objects.all()
+[<Number: -1, -1.000>, <Number: 42, 42.000>, <Number: 1337, 1337.000>]
+
+We can increment a value of all objects in a query set.
+
+>>> Number.objects.filter(integer__gt=0).update(integer=F('integer') + 1)
+2
+>>> Number.objects.all()
+[<Number: -1, -1.000>, <Number: 43, 42.000>, <Number: 1338, 1337.000>]
+
+We can filter for objects, where a value is not equals the value of an other field.
+
+>>> Number.objects.exclude(float=F('integer'))
+[<Number: 43, 42.000>, <Number: 1338, 1337.000>]
+
+Complex expressions of different connection types are possible.
+
+>>> n = Number.objects.create(integer=10, float=123.45)
+
+>>> Number.objects.filter(pk=n.pk).update(float=F('integer') + F('float') * 2)
+1
+>>> Number.objects.get(pk=n.pk)
+<Number: 10, 256.900>
+
+All supported operators, work as expected in native and reverse order.
+
+>>> from operator import add, sub, mul, div, mod, and_, or_
+>>> for op in (add, sub, mul, div, mod, and_, or_):
+...     n = Number.objects.create(integer=42, float=15.)
+...     Number.objects.filter(pk=n.pk).update(
+...         integer=op(F('integer'), 15), float=op(42., F('float')))
+...     Number.objects.get(pk=n.pk)
+1
+<Number: 57, 57.000>
+1
+<Number: 27, 27.000>
+1
+<Number: 630, 630.000>
+1
+<Number: 2, 2.800>
+1
+<Number: 12, 12.000>
+1
+<Number: 10, 10.000>
+1
+<Number: 47, 47.000>
+
+
+>>> Company(name='Example Inc.', num_employees=2300, num_chairs=5,
+...     ceo=Employee.objects.create(firstname='Joe', lastname='Smith')).save()
+>>> Company(name='Foobar Ltd.', num_employees=3, num_chairs=3,
+...     ceo=Employee.objects.create(firstname='Frank', lastname='Meyer')).save()
+>>> Company(name='Test GmbH', num_employees=32, num_chairs=1,
+...     ceo=Employee.objects.create(firstname='Max', lastname='Mustermann')).save()
+
+We can filter for companies where the number of employees is greater than the
+number of chairs.
+
+>>> Company.objects.filter(num_employees__gt=F('num_chairs'))
+[<Company: Example Inc.>, <Company: Test GmbH>]
+
+The relation of a foreign key can become copied over to an other foreign key.
+
+>>> Company.objects.update(point_of_contact=F('ceo'))
+3
+>>> [c.point_of_contact for c in Company.objects.all()]
+[<Employee: Joe Smith>, <Employee: Frank Meyer>, <Employee: Max Mustermann>]
+
+"""}
Index: docs/db-api.txt
===================================================================
--- docs/db-api.txt	(revision 8450)
+++ docs/db-api.txt	(working copy)
@@ -30,6 +30,8 @@
         headline = models.CharField(max_length=255)
         body_text = models.TextField()
         pub_date = models.DateTimeField()
+        num_comments = models.IntegerField()
+        comment_threshold = models.IntegerField()
         authors = models.ManyToManyField(Author)
 
         def __unicode__(self):
@@ -1744,6 +1746,46 @@
     Blog.objetcs.filter(entry__author__isnull=False,
             entry__author__name__isnull=True)
 
+Using other model attributes in your lookups with F objects
+-----------------------------------------------------------
+
+**New in Django development version**
+
+When filtering you can refer to you can refer to other attributes of
+your model by using F objects and expressions.  For example if you
+want to obtain the entries that have more comments than they were
+suposed to you could do::
+
+    Entry.objects.filter(num_comments__gt=F('comment_threshold'))
+
+You could also use aritmethic expressions so you could get those that
+have doubled the expected threshold::
+
+    Entry.objects.filter(num_comments__gt=2*F('comment_threshold'))
+
+The available operands for arithmetic expressions are::
+
+ * Addition using ``+``
+
+ * Substraction using ``-``
+
+ * Multiplication using ``*``
+
+ * Division using ``/``
+
+ * Modulo using ``%%``
+ 
+ * Bitwise AND using ``&``
+
+ * Bitwise OR using ``|``
+
+.. note:: 
+   F objects can only access one database table, the model's main
+   table. If you need to access more than this you can use extra or
+   `fall back to SQL`_.
+
+   .. _`fall back to SQL`: ../model-api/#falling-back-to--raw-sql
+
 Spanning multi-valued relationships
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
@@ -2283,11 +2325,11 @@
     # Change every Entry so that it belongs to this Blog.
     Entry.objects.all().update(blog=b)
 
-The ``update()`` method is applied instantly and doesn't return anything
-(similar to ``delete()``). The only restriction on the ``QuerySet`` that is
-updated is that it can only access one database table, the model's main
-table. So don't try to filter based on related fields or anything like that;
-it won't work.
+The ``update()`` method is applied instantly and returns the number of
+objects that were affected. The only restriction on the ``QuerySet``
+that is updated is that it can only access one database table, the
+model's main table. So don't try to filter based on related fields or
+anything like that; it won't work.
 
 Be aware that the ``update()`` method is converted directly to an SQL
 statement. It is a bulk operation for direct updates. It doesn't run any
@@ -2300,7 +2342,14 @@
     for item in my_queryset:
         item.save()
 
+When using ``update()`` you can also refer to other fields in the
+model by using F objects and expressions. Updating the comment
+threshold of all entries for it to be the same as the current number
+of comments could be done like this::
 
+    Entry.objects.all().update(comment_threshold=F('num_comments'))
+
+
 Extra instance methods
 ======================
 
