diff --git a/django/db/backends/mysql/base.py b/django/db/backends/mysql/base.py
index 830808b..b47e4e6 100644
--- a/django/db/backends/mysql/base.py
+++ b/django/db/backends/mysql/base.py
@@ -307,6 +307,7 @@ class DatabaseOperations(BaseDatabaseOperations):
 class DatabaseWrapper(BaseDatabaseWrapper):
     vendor = 'mysql'
     operators = {
+        'ne': '<> %s',
         'exact': '= %s',
         'iexact': 'LIKE %s',
         'contains': 'LIKE BINARY %s',
diff --git a/django/db/backends/oracle/base.py b/django/db/backends/oracle/base.py
index 105730c..1a712f6 100644
--- a/django/db/backends/oracle/base.py
+++ b/django/db/backends/oracle/base.py
@@ -407,6 +407,7 @@ class DatabaseWrapper(BaseDatabaseWrapper):
     operators = _UninitializedOperatorsDescriptor()
 
     _standard_operators = {
+        'ne': '<> %s',
         'exact': '= %s',
         'iexact': '= UPPER(%s)',
         'contains': "LIKE TRANSLATE(%s USING NCHAR_CS) ESCAPE TRANSLATE('\\' USING NCHAR_CS)",
diff --git a/django/db/backends/postgresql_psycopg2/base.py b/django/db/backends/postgresql_psycopg2/base.py
index a77eccf..0919611 100644
--- a/django/db/backends/postgresql_psycopg2/base.py
+++ b/django/db/backends/postgresql_psycopg2/base.py
@@ -97,6 +97,7 @@ class DatabaseFeatures(BaseDatabaseFeatures):
 class DatabaseWrapper(BaseDatabaseWrapper):
     vendor = 'postgresql'
     operators = {
+        'ne': '<> %s',
         'exact': '= %s',
         'iexact': '= UPPER(%s)',
         'contains': 'LIKE %s',
diff --git a/django/db/backends/sqlite3/base.py b/django/db/backends/sqlite3/base.py
index b5d38bb..e6ad1cd 100644
--- a/django/db/backends/sqlite3/base.py
+++ b/django/db/backends/sqlite3/base.py
@@ -204,6 +204,7 @@ class DatabaseWrapper(BaseDatabaseWrapper):
     # being escaped has a percent or underscore in it.
     # See http://www.sqlite.org/lang_expr.html for an explanation.
     operators = {
+        'ne': '<> %s',
         'exact': '= %s',
         'iexact': "LIKE %s ESCAPE '\\'",
         'contains': "LIKE %s ESCAPE '\\'",
diff --git a/django/db/models/fields/__init__.py b/django/db/models/fields/__init__.py
index 04b13aa..851b2ec 100644
--- a/django/db/models/fields/__init__.py
+++ b/django/db/models/fields/__init__.py
@@ -306,9 +306,9 @@ class Field(object):
                 'endswith', 'iendswith', 'isnull'
             ):
             return value
-        elif lookup_type in ('exact', 'gt', 'gte', 'lt', 'lte'):
+        elif lookup_type in ('exact', 'ne', 'gt', 'gte', 'lt', 'lte'):
             return self.get_prep_value(value)
-        elif lookup_type in ('range', 'in'):
+        elif lookup_type in ('range', 'in', 'notin'):
             return [self.get_prep_value(v) for v in value]
         elif lookup_type == 'year':
             try:
@@ -342,10 +342,10 @@ class Field(object):
         if lookup_type in ('regex', 'iregex', 'month', 'day', 'week_day',
                            'search'):
             return [value]
-        elif lookup_type in ('exact', 'gt', 'gte', 'lt', 'lte'):
+        elif lookup_type in ('exact', 'ne', 'gt', 'gte', 'lt', 'lte'):
             return [self.get_db_prep_value(value, connection=connection,
                                            prepared=prepared)]
-        elif lookup_type in ('range', 'in'):
+        elif lookup_type in ('range', 'in', 'notin'):
             return [self.get_db_prep_value(v, connection=connection,
                                            prepared=prepared) for v in value]
         elif lookup_type in ('contains', 'icontains'):
diff --git a/django/db/models/fields/related.py b/django/db/models/fields/related.py
index ad05c83..8fba124 100644
--- a/django/db/models/fields/related.py
+++ b/django/db/models/fields/related.py
@@ -133,9 +133,9 @@ class RelatedField(object):
         # get_(next/prev)_by_date work; other lookups are not allowed since that
         # gets messy pretty quick. This is a good candidate for some refactoring
         # in the future.
-        if lookup_type in ['exact', 'gt', 'lt', 'gte', 'lte']:
+        if lookup_type in ['exact', 'ne', 'gt', 'lt', 'gte', 'lte']:
             return self._pk_trace(value, 'get_prep_lookup', lookup_type)
-        if lookup_type in ('range', 'in'):
+        if lookup_type in ('range', 'in', 'notin'):
             return [self._pk_trace(v, 'get_prep_lookup', lookup_type) for v in value]
         elif lookup_type == 'isnull':
             return []
@@ -161,10 +161,10 @@ class RelatedField(object):
         # get_(next/prev)_by_date work; other lookups are not allowed since that
         # gets messy pretty quick. This is a good candidate for some refactoring
         # in the future.
-        if lookup_type in ['exact', 'gt', 'lt', 'gte', 'lte']:
+        if lookup_type in ['exact', 'ne', 'gt', 'lt', 'gte', 'lte']:
             return [self._pk_trace(value, 'get_db_prep_lookup', lookup_type,
                             connection=connection, prepared=prepared)]
-        if lookup_type in ('range', 'in'):
+        if lookup_type in ('range', 'in', 'notin'):
             return [self._pk_trace(v, 'get_db_prep_lookup', lookup_type,
                             connection=connection, prepared=prepared)
                     for v in value]
@@ -205,7 +205,7 @@ class RelatedField(object):
             else:
                 field = field.rel.to._meta.pk
 
-        if lookup_type in ('range', 'in'):
+        if lookup_type in ('range', 'in', 'notin'):
             v = [v]
         v = getattr(field, prep_func)(lookup_type, v, **kwargs)
         if isinstance(v, list):
diff --git a/django/db/models/sql/constants.py b/django/db/models/sql/constants.py
index 63c704f..0ba218c 100644
--- a/django/db/models/sql/constants.py
+++ b/django/db/models/sql/constants.py
@@ -2,8 +2,8 @@ import re
 
 # Valid query types (a dictionary is used for speedy lookups).
 QUERY_TERMS = dict([(x, None) for x in (
-    'exact', 'iexact', 'contains', 'icontains', 'gt', 'gte', 'lt', 'lte', 'in',
-    'startswith', 'istartswith', 'endswith', 'iendswith', 'range', 'year',
+    'exact', 'ne', 'iexact', 'contains', 'icontains', 'gt', 'gte', 'lt', 'lte', 'in',
+    'notin', 'startswith', 'istartswith', 'endswith', 'iendswith', 'range', 'year',
     'month', 'day', 'week_day', 'isnull', 'search', 'regex', 'iregex',
     )])
 
diff --git a/django/db/models/sql/query.py b/django/db/models/sql/query.py
index 4891855..f6fc472 100644
--- a/django/db/models/sql/query.py
+++ b/django/db/models/sql/query.py
@@ -1071,10 +1071,10 @@ class Query(object):
         # 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':
+            if lookup_type not in ('exact', 'ne'):
                 raise ValueError("Cannot use None as a query value")
+            value = lookup_type == 'exact'
             lookup_type = 'isnull'
-            value = True
         elif callable(value):
             value = value()
         elif isinstance(value, ExpressionNode):
@@ -1179,7 +1179,7 @@ class Query(object):
                             entry.negate()
                             self.where.add(entry, AND)
                             break
-                if not (lookup_type == 'in'
+                if not (lookup_type in ('in', 'notin')
                             and not hasattr(value, 'as_sql')
                             and not hasattr(value, '_as_sql')
                             and not value) and field.null:
@@ -1187,7 +1187,7 @@ class Query(object):
                     # exclude the "foo__in=[]" case from this handling, because
                     # it's short-circuited in the Where class.
                     # We also need to handle the case where a subquery is provided
-                    self.where.add((Constraint(alias, col, None), 'isnull', False), AND)
+                    self.where.add((Constraint(alias, col, None), 'isnull', lookup_type == 'notin'), AND)
 
         if can_reuse is not None:
             can_reuse.update(join_list)
diff --git a/django/db/models/sql/where.py b/django/db/models/sql/where.py
index 1455ba6..e1aa6c3 100644
--- a/django/db/models/sql/where.py
+++ b/django/db/models/sql/where.py
@@ -165,10 +165,10 @@ class WhereNode(tree.Node):
         else:
             extra = ''
 
-        if (len(params) == 1 and params[0] == '' and lookup_type == 'exact'
+        if (len(params) == 1 and params[0] == '' and lookup_type in ('exact', 'ne')
             and connection.features.interprets_empty_strings_as_nulls):
+            value_annot = lookup_type == 'exact'
             lookup_type = 'isnull'
-            value_annot = True
 
         if lookup_type in connection.operators:
             format = "%s %%s %%s" % (connection.ops.lookup_cast(lookup_type),)
@@ -176,11 +176,15 @@ class WhereNode(tree.Node):
                               connection.operators[lookup_type] % cast_sql,
                               extra), params)
 
-        if lookup_type == 'in':
+        if lookup_type in ('in', 'notin'):
             if not value_annot:
                 raise EmptyResultSet
+            if lookup_type == 'in':
+                op = 'IN'
+            else:
+                op = 'NOT IN'
             if extra:
-                return ('%s IN %s' % (field_sql, extra), params)
+                return ('%s %s %s' % (field_sql, op, extra), params)
             max_in_list_size = connection.ops.max_in_list_size()
             if max_in_list_size and len(params) > max_in_list_size:
                 # Break up the params list into an OR of manageable chunks.
@@ -188,7 +192,7 @@ class WhereNode(tree.Node):
                 for offset in xrange(0, len(params), max_in_list_size):
                     if offset > 0:
                         in_clause_elements.append(' OR ')
-                    in_clause_elements.append('%s IN (' % field_sql)
+                    in_clause_elements.append('%s %s (' % (field_sql, op))
                     group_size = min(len(params) - offset, max_in_list_size)
                     param_group = ', '.join(repeat('%s', group_size))
                     in_clause_elements.append(param_group)
@@ -196,7 +200,7 @@ class WhereNode(tree.Node):
                 in_clause_elements.append(')')
                 return ''.join(in_clause_elements), params
             else:
-                return ('%s IN (%s)' % (field_sql,
+                return ('%s %s (%s)' % (field_sql, op,
                                         ', '.join(repeat('%s', len(params)))),
                         params)
         elif lookup_type in ('range', 'year'):
