Index: django/db/models/sql/compiler.py
===================================================================
--- django/db/models/sql/compiler.py	(revision 13301)
+++ django/db/models/sql/compiler.py	(working copy)
@@ -114,6 +114,10 @@
                         result.append('LIMIT %d' % val)
                 result.append('OFFSET %d' % self.query.low_mark)
 
+        if self.query.select_for_update and self.connection.features.has_select_for_update:
+            nowait = self.query.select_for_update_nowait and self.connection.features.has_select_for_update
+            result.append("%s" % self.connection.ops.for_update_sql(nowait=nowait))
+
         return ' '.join(result), tuple(params)
 
     def as_nested_sql(self):
Index: django/db/models/sql/query.py
===================================================================
--- django/db/models/sql/query.py	(revision 13301)
+++ django/db/models/sql/query.py	(working copy)
@@ -11,7 +11,7 @@
 from django.utils.tree import Node
 from django.utils.datastructures import SortedDict
 from django.utils.encoding import force_unicode
-from django.db import connections, DEFAULT_DB_ALIAS
+from django.db import connections, DEFAULT_DB_ALIAS, DatabaseError
 from django.db.models import signals
 from django.db.models.fields import FieldDoesNotExist
 from django.db.models.query_utils import select_related_descend, InvalidQuery
@@ -23,8 +23,16 @@
     ExtraWhere, AND, OR)
 from django.core.exceptions import FieldError
 
-__all__ = ['Query', 'RawQuery']
+__all__ = ['Query', 'RawQuery', 'LockNotAvailable']
 
+
+class LockNotAvailable(DatabaseError): 
+    '''
+    Raised when a query fails because a lock was not available. 
+    '''
+    pass
+
+
 class RawQuery(object):
     """
     A single raw SQL query
@@ -84,9 +92,13 @@
 
     def _execute_query(self):
         self.cursor = connections[self.using].cursor()
-        self.cursor.execute(self.sql, self.params)
+        try:
+            self.cursor.execute(self.sql, self.params)
+        except DatabaseError, e:
+            if self.connection.features.has_select_for_update_nowait and self.connection.ops.signals_lock_not_available(e):
+                raise LockNotAvailable(*e.args)
+            raise
 
-
 class Query(object):
     """
     A single SQL query.
@@ -131,6 +143,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 = []
 
@@ -259,6 +273,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.aggregates = deepcopy(self.aggregates, memo=memo)
@@ -359,6 +375,7 @@
 
         query.clear_ordering(True)
         query.clear_limits()
+        query.select_for_update = False
         query.select_related = False
         query.related_select_cols = []
         query.related_select_fields = []
Index: django/db/models/manager.py
===================================================================
--- django/db/models/manager.py	(revision 13301)
+++ django/db/models/manager.py	(working copy)
@@ -164,6 +164,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/__init__.py
===================================================================
--- django/db/models/__init__.py	(revision 13301)
+++ django/db/models/__init__.py	(working copy)
@@ -11,6 +11,7 @@
 from django.db.models.fields.subclassing import SubfieldBase
 from django.db.models.fields.files import FileField, ImageField
 from django.db.models.fields.related import ForeignKey, OneToOneField, ManyToManyField, ManyToOneRel, ManyToManyRel, OneToOneRel
+from django.db.models.sql.query import LockNotAvailable
 from django.db.models import signals
 
 # Admin stages.
Index: django/db/models/query.py
===================================================================
--- django/db/models/query.py	(revision 13301)
+++ django/db/models/query.py	(working copy)
@@ -424,6 +424,7 @@
         del_query._for_write = True
 
         # Disable non-supported fields.
+        del_query.query.select_for_update = False
         del_query.query.select_related = False
         del_query.query.clear_ordering()
 
@@ -585,6 +586,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.
Index: django/db/backends/mysql/base.py
===================================================================
--- django/db/backends/mysql/base.py	(revision 13301)
+++ django/db/backends/mysql/base.py	(working copy)
@@ -124,9 +124,12 @@
     allows_group_by_pk = True
     related_fields_match_type = True
     allow_sliced_subqueries = False
+    has_select_for_update = True
+    has_select_for_update_nowait = False
 
 class DatabaseOperations(BaseDatabaseOperations):
     compiler_module = "django.db.backends.mysql.compiler"
+    signals_deadlock = lambda self, e: e.args[0] == ER.LOCK_DEADLOCK
 
     def date_extract_sql(self, lookup_type, field_name):
         # http://dev.mysql.com/doc/mysql/en/date-and-time-functions.html
Index: django/db/backends/oracle/base.py
===================================================================
--- django/db/backends/oracle/base.py	(revision 13301)
+++ django/db/backends/oracle/base.py	(working copy)
@@ -50,6 +50,8 @@
     uses_savepoints = True
     can_return_id_from_insert = True
     allow_sliced_subqueries = False
+    has_select_for_update = True 
+    has_select_for_update_nowait = True
 
 
 class DatabaseOperations(BaseDatabaseOperations):
@@ -279,6 +281,12 @@
                                            'column': column_name})
         return output
 
+    def signals_deadlock(self, exception): 
+        return exception.args[0].code == 60 
+
+    def signals_lock_not_available(self, exception): 
+        return exception.args[0].code == 54 
+
     def start_transaction_sql(self):
         return ''
 
Index: django/db/backends/__init__.py
===================================================================
--- django/db/backends/__init__.py	(revision 13301)
+++ django/db/backends/__init__.py	(working copy)
@@ -96,6 +96,8 @@
     # integer primary keys.
     related_fields_match_type = False
     allow_sliced_subqueries = True
+    has_select_for_update = False
+    has_select_for_update_nowait = False
 
 class BaseDatabaseOperations(object):
     """
@@ -185,6 +187,15 @@
         ordering.
         """
         return []
+    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 fulltext_search_sql(self, field_name):
         """
Index: django/db/backends/postgresql_psycopg2/base.py
===================================================================
--- django/db/backends/postgresql_psycopg2/base.py	(revision 13301)
+++ django/db/backends/postgresql_psycopg2/base.py	(working copy)
@@ -19,6 +19,7 @@
 try:
     import psycopg2 as Database
     import psycopg2.extensions
+    from psycopg2 import errorcodes
 except ImportError, e:
     from django.core.exceptions import ImproperlyConfigured
     raise ImproperlyConfigured("Error loading psycopg2 module: %s" % e)
@@ -67,8 +68,12 @@
 class DatabaseFeatures(BaseDatabaseFeatures):
     needs_datetime_string_cast = False
     can_return_id_from_insert = False
+    has_select_for_update = True
+    has_select_for_update_nowait = True
 
 class DatabaseOperations(PostgresqlDatabaseOperations):
+    signals_deadlock = lambda self, e: e.pgcode == errorcodes.DEADLOCK_DETECTED
+    signals_lock_not_available = lambda self, e: e.pgcode == errorcodes.LOCK_NOT_AVAILABLE
     def last_executed_query(self, cursor, sql, params):
         # With psycopg2, cursor objects have a "query" attribute that is the
         # exact query sent to the database. See docs here:
Index: docs/ref/models/querysets.txt
===================================================================
--- docs/ref/models/querysets.txt	(revision 13301)
+++ docs/ref/models/querysets.txt	(working copy)
@@ -963,6 +963,53 @@
     # queries the database with the 'backup' alias
     >>> Entry.objects.using('backup')
 
+``select_for_update(nowait=False)`` 
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 
+	 
+Returns a queryset that will lock rows until the end of the transaction,  
+generating a SELECT ... FOR UPDATE statement on supported databases. 
+	 
+For example:: 
+	 
+    entries = Entry.objects.select_for_update().filter(author=request.user) 
+ 
+All matched entries will be locked until the end of the transaction block,  
+meaning that other transactions will be prevented from changing or acquiring  
+locks on them. 
+ 
+Usually, if another transaction has already acquired a lock on one of the  
+selected rows, the query will block until the lock is released. If this is  
+not the behaviour you want, call ``select_for_update(nowait=True)``. This will  
+make the call non-blocking. If a conflicting lock is already acquired by  
+another transaction, ``django.db.models.LockNotAvailable`` will be raised when  
+the queryset is evaluated. 
+ 
+Using blocking locks on a database can lead to deadlocks. This occurs when two  
+concurrent transactions are both waiting on a lock the other transaction  
+already holds. To deal with deadlocks, wrap your views that use  
+``select_for_update(nowait=False)`` with the  
+``django.views.decorators.deadlock.handle_deadlocks`` decorator.  
+ 
+For example:: 
+ 
+    from django.db import transaction 
+    from django.views.decorators.deadlock import handle_deadlocks 
+ 
+    @handle_deadlocks(max_retries=2) 
+    @transaction.commit_on_success 
+    def my_view(request): 
+        ... 
+ 
+If the database engine detects a deadlock involving ``my_view`` and decides  
+to abort its transaction, it will be automatically retried. If deadlocks keep  
+occurring after two repeated attempts,  
+``django.views.decorators.DeadlockError`` will be raised, which can be  
+propagated to the user or handled in a middleware. 
+ 
+Currently the ``postgresql_psycopg2``, ``oracle``, and ``mysql`` 
+database backends support ``select_for_update()`` but MySQL has no 
+support for the ``nowait`` argument. Other backends will simply 
+generate queries as if ``select_for_update()`` had not been used. 
 
 QuerySet methods that do not return QuerySets
 ---------------------------------------------
Index: docs/ref/databases.txt
===================================================================
--- docs/ref/databases.txt	(revision 13301)
+++ docs/ref/databases.txt	(working copy)
@@ -345,6 +345,15 @@
 column types have a maximum length restriction of 255 characters, regardless
 of whether ``unique=True`` is specified or not.
 
+Row locking with ``QuerySet.select_for_update()`` 
+------------------------------------------------- 
+ 
+MySQL does not support the NOWAIT option to the SELECT ... FOR UPDATE  
+statement. However, you may call the ``select_for_update()`` method of a  
+queryset with ``nowait=True``. In that case, the argument will be silently  
+discarded and the generated query will block until the requested lock can be  
+acquired. 
+
 .. _sqlite-notes:
 
 SQLite notes
