Ticket #2705: select_for_update.patch

File select_for_update.patch, 8.3 KB (added by Collin Grady <cgrady@…>, 8 years ago)

improvement on same idea, supports backend-specific syntax

  • django/db/models/manager.py

     
    9999    def order_by(self, *args, **kwargs):
    100100        return self.get_query_set().order_by(*args, **kwargs)
    101101
     102    def select_for_update(self, *args, **kwargs):
     103        return self.get_query_set().select_for_update(*args, **kwargs)
     104
    102105    def select_related(self, *args, **kwargs):
    103106        return self.get_query_set().select_related(*args, **kwargs)
    104107
  • django/db/models/query.py

     
    8282    def __init__(self, model=None):
    8383        self.model = model
    8484        self._filters = Q()
    85         self._order_by = None        # Ordering, e.g. ('date', '-name'). If None, use model's ordering.
    86         self._select_related = False # Whether to fill cache for related objects.
    87         self._max_related_depth = 0  # Maximum "depth" for select_related
    88         self._distinct = False       # Whether the query should use SELECT DISTINCT.
    89         self._select = {}            # Dictionary of attname -> SQL.
    90         self._where = []             # List of extra WHERE clauses to use.
    91         self._params = []            # List of params to use for extra WHERE clauses.
    92         self._tables = []            # List of extra tables to use.
    93         self._offset = None          # OFFSET clause.
    94         self._limit = None           # LIMIT clause.
     85        self._order_by = None           # Ordering, e.g. ('date', '-name'). If None, use model's ordering.
     86        self._select_for_update = False # Whether to select for update.
     87        self._select_related = False    # Whether to fill cache for related objects.
     88        self._max_related_depth = 0     # Maximum "depth" for select_related
     89        self._distinct = False          # Whether the query should use SELECT DISTINCT.
     90        self._select = {}               # Dictionary of attname -> SQL.
     91        self._where = []                # List of extra WHERE clauses to use.
     92        self._params = []               # List of params to use for extra WHERE clauses.
     93        self._tables = []               # List of extra tables to use.
     94        self._offset = None             # OFFSET clause.
     95        self._limit = None              # LIMIT clause.
    9596        self._result_cache = None
    9697
    9798    ########################
     
    211212           
    212213        counter = self._clone()
    213214        counter._order_by = ()
     215        counter._select_for_update = False
    214216        counter._select_related = False
    215217
    216218        offset = counter._offset
     
    316318        del_query = self._clone()
    317319
    318320        # disable non-supported fields
     321        del_query._select_for_update = False
    319322        del_query._select_related = False
    320323        del_query._order_by = []
    321324
     
    398401        else:
    399402            return self._filter_or_exclude(None, **filter_obj)
    400403
     404    def select_for_update(self, true_or_false=True):
     405        "Returns a new QuerySet instance with '_select_for_update' modified."
     406        return self._clone(_select_for_update=true_or_false)
     407
    401408    def select_related(self, true_or_false=True, depth=0):
    402409        "Returns a new QuerySet instance with '_select_related' modified."
    403410        return self._clone(_select_related=true_or_false, _max_related_depth=depth)
     
    433440        c.model = self.model
    434441        c._filters = self._filters
    435442        c._order_by = self._order_by
     443        c._select_for_update = self._select_for_update
    436444        c._select_related = self._select_related
    437445        c._max_related_depth = self._max_related_depth
    438446        c._distinct = self._distinct
     
    549557        else:
    550558            assert self._offset is None, "'offset' is not allowed without 'limit'"
    551559
     560        # FOR UPDATE
     561        if self._select_for_update:
     562            sql.append("%s" % backend.get_for_update_sql())
     563
    552564        return select, " ".join(sql), params
    553565
    554566class ValuesQuerySet(QuerySet):
  • django/db/backends/ado_mssql/base.py

     
    116116    if lookup_type=='day':
    117117        return "Convert(datetime, Convert(varchar(12), %s))" % field_name
    118118
     119def get_for_update_sql():
     120    return 'WITH (UPDLOCK, HOLDLOCK)'
     121
    119122def get_limit_offset_sql(limit, offset=None):
    120123    # TODO: This is a guess. Make sure this is correct.
    121124    sql = "LIMIT %s" % limit
  • django/db/backends/mysql_old/base.py

     
    166166        sql = "CAST(DATE_FORMAT(%s, '%s') AS DATETIME)" % (field_name, format_str)
    167167    return sql
    168168
     169def get_for_update_sql():
     170    return 'FOR UPDATE'
     171
    169172def get_limit_offset_sql(limit, offset=None):
    170173    sql = "LIMIT "
    171174    if offset and offset != 0:
  • django/db/backends/postgresql/base.py

     
    137137    # http://www.postgresql.org/docs/8.0/static/functions-datetime.html#FUNCTIONS-DATETIME-TRUNC
    138138    return "DATE_TRUNC('%s', %s)" % (lookup_type, field_name)
    139139
     140def get_for_update_sql():
     141    return 'FOR UPDATE'
     142
    140143def get_limit_offset_sql(limit, offset=None):
    141144    sql = "LIMIT %s" % limit
    142145    if offset and offset != 0:
  • django/db/backends/sqlite3/base.py

     
    131131    # sqlite doesn't support DATE_TRUNC, so we fake it as above.
    132132    return 'django_date_trunc("%s", %s)' % (lookup_type.lower(), field_name)
    133133
     134def get_for_update_sql():
     135    # sqlite does not support FOR UPDATE
     136    return ''
     137
    134138def get_limit_offset_sql(limit, offset=None):
    135139    sql = "LIMIT %s" % limit
    136140    if offset and offset != 0:
  • django/db/backends/mysql/base.py

     
    164164        sql = "CAST(DATE_FORMAT(%s, '%s') AS DATETIME)" % (field_name, format_str)
    165165    return sql
    166166
     167def get_for_update_sql():
     168    return 'FOR UPDATE'
     169
    167170def get_limit_offset_sql(limit, offset=None):
    168171    sql = "LIMIT "
    169172    if offset and offset != 0:
  • django/db/backends/oracle/base.py

     
    101101def get_date_trunc_sql(lookup_type, field_name):
    102102    return "EXTRACT(%s FROM TRUNC(%s))" % (lookup_type, field_name)
    103103
     104def get_for_update_sql():
     105    return 'FOR UPDATE'
     106
    104107def get_limit_offset_sql(limit, offset=None):
    105108    # Limits and offset are too complicated to be handled here.
    106109    # Instead, they are handled in django/db/query.py.
  • django/db/backends/postgresql_psycopg2/base.py

     
    9797    # http://www.postgresql.org/docs/8.0/static/functions-datetime.html#FUNCTIONS-DATETIME-TRUNC
    9898    return "DATE_TRUNC('%s', %s)" % (lookup_type, field_name)
    9999
     100def get_for_update_sql():
     101    return 'FOR UPDATE'
     102
    100103def get_limit_offset_sql(limit, offset=None):
    101104    sql = "LIMIT %s" % limit
    102105    if offset and offset != 0:
  • django/db/backends/dummy/base.py

     
    3434get_last_insert_id = complain
    3535get_date_extract_sql = complain
    3636get_date_trunc_sql = complain
     37get_for_update_sql = complain
    3738get_limit_offset_sql = complain
    3839get_random_function_sql = complain
    3940get_deferrable_sql = complain
Back to Top