diff --git a/django/contrib/sites/management.py b/django/contrib/sites/management.py
index 5cecfb4..6831cab 100644
--- a/django/contrib/sites/management.py
+++ b/django/contrib/sites/management.py
@@ -13,6 +13,5 @@ def create_default_site(app, created_models, verbosity):
             print "Creating example.com Site object"
         s = Site(domain="example.com", name="example.com")
         s.save()
-    Site.objects.clear_cache()
 
 dispatcher.connect(create_default_site, sender=site_app, signal=signals.post_syncdb)
diff --git a/django/contrib/sites/models.py b/django/contrib/sites/models.py
index c928a4e..fb6d0a2 100644
--- a/django/contrib/sites/models.py
+++ b/django/contrib/sites/models.py
@@ -44,15 +44,6 @@ class Site(models.Model):
     def __unicode__(self):
         return self.domain
 
-    def delete(self):
-        pk = self.pk
-        super(Site, self).delete()
-        try:
-            del(SITE_CACHE[pk])
-        except KeyError:
-            pass
-        
-
 class RequestSite(object):
     """
     A class that shares the primary interface of Site (i.e., it has
diff --git a/django/contrib/sites/tests.py b/django/contrib/sites/tests.py
deleted file mode 100644
index d2ec331..0000000
--- a/django/contrib/sites/tests.py
+++ /dev/null
@@ -1,13 +0,0 @@
-"""
->>> # Make sure that get_current() does not return a deleted Site object.
->>> from django.contrib.sites.models import Site
->>> s = Site.objects.get_current()
->>> s
-<Site: example.com>
-
->>> s.delete()
->>> Site.objects.get_current()
-Traceback (most recent call last):
-...
-DoesNotExist: Site matching query does not exist.
-"""
diff --git a/django/db/models/__init__.py b/django/db/models/__init__.py
index 86763d9..f5ab8eb 100644
--- a/django/db/models/__init__.py
+++ b/django/db/models/__init__.py
@@ -4,6 +4,7 @@ from django.core import validators
 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, AdminOptions
 from django.db.models.fields import *
diff --git a/django/db/models/base.py b/django/db/models/base.py
index 14a4804..3b6a5fe 100644
--- a/django/db/models/base.py
+++ b/django/db/models/base.py
@@ -10,7 +10,7 @@ from django.core import validators
 from django.core.exceptions import ObjectDoesNotExist, MultipleObjectsReturned, FieldError
 from django.db.models.fields import AutoField, ImageField, FieldDoesNotExist
 from django.db.models.fields.related import OneToOneRel, ManyToOneRel, OneToOneField
-from django.db.models.query import delete_objects, Q, CollectedObjects
+from django.db.models.query import delete_objects, Q
 from django.db.models.options import Options, AdminOptions
 from django.db import connection, transaction
 from django.db.models import signals
@@ -368,16 +368,17 @@ class Model(object):
                 error_dict[f.name] = errors
         return error_dict
 
-    def _collect_sub_objects(self, seen_objs, parent=None, nullable=False):
+    def _collect_sub_objects(self, seen_objs):
         """
         Recursively populates seen_objs with all objects related to this object.
-        When done, seen_objs.items() will be in the format:
-            [(model_class, {pk_val: obj, pk_val: obj, ...}),
-             (model_class, {pk_val: obj, pk_val: obj, ...}),...]
+        When done, seen_objs will be in the format:
+            {model_class: {pk_val: obj, pk_val: obj, ...},
+             model_class: {pk_val: obj, pk_val: obj, ...}, ...}
         """
         pk_val = self._get_pk_val()
-        if seen_objs.add(self.__class__, pk_val, self, parent, nullable):
+        if pk_val in seen_objs.setdefault(self.__class__, {}):
             return
+        seen_objs[self.__class__][pk_val] = self
 
         for related in self._meta.get_all_related_objects():
             rel_opts_name = related.get_accessor_name()
@@ -387,16 +388,16 @@ class Model(object):
                 except ObjectDoesNotExist:
                     pass
                 else:
-                    sub_obj._collect_sub_objects(seen_objs, self.__class__, related.field.null)
+                    sub_obj._collect_sub_objects(seen_objs)
             else:
                 for sub_obj in getattr(self, rel_opts_name).all():
-                    sub_obj._collect_sub_objects(seen_objs, self.__class__, related.field.null)
+                    sub_obj._collect_sub_objects(seen_objs)
 
     def delete(self):
         assert self._get_pk_val() is not None, "%s object can't be deleted because its %s attribute is set to None." % (self._meta.object_name, self._meta.pk.attname)
 
         # Find all the objects than need to be deleted
-        seen_objs = CollectedObjects()
+        seen_objs = SortedDict()
         self._collect_sub_objects(seen_objs)
 
         # Actually delete the objects
diff --git a/django/db/models/loading.py b/django/db/models/loading.py
index 6837e07..e62188a 100644
--- a/django/db/models/loading.py
+++ b/django/db/models/loading.py
@@ -2,8 +2,6 @@
 
 from django.conf import settings
 from django.core.exceptions import ImproperlyConfigured
-from django.utils.datastructures import SortedDict
-
 import sys
 import os
 import threading
@@ -20,10 +18,10 @@ class AppCache(object):
     # http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/66531.
     __shared_state = dict(
         # Keys of app_store are the model modules for each application.
-        app_store = SortedDict(),
+        app_store = {},
 
         # Mapping of app_labels to a dictionary of model names to model code.
-        app_models = SortedDict(),
+        app_models = {},
 
         # Mapping of app_labels to errors raised when trying to import the app.
         app_errors = {},
@@ -135,7 +133,7 @@ class AppCache(object):
         """
         self._populate()
         if app_mod:
-            return self.app_models.get(app_mod.__name__.split('.')[-2], SortedDict()).values()
+            return self.app_models.get(app_mod.__name__.split('.')[-2], {}).values()
         else:
             model_list = []
             for app_entry in self.app_models.itervalues():
@@ -151,7 +149,7 @@ class AppCache(object):
         """
         if seed_cache:
             self._populate()
-        return self.app_models.get(app_label, SortedDict()).get(model_name.lower())
+        return self.app_models.get(app_label, {}).get(model_name.lower())
 
     def register_models(self, app_label, *models):
         """
@@ -161,7 +159,7 @@ class AppCache(object):
             # Store as 'name: model' pair in a dictionary
             # in the app_models dictionary
             model_name = model._meta.object_name.lower()
-            model_dict = self.app_models.setdefault(app_label, SortedDict())
+            model_dict = self.app_models.setdefault(app_label, {})
             if model_name in model_dict:
                 # The same model may be imported via different paths (e.g.
                 # appname.models and project.appname.models). We use the source
diff --git a/django/db/models/query.py b/django/db/models/query.py
index 8714cff..fb6d116 100644
--- a/django/db/models/query.py
+++ b/django/db/models/query.py
@@ -16,92 +16,6 @@ ITER_CHUNK_SIZE = CHUNK_SIZE
 # Pull into this namespace for backwards compatibility
 EmptyResultSet = sql.EmptyResultSet
 
-class CyclicDependency(Exception):
-    pass
-
-class CollectedObjects(object):
-    """
-    A container that stores keys and lists of values along with
-    remembering the parent objects for all the keys.
-
-    This is used for the database object deletion routines so that we
-    can calculate the 'leaf' objects which should be deleted first.
-    """
-
-    def __init__(self):
-        self.data = {}
-        self.children = {}
-
-    def add(self, model, pk, obj, parent_model, nullable=False):
-        """
-        Adds an item.
-        model is the class of the object being added,
-        pk is the primary key, obj is the object itself, 
-        parent_model is the model of the parent object
-        that this object was reached through, nullable should
-        be True if this relation is nullable.
-
-        If the item already existed in the structure,
-        returns true, otherwise false.
-        """
-        d = self.data.setdefault(model, SortedDict())
-        retval = pk in d
-        d[pk] = obj
-        # Nullable relationships can be ignored -- they
-        # are nulled out before deleting, and therefore
-        # do not affect the order in which objects have
-        # to be deleted.
-        if parent_model is not None and not nullable:
-            self.children.setdefault(parent_model, []).append(model)
-
-        return retval
-
-    def __contains__(self, key):
-        return self.data.__contains__(key)
-
-    def __getitem__(self, key):
-        return self.data[key]
-
-    def __nonzero__(self):
-        return bool(self.data)
-
-    def iteritems(self):
-        for k in self.ordered_keys():
-            yield k, self[k]
-
-    def items(self):
-        return list(self.iteritems())
-
-    def keys(self):
-        return self.ordered_keys()
-
-    def ordered_keys(self):
-        """
-        Returns the models in the order that they should be 
-        dealth with i.e. models with no dependencies first.
-        """
-        dealt_with = SortedDict()
-        # Start with items that have no children
-        models = self.data.keys()
-        while len(dealt_with) < len(models):
-            found = False
-            for model in models:
-                children = self.children.setdefault(model, [])
-                if len([c for c in children if c not in dealt_with]) == 0:
-                    dealt_with[model] = None
-                    found = True
-            if not found:
-                raise CyclicDependency("There is a cyclic dependency of items to be processed.")
-            
-        return dealt_with.keys()
-
-    def unordered_keys(self):
-        """
-        Fallback for the case where is a cyclic dependency but we
-        don't care.
-        """
-        return self.data.keys()
-
 class QuerySet(object):
     "Represents a lazy database lookup for a set of objects"
     def __init__(self, model=None, query=None):
@@ -361,7 +275,7 @@ class QuerySet(object):
         while 1:
             # Collect all the objects to be deleted in this chunk, and all the
             # objects that are related to the objects that are to be deleted.
-            seen_objs = CollectedObjects()
+            seen_objs = SortedDict()
             for object in del_query[:CHUNK_SIZE]:
                 object._collect_sub_objects(seen_objs)
 
@@ -768,27 +682,19 @@ def delete_objects(seen_objs):
     Iterate through a list of seen classes, and remove any instances that are
     referred to.
     """
-    try:
-        ordered_classes = seen_objs.keys()
-    except CyclicDependency:
-        # if there is a cyclic dependency, we cannot in general delete
-        # the objects.  However, if an appropriate transaction is set
-        # up, or if the database is lax enough, it will succeed. 
-        # So for now, we go ahead and try anway.
-        ordered_classes = seen_objs.unordered_keys()
-
-    obj_pairs = {}
+    ordered_classes = seen_objs.keys()
+    ordered_classes.reverse()
+
     for cls in ordered_classes:
-        items = seen_objs[cls].items()
-        items.sort()
-        obj_pairs[cls] = items
+        seen_objs[cls] = seen_objs[cls].items()
+        seen_objs[cls].sort()
 
         # Pre notify all instances to be deleted
-        for pk_val, instance in items:
+        for pk_val, instance in seen_objs[cls]:
             dispatcher.send(signal=signals.pre_delete, sender=cls,
                     instance=instance)
 
-        pk_list = [pk for pk,instance in items]
+        pk_list = [pk for pk,instance in seen_objs[cls]]
         del_query = sql.DeleteQuery(cls, connection)
         del_query.delete_batch_related(pk_list)
 
@@ -799,17 +705,15 @@ def delete_objects(seen_objs):
 
     # Now delete the actual data
     for cls in ordered_classes:
-        items = obj_pairs[cls]
-        items.reverse()
-
-        pk_list = [pk for pk,instance in items]
+        seen_objs[cls].reverse()
+        pk_list = [pk for pk,instance in seen_objs[cls]]
         del_query = sql.DeleteQuery(cls, connection)
         del_query.delete_batch(pk_list)
 
         # Last cleanup; set NULLs where there once was a reference to the
         # object, NULL the primary key of the found objects, and perform
         # post-notification.
-        for pk_val, instance in items:
+        for pk_val, instance in seen_objs[cls]:
             for field in cls._meta.fields:
                 if field.rel and field.null and field.rel.to in seen_objs:
                     setattr(instance, field.attname, None)
diff --git a/django/db/models/sql/expressions.py b/django/db/models/sql/expressions.py
new file mode 100644
index 0000000..0a933f5
--- /dev/null
+++ b/django/db/models/sql/expressions.py
@@ -0,0 +1,158 @@
+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
+
+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([Literal(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(Literal(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, opts, field, 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 as_sql(self, opts, field, prep_func=None, qn=None, node=None):
+        if not qn:
+            qn = connection.ops.quote_name
+        if node is None:
+            node = self
+
+        result = []
+        result_params = []
+        for child in node.children:
+            if hasattr(child, 'as_sql'):
+                sql, params = child.as_sql(opts, field, prep_func, qn)
+                format = '%s'
+            else:
+                sql, params = self.as_sql(opts, field, prep_func, qn, child)
+                if len(child.children) > 1:
+                    format = '(%s)'
+                else:
+                    format = '%s'
+            if sql:
+                result.append(format % sql)
+                result_params.extend(params)
+        conn = ' %s ' % node.connector
+        return conn.join(result), result_params
+
+class Literal(Expression):
+    """
+    An expression representing the given value.
+    """
+    def __init__(self, value):
+        self.value = value
+
+    def as_sql(self, opts, field, prep_func=None, qn=None):
+        if self.value is None:
+            return 'NULL', ()
+
+        if isinstance(self.value, datetime):
+            sql = connection.ops.datetime_cast_sql()
+        else:
+            sql = '%s'
+        params = prep_func and prep_func(self.value) or (self.value,)
+
+        if isinstance(params, QueryWrapper):
+            return params.data
+        return sql, params
+
+class F(Expression):
+    """
+    An expression representing the value of the given field.
+    """
+    def __init__(self, name):
+        self.name = name
+
+    def as_sql(self, opts, field, prep_func=None, qn=None):
+        if not qn:
+            qn = connection.ops.quote_name
+
+        try:
+            src_field = opts.get_field(self.name)
+        except FieldDoesNotExist:
+            names = opts.get_all_field_names()
+            raise FieldError('Cannot resolve keyword %r into field. '
+                    'Choices are: %s' % (self.name, ', '.join(names)))
+
+        field_sql = connection.ops.field_cast_sql(src_field.db_type())
+        lhs = '%s.%s' % (qn(opts.db_table), qn(src_field.column))
+        return field_sql % lhs, ()
diff --git a/django/db/models/sql/query.py b/django/db/models/sql/query.py
index 3044882..567879b 100644
--- a/django/db/models/sql/query.py
+++ b/django/db/models/sql/query.py
@@ -250,7 +250,7 @@ class Query(object):
         # get_from_clause() for details.
         from_, f_params = self.get_from_clause()
 
-        where, w_params = self.where.as_sql(qn=self.quote_name_unless_alias)
+        where, w_params = self.where.as_sql(self.get_meta(), qn=self.quote_name_unless_alias)
         params = list(self.extra_select_params)
 
         result = ['SELECT']
diff --git a/django/db/models/sql/subqueries.py b/django/db/models/sql/subqueries.py
index 28436ab..b64639c 100644
--- a/django/db/models/sql/subqueries.py
+++ b/django/db/models/sql/subqueries.py
@@ -7,6 +7,7 @@ from django.db.models.sql.constants import *
 from django.db.models.sql.datastructures import Date
 from django.db.models.sql.query import Query
 from django.db.models.sql.where import AND
+from django.db.models.sql.expressions import Expression, Literal
 
 __all__ = ['DeleteQuery', 'UpdateQuery', 'InsertQuery', 'DateQuery',
         'CountQuery']
@@ -24,7 +25,7 @@ class DeleteQuery(Query):
         assert len(self.tables) == 1, \
                 "Can only delete from one table at a time."
         result = ['DELETE FROM %s' % self.quote_name_unless_alias(self.tables[0])]
-        where, params = self.where.as_sql()
+        where, params = self.where.as_sql(self.get_meta())
         result.append('WHERE %s' % where)
         return ' '.join(result), tuple(params)
 
@@ -126,14 +127,11 @@ class UpdateQuery(Query):
         result = ['UPDATE %s' % qn(table)]
         result.append('SET')
         values, update_params = [], []
-        for name, val, placeholder in self.values:
-            if val is not None:
-                values.append('%s = %s' % (qn(name), placeholder))
-                update_params.append(val)
-            else:
-                values.append('%s = NULL' % qn(name))
+        for name, sql, params in self.values:
+            values.append('%s = %s' % (qn(name), sql))
+            update_params.extend(params)
         result.append(', '.join(values))
-        where, params = self.where.as_sql()
+        where, params = self.where.as_sql(self.get_meta())
         if where:
             result.append('WHERE %s' % where)
         return ' '.join(result), tuple(update_params + params)
@@ -207,7 +205,7 @@ class UpdateQuery(Query):
             self.where.add((None, f.column, f, 'in',
                     pk_list[offset : offset + GET_ITERATOR_CHUNK_SIZE]),
                     AND)
-            self.values = [(related_field.column, None, '%s')]
+            self.values = [(related_field.column, 'NULL', ())]
             self.execute_sql(None)
 
     def add_update_values(self, values):
@@ -232,31 +230,32 @@ class UpdateQuery(Query):
         """
         from django.db.models.base import Model
         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):
-                val = val.pk
-
-            # Getting the placeholder for the field.
-            if hasattr(field, 'get_placeholder'):
-                placeholder = field.get_placeholder(val)
+            if isinstance(val, Expression):
+                expr = val
             else:
-                placeholder = '%s'
+                expr = Literal(val)
+
+            sql, params = expr.as_sql(
+                self.get_meta(),
+                field,
+                lambda x: field.get_db_prep_lookup('exact', field.get_db_prep_save(x)),
+                self.connection.ops.quote_name)
 
             if model:
-                self.add_related_update(model, field.column, val, placeholder)
+                self.add_related_update(model, field.column, sql, params)
             else:
-                self.values.append((field.column, val, placeholder))
+                self.values.append((field.column, sql, params))
 
-    def add_related_update(self, model, column, value, placeholder):
+    def add_related_update(self, model, column, sql, params):
         """
         Adds (name, value) to an update query for an ancestor model.
 
         Updates are coalesced so that we only run one update query per ancestor.
         """
         try:
-            self.related_updates[model].append((column, value, placeholder))
+            self.related_updates[model].append((column, sql, params))
         except KeyError:
-            self.related_updates[model] = [(column, value, placeholder)]
+            self.related_updates[model] = [(column, sql, params)]
 
     def get_related_updates(self):
         """
@@ -312,22 +311,15 @@ class InsertQuery(Query):
         parameters. This provides a way to insert NULL and DEFAULT keywords
         into the query, for example.
         """
-        placeholders, values = [], []
+        values = []
         for field, val in insert_values:
-            if hasattr(field, 'get_placeholder'):
-                # Some fields (e.g. geo fields) need special munging before
-                # they can be inserted.
-                placeholders.append(field.get_placeholder(val))
-            else:
-                placeholders.append('%s')
-
             self.columns.append(field.column)
             values.append(val)
         if raw_values:
             self.values.extend(values)
         else:
             self.params += tuple(values)
-            self.values.extend(placeholders)
+            self.values.extend(['%s'] * len(values))
 
 class DateQuery(Query):
     """
diff --git a/django/db/models/sql/where.py b/django/db/models/sql/where.py
index 14e5448..e98596b 100644
--- a/django/db/models/sql/where.py
+++ b/django/db/models/sql/where.py
@@ -4,9 +4,11 @@ Code to manage the creation and SQL rendering of 'where' constraints.
 import datetime
 
 from django.utils import tree
+from django.utils.functional import curry
 from django.db import connection
 from django.db.models.fields import Field
 from django.db.models.query_utils import QueryWrapper
+from django.db.models.sql.expressions import Expression, Literal
 from datastructures import EmptyResultSet, FullResultSet
 
 # Connection types
@@ -26,7 +28,7 @@ class WhereNode(tree.Node):
     """
     default = AND
 
-    def as_sql(self, node=None, qn=None):
+    def as_sql(self, opts, node=None, qn=None):
         """
         Returns the SQL version of the where clause and the value to be
         substituted in. Returns None, None if this node is empty.
@@ -47,10 +49,10 @@ class WhereNode(tree.Node):
         for child in node.children:
             try:
                 if hasattr(child, 'as_sql'):
-                    sql, params = child.as_sql(qn=qn)
+                    sql, params = child.as_sql(opts, qn=qn)
                     format = '(%s)'
                 elif isinstance(child, tree.Node):
-                    sql, params = self.as_sql(child, qn)
+                    sql, params = self.as_sql(opts, child, qn)
                     if child.negated:
                         format = 'NOT (%s)'
                     elif len(child.children) == 1:
@@ -58,7 +60,7 @@ class WhereNode(tree.Node):
                     else:
                         format = '(%s)'
                 else:
-                    sql, params = self.make_atom(child, qn)
+                    sql, params = self.make_atom(opts, child, qn)
                     format = '%s'
             except EmptyResultSet:
                 if node.connector == AND and not node.negated:
@@ -86,7 +88,7 @@ class WhereNode(tree.Node):
         conn = ' %s ' % node.connector
         return conn.join(result), result_params
 
-    def make_atom(self, child, qn):
+    def make_atom(self, opts, child, qn):
         """
         Turn a tuple (table_alias, field_name, field_class, lookup_type, value)
         into valid SQL.
@@ -99,36 +101,39 @@ class WhereNode(tree.Node):
             lhs = '%s.%s' % (qn(table_alias), qn(name))
         else:
             lhs = qn(name)
+        if not field:
+            field = Field()
         db_type = field and field.db_type() or None
         field_sql = connection.ops.field_cast_sql(db_type) % lhs
+        prep_func = curry(field.get_db_prep_lookup, lookup_type)
 
-        if isinstance(value, datetime.datetime):
-            cast_sql = connection.ops.datetime_cast_sql()
-        else:
-            cast_sql = '%s'
+        if lookup_type in connection.operators:
+            if isinstance(value, Expression):
+                sql, params = value.as_sql(opts, field, prep_func, qn)
+            else:
+                sql, params = Literal(value).as_sql(opts, field, prep_func, qn)
 
-        if field:
-            params = field.get_db_prep_lookup(lookup_type, value)
-        else:
-            params = Field().get_db_prep_lookup(lookup_type, value)
+            format = '%s %s' % (
+                connection.ops.lookup_cast(lookup_type),
+                connection.operators[lookup_type])
+            return format % (field_sql, sql), params
+
+        if isinstance(value, Expression):
+            raise TypeError('Invalid lookup_type for use with %s object: %r' % (
+                value.__class__.__name__, lookup_type))
+
+        params = prep_func(value)
         if isinstance(params, QueryWrapper):
             extra, params = params.data
         else:
             extra = ''
 
-        if lookup_type in connection.operators:
-            format = "%s %%s %s" % (connection.ops.lookup_cast(lookup_type),
-                    extra)
-            return (format % (field_sql,
-                    connection.operators[lookup_type] % cast_sql), params)
-
         if lookup_type == 'in':
             if not value:
                 raise EmptyResultSet
             if extra:
                 return ('%s IN %s' % (field_sql, extra), params)
-            return ('%s IN (%s)' % (field_sql, ', '.join(['%s'] * len(value))),
-                    params)
+            return ('%s IN (%s)' % (field_sql, ', '.join(['%s'] * len(value))), params)
         elif lookup_type in ('range', 'year'):
             return ('%s BETWEEN %%s and %%s' % field_sql, params)
         elif lookup_type in ('month', 'day'):
@@ -164,7 +169,7 @@ class EverythingNode(object):
     """
     A node that matches everything.
     """
-    def as_sql(self, qn=None):
+    def as_sql(self, opts, qn=None):
         raise FullResultSet
 
     def relabel_aliases(self, change_map, node=None):
diff --git a/tests/modeltests/delete/__init__.py b/tests/modeltests/delete/__init__.py
deleted file mode 100644
index 8b13789..0000000
--- a/tests/modeltests/delete/__init__.py
+++ /dev/null
@@ -1 +0,0 @@
-
diff --git a/tests/modeltests/delete/models.py b/tests/modeltests/delete/models.py
deleted file mode 100644
index f5b423e..0000000
--- a/tests/modeltests/delete/models.py
+++ /dev/null
@@ -1,179 +0,0 @@
-# coding: utf-8
-"""
-Tests for some corner cases with deleting.
-"""
-
-from django.db import models
-
-class DefaultRepr(object):
-    def __repr__(self):
-        return u"<%s: %s>" % (self.__class__.__name__, self.__dict__)
-
-class A(DefaultRepr, models.Model):
-    pass
-
-class B(DefaultRepr, models.Model):
-    a = models.ForeignKey(A)
-
-class C(DefaultRepr, models.Model):
-    b = models.ForeignKey(B)
-
-class D(DefaultRepr, models.Model):
-    c = models.ForeignKey(C)
-    a = models.ForeignKey(A)
-
-# Simplified, we have:
-# A
-# B -> A
-# C -> B
-# D -> C
-# D -> A
-
-# So, we must delete Ds first of all, then Cs then Bs then As.
-# However, if we start at As, we might find Bs first (in which 
-# case things will be nice), or find Ds first.
-
-# Some mutually dependent models, but nullable
-class E(DefaultRepr, models.Model):
-    f = models.ForeignKey('F', null=True, related_name='e_rel')
-
-class F(DefaultRepr, models.Model):
-    e = models.ForeignKey(E, related_name='f_rel')
-
-
-__test__ = {'API_TESTS': """
-# First, some tests for the datastructure we use
-
->>> from django.db.models.query import CollectedObjects
-
->>> g = CollectedObjects()
->>> g.add("key1", 1, "item1", None)
-False
->>> g["key1"]
-{1: 'item1'}
->>> g.add("key2", 1, "item1", "key1")
-False
->>> g.add("key2", 2, "item2", "key1")
-False
->>> g["key2"]
-{1: 'item1', 2: 'item2'}
->>> g.add("key3", 1, "item1", "key1")
-False
->>> g.add("key3", 1, "item1", "key2")
-True
->>> g.ordered_keys()
-['key3', 'key2', 'key1']
-
->>> g.add("key2", 1, "item1", "key3")
-True
->>> g.ordered_keys()
-Traceback (most recent call last):
-    ...
-CyclicDependency: There is a cyclic dependency of items to be processed.
-
-
-
-# Due to the way that transactions work in the test harness,
-# doing m.delete() here can work but fail in a real situation,
-# since it may delete all objects, but not in the right order.
-# So we manually check that the order of deletion is correct.
-
-# Also, it is possible that the order is correct 'accidentally', due
-# solely to order of imports etc.  To check this, we set the order
-# that 'get_models()' will retrieve to a known 'nice' order, and
-# then try again with a known 'tricky' order.  Slightly naughty
-# access to internals here :-)
-
->>> from django.db.models.loading import cache
-
-# Nice order
->>> cache.app_models['delete'].keyOrder = ['a', 'b', 'c', 'd']
->>> del A._meta._related_objects_cache
->>> del B._meta._related_objects_cache
->>> del C._meta._related_objects_cache
->>> del D._meta._related_objects_cache
-
->>> a1 = A()
->>> a1.save()
->>> b1 = B(a=a1)
->>> b1.save()
->>> c1 = C(b=b1)
->>> c1.save()
->>> d1 = D(c=c1, a=a1)
->>> d1.save()
-
->>> o = CollectedObjects()
->>> a1._collect_sub_objects(o)
->>> o.keys()
-[<class 'modeltests.delete.models.D'>, <class 'modeltests.delete.models.C'>, <class 'modeltests.delete.models.B'>, <class 'modeltests.delete.models.A'>]
->>> a1.delete()
-
-# Same again with a known bad order
->>> cache.app_models['delete'].keyOrder = ['d', 'c', 'b', 'a']
->>> del A._meta._related_objects_cache
->>> del B._meta._related_objects_cache
->>> del C._meta._related_objects_cache
->>> del D._meta._related_objects_cache
-
->>> a2 = A()
->>> a2.save()
->>> b2 = B(a=a2)
->>> b2.save()
->>> c2 = C(b=b2)
->>> c2.save()
->>> d2 = D(c=c2, a=a2)
->>> d2.save()
-
->>> o = CollectedObjects()
->>> a2._collect_sub_objects(o)
->>> o.keys()
-[<class 'modeltests.delete.models.D'>, <class 'modeltests.delete.models.C'>, <class 'modeltests.delete.models.B'>, <class 'modeltests.delete.models.A'>]
->>> a2.delete()
-
-# Tests for nullable related fields
-
->>> g = CollectedObjects()
->>> g.add("key1", 1, "item1", None)
-False
->>> g.add("key2", 1, "item1", "key1", nullable=True)
-False
->>> g.add("key1", 1, "item1", "key2")
-True
->>> g.ordered_keys()
-['key1', 'key2']
-
->>> e1 = E()
->>> e1.save()
->>> f1 = F(e=e1)
->>> f1.save()
->>> e1.f = f1
->>> e1.save()
-
-# Since E.f is nullable, we should delete F first (after nulling out
-# the E.f field), then E.
-
->>> o = CollectedObjects()
->>> e1._collect_sub_objects(o)
->>> o.keys()
-[<class 'modeltests.delete.models.F'>, <class 'modeltests.delete.models.E'>]
-
->>> e1.delete()
-
->>> e2 = E()
->>> e2.save()
->>> f2 = F(e=e2)
->>> f2.save()
->>> e2.f = f2
->>> e2.save()
-
-# Same deal as before, though we are starting from the other object.
-
->>> o = CollectedObjects()
->>> f2._collect_sub_objects(o)
->>> o.keys()
-[<class 'modeltests.delete.models.F'>, <class 'modeltests.delete.models.E'>]
-
->>> f2.delete()
-
-"""
-}
diff --git a/tests/modeltests/expressions/models.py b/tests/modeltests/expressions/models.py
new file mode 100644
index 0000000..bb92ee8
--- /dev/null
+++ b/tests/modeltests/expressions/models.py
@@ -0,0 +1,113 @@
+"""
+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'))
+>>> 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)
+>>> 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)
+>>> 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)
+<Number: 57, 57.000>
+<Number: 27, 27.000>
+<Number: 630, 630.000>
+<Number: 3, 2.800>
+<Number: 12, 12.000>
+<Number: 10, 10.000>
+<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'))
+>>> [c.point_of_contact for c in Company.objects.all()]
+[<Employee: Joe Smith>, <Employee: Frank Meyer>, <Employee: Max Mustermann>]
+
+"""}
diff --git a/tests/modeltests/update/models.py b/tests/modeltests/update/models.py
index 8a35b61..1df1811 100644
--- a/tests/modeltests/update/models.py
+++ b/tests/modeltests/update/models.py
@@ -4,71 +4,83 @@ updates.
 """
 
 from django.db import models
+from django.conf import settings
 
-class DataPoint(models.Model):
+class Product(models.Model):
     name = models.CharField(max_length=20)
-    value = models.CharField(max_length=20)
-    another_value = models.CharField(max_length=20, blank=True)
+    description = models.CharField(max_length=20)
+    expires = models.DateTimeField(null=True)
 
     def __unicode__(self):
         return unicode(self.name)
 
-class RelatedPoint(models.Model):
+class RelatedProduct(models.Model):
     name = models.CharField(max_length=20)
-    data = models.ForeignKey(DataPoint)
+    data = models.ForeignKey(Product)
 
     def __unicode__(self):
         return unicode(self.name)
 
 
 __test__ = {'API_TESTS': """
->>> DataPoint(name="d0", value="apple").save()
->>> DataPoint(name="d2", value="banana").save()
->>> d3 = DataPoint(name="d3", value="banana")
->>> d3.save()
->>> RelatedPoint(name="r1", data=d3).save()
+>>> from datetime import datetime
+
+>>> Product(name="p0", description="apple").save()
+>>> Product(name="p2", description="banana").save()
+>>> p3 = Product(name="p3", description="banana")
+>>> p3.save()
+>>> RelatedProduct(name="r1", data=p3).save()
 
 Objects are updated by first filtering the candidates into a queryset and then
 calling the update() method. It executes immediately and returns nothing.
 
->>> DataPoint.objects.filter(value="apple").update(name="d1")
->>> DataPoint.objects.filter(value="apple")
-[<DataPoint: d1>]
+>>> Product.objects.filter(description="apple").update(name="p1")
+>>> Product.objects.filter(description="apple")
+[<Product: p1>]
 
 We can update multiple objects at once.
 
->>> DataPoint.objects.filter(value="banana").update(value="pineapple")
->>> DataPoint.objects.get(name="d2").value
+>>> Product.objects.filter(description="banana").update(description="pineapple")
+>>> Product.objects.get(name="p2").description
 u'pineapple'
 
 Foreign key fields can also be updated, although you can only update the object
 referred to, not anything inside the related object.
 
->>> d = DataPoint.objects.get(name="d1")
->>> RelatedPoint.objects.filter(name="r1").update(data=d)
->>> RelatedPoint.objects.filter(data__name="d1")
-[<RelatedPoint: r1>]
+>>> p = Product.objects.get(name="p1")
+>>> RelatedProduct.objects.filter(name="r1").update(data=p)
+>>> RelatedProduct.objects.filter(data__name="p1")
+[<RelatedProduct: r1>]
+
+Multiple fields can be updated at once. If DATABASE_ENGINE is mysql microseconds
+must be truncated.
+
+>>> Product.objects.filter(description="pineapple").update(
+...     description="fruit",
+...     expires=datetime(2010, 1, 1, 12, 0, 0, 123456))
+>>> p = Product.objects.get(name="p2")
+>>> p.description, p.expires
+"""}
 
-Multiple fields can be updated at once
+if settings.DATABASE_ENGINE == 'mysql':
+    __test__['API_TESTS'] += "(u'fruit', datetime.datetime(2010, 1, 1, 12, 0))"
+else:
+    __test__['API_TESTS'] += "(u'fruit', datetime.datetime(2010, 1, 1, 12, 0, 0, 123456))"
 
->>> DataPoint.objects.filter(value="pineapple").update(value="fruit", another_value="peaches")
->>> d = DataPoint.objects.get(name="d2")
->>> d.value, d.another_value
-(u'fruit', u'peaches')
+__test__['API_TESTS'] += """
 
 In the rare case you want to update every instance of a model, update() is also
-a manager method.
+a manager method and update with None works as well.
 
->>> DataPoint.objects.update(value='thing')
->>> DataPoint.objects.values('value').distinct()
-[{'value': u'thing'}]
+>>> Product.objects.update(expires=None)
+>>> Product.objects.values('expires').distinct()
+[{'expires': None}]
 
 We do not support update on already sliced query sets.
 
->>> DataPoint.objects.all()[:2].update(another_value='another thing')
+>>> Product.objects.all()[:2].update(another_value='another thing')
 Traceback (most recent call last):
     ...
 AssertionError: Cannot update a query once a slice has been taken.
 
 """
-}
