Index: django/db/models/sql/query.py
===================================================================
--- django/db/models/sql/query.py	(revision 7513)
+++ django/db/models/sql/query.py	(working copy)
@@ -67,6 +67,8 @@
         self.order_by = []
         self.low_mark, self.high_mark = 0, None  # Used for offset/limit
         self.distinct = False
+        self.select_for_update = False
+        self.select_for_update_nowait = False
         self.select_related = False
         self.related_select_cols = []
 
@@ -173,6 +175,8 @@
         obj.order_by = self.order_by[:]
         obj.low_mark, obj.high_mark = self.low_mark, self.high_mark
         obj.distinct = self.distinct
+        obj.select_for_update = self.select_for_update
+        obj.select_for_update_nowait = self.select_for_update_nowait
         obj.select_related = self.select_related
         obj.related_select_cols = []
         obj.max_depth = self.max_depth
@@ -211,6 +215,7 @@
         obj = self.clone()
         obj.clear_ordering(True)
         obj.clear_limits()
+        obj.select_for_update = False
         obj.select_related = False
         obj.related_select_cols = []
         obj.related_select_fields = []
@@ -290,6 +295,9 @@
                         result.append('LIMIT %d' % val)
                 result.append('OFFSET %d' % self.low_mark)
 
+        if self.select_for_update:
+            result.append("%s" % self.connection.ops.for_update_sql(nowait=self.select_for_update_nowait))
+
         params.extend(self.extra_params)
         return ' '.join(result), tuple(params)
 
Index: django/db/models/manager.py
===================================================================
--- django/db/models/manager.py	(revision 7513)
+++ django/db/models/manager.py	(working copy)
@@ -108,6 +108,9 @@
     def order_by(self, *args, **kwargs):
         return self.get_query_set().order_by(*args, **kwargs)
 
+    def select_for_update(self, *args, **kwargs):
+        return self.get_query_set().select_for_update(*args, **kwargs)
+        
     def select_related(self, *args, **kwargs):
         return self.get_query_set().select_related(*args, **kwargs)
 
Index: django/db/models/query.py
===================================================================
--- django/db/models/query.py	(revision 7513)
+++ django/db/models/query.py	(working copy)
@@ -267,6 +267,7 @@
         del_query = self._clone()
 
         # Disable non-supported fields.
+        del_query.query.select_for_update = False
         del_query.query.select_related = False
         del_query.query.clear_ordering()
 
@@ -402,6 +403,18 @@
         else:
             return self._filter_or_exclude(None, **filter_obj)
 
+    def select_for_update(self, **kwargs):
+        """
+        Returns a new QuerySet instance that will select objects with a
+        FOR UPDATE lock.
+        """
+        # Default to false for nowait
+        nowait = kwargs.pop('nowait', False)
+        obj = self._clone()
+        obj.query.select_for_update = True
+        obj.query.select_for_update_nowait = nowait
+        return obj
+
     def select_related(self, *fields, **kwargs):
         """
         Returns a new QuerySet instance that will select related objects. If
Index: django/db/backends/sqlite3/base.py
===================================================================
--- django/db/backends/sqlite3/base.py	(revision 7513)
+++ django/db/backends/sqlite3/base.py	(working copy)
@@ -52,6 +52,10 @@
         # function django_date_trunc that's registered in connect().
         return 'django_date_trunc("%s", %s)' % (lookup_type.lower(), field_name)
 
+    def for_update_sql(self):
+        # sqlite does not support FOR UPDATE
+        return ''
+
     def drop_foreignkey_sql(self):
         return ""
 
@@ -171,3 +175,4 @@
         return bool(re.search(re_pattern, re_string))
     except:
         return False
+
Index: django/db/backends/mysql/base.py
===================================================================
--- django/db/backends/mysql/base.py	(revision 7513)
+++ django/db/backends/mysql/base.py	(working copy)
@@ -89,6 +89,16 @@
     def fulltext_search_sql(self, field_name):
         return 'MATCH (%s) AGAINST (%%s IN BOOLEAN MODE)' % field_name
 
+    def for_update_sql(self, nowait=False):
+        """
+        Return FOR UPDATE SQL clause to lock row for update
+
+        Currently mysql ignores NOWAIT
+        """
+        if nowait:
+            raise NotImplementedError("NOWAIT option for SELECT ... FOR UPDATE not implemented with mysql");
+        BaseDatabaseWrapper.for_update_sql(self,nowait=False)
+
     def limit_offset_sql(self, limit, offset=None):
         # 'LIMIT 20,40'
         sql = "LIMIT "
Index: django/db/backends/__init__.py
===================================================================
--- django/db/backends/__init__.py	(revision 7513)
+++ django/db/backends/__init__.py	(working copy)
@@ -160,6 +160,16 @@
         """
         return cursor.lastrowid
 
+    def for_update_sql(self, nowait=False):
+        """
+        Return FOR UPDATE SQL clause to lock row for update
+        """
+        if nowait:
+            nowaitstr = ' NOWAIT'
+        else:
+            nowaitstr = ''
+        return 'FOR UPDATE' + nowaitstr
+
     def limit_offset_sql(self, limit, offset=None):
         """
         Returns a LIMIT/OFFSET SQL clause, given a limit and optional offset.
Index: tests/regressiontests/queries/models.py
===================================================================
--- tests/regressiontests/queries/models.py	(revision 7513)
+++ tests/regressiontests/queries/models.py	(working copy)
@@ -695,6 +695,20 @@
 >>> Item.objects.exclude(~Q(tags__name='t1', name='one'), name='two')
 [<Item: four>, <Item: one>, <Item: three>]
 
+Bug #2075
+Added FOR UPDATE functionality
+>>> from django.db import transaction
+>>> @transaction.commit_manually
+>>> def test_for_update():
+>>>     t = Tag(name='for update test')
+>>>     t.save()
+>>>     transaction.commit()
+>>>     tfound = Tag.objects.select_for_update().get(pk=t.id)
+>>>     tfound.name = 'for update test 2'
+>>>     tfound.save()
+>>>     transaction.commit()
+>>> test_for_update()
+
 Bug #7095
 Updates that are filtered on the model being updated are somewhat tricky to get
 in MySQL. This exercises that case.
Index: docs/db-api.txt
===================================================================
--- docs/db-api.txt	(revision 7513)
+++ docs/db-api.txt	(working copy)
@@ -1046,6 +1046,36 @@
 ``extra()`` is new. Previously, you could attempt to pass parameters for
 ``select`` in the ``params`` argument, but it worked very unreliably.
 
+select_for_update
+~~~~~~~~~~~~~~~~~
+
+**New in Django development version:**
+
+Lock rows returned from a query. Most databases allow you to exclusively
+lock rows with ``select_for_update()``. To do this call the method
+``select_for_update()`` to lock all retrieved objects::
+
+    entry = Entry.objects.select_for_update().get(pk=1)
+    ...
+    entry.save()
+
+All objects returned using ``select_for_update()`` will be locked with an
+exclusive lock which will remain locked until the transaction has finished.
+In the case of using middleware, the locks will be released when the view
+returns and the transaction is committed or rolled back. SQLite does not
+support an exclusive lock so this is simply ignored for SQLite. Other
+databases issue a ``FOR UPDATE``.
+
+If you would not like to wait for the lock then set the parameter nowait to
+True. In this case, it will grab the lock if it isn't already locked. If
+it is locked then it will throw an exception. This is not supported
+with mysql. Doing this with mysql will raise a ``NotImplemented`` exception.
+
+Note that all rows returned are locked.  If you retrieve multiple objects,
+all objects will be locked until the transaction is committed. Another
+process which does a ``select_for_update()`` on the same rows will wait until
+the transaction which has the locks is finished.
+
 QuerySet methods that do not return QuerySets
 ---------------------------------------------
 
