mirror of
https://github.com/django/django.git
synced 2025-07-05 10:19:20 +00:00
queryset-refactor: Added faster paths for updates and inserts that are done
from other core code. This saves a round-trip from field object to field name and back to field object when we already have the right information to hand. git-svn-id: http://code.djangoproject.com/svn/django/branches/queryset-refactor@7437 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
parent
fcfa8b204a
commit
d4956cb427
@ -308,29 +308,28 @@ class Model(object):
|
|||||||
if manager.filter(pk=pk_val).extra(select={'a': 1}).values('a').order_by():
|
if manager.filter(pk=pk_val).extra(select={'a': 1}).values('a').order_by():
|
||||||
# It does already exist, so do an UPDATE.
|
# It does already exist, so do an UPDATE.
|
||||||
if non_pks:
|
if non_pks:
|
||||||
values = [(f.name, f.get_db_prep_save(raw and getattr(self, f.attname) or f.pre_save(self, False))) for f in non_pks]
|
values = [(f, None, f.get_db_prep_save(raw and getattr(self, f.attname) or f.pre_save(self, False))) for f in non_pks]
|
||||||
manager.filter(pk=pk_val).update(**dict(values))
|
manager.filter(pk=pk_val)._update(values)
|
||||||
else:
|
else:
|
||||||
record_exists = False
|
record_exists = False
|
||||||
if not pk_set or not record_exists:
|
if not pk_set or not record_exists:
|
||||||
if not pk_set:
|
if not pk_set:
|
||||||
values = [(f.name, f.get_db_prep_save(raw and getattr(self, f.attname) or f.pre_save(self, True))) for f in meta.local_fields if not isinstance(f, AutoField)]
|
values = [(f, f.get_db_prep_save(raw and getattr(self, f.attname) or f.pre_save(self, True))) for f in meta.local_fields if not isinstance(f, AutoField)]
|
||||||
else:
|
else:
|
||||||
values = [(f.name, f.get_db_prep_save(raw and getattr(self, f.attname) or f.pre_save(self, True))) for f in meta.local_fields]
|
values = [(f, f.get_db_prep_save(raw and getattr(self, f.attname) or f.pre_save(self, True))) for f in meta.local_fields]
|
||||||
|
|
||||||
if meta.order_with_respect_to:
|
if meta.order_with_respect_to:
|
||||||
field = meta.order_with_respect_to
|
field = meta.order_with_respect_to
|
||||||
values.append(('_order', manager.filter(**{field.name: getattr(self, field.attname)}).count()))
|
values.append((meta.get_field_by_name('_order')[0], manager.filter(**{field.name: getattr(self, field.attname)}).count()))
|
||||||
record_exists = False
|
record_exists = False
|
||||||
|
|
||||||
update_pk = bool(meta.has_auto_field and not pk_set)
|
update_pk = bool(meta.has_auto_field and not pk_set)
|
||||||
if values:
|
if values:
|
||||||
# Create a new record.
|
# Create a new record.
|
||||||
result = manager._insert(__return_id=update_pk, **dict(values))
|
result = manager._insert(values, return_id=update_pk)
|
||||||
else:
|
else:
|
||||||
# Create a new record with defaults for everything.
|
# Create a new record with defaults for everything.
|
||||||
result = manager._insert(__return_id=update_pk,
|
result = manager._insert([(meta.pk, connection.ops.pk_default_value())], return_id=update_pk, raw_values=True)
|
||||||
__raw_values=True, pk=connection.ops.pk_default_value())
|
|
||||||
|
|
||||||
if update_pk:
|
if update_pk:
|
||||||
setattr(self, meta.pk.attname, result)
|
setattr(self, meta.pk.attname, result)
|
||||||
|
@ -123,8 +123,11 @@ class Manager(object):
|
|||||||
def reverse(self, *args, **kwargs):
|
def reverse(self, *args, **kwargs):
|
||||||
return self.get_query_set().reverse(*args, **kwargs)
|
return self.get_query_set().reverse(*args, **kwargs)
|
||||||
|
|
||||||
def _insert(self, **kwargs):
|
def _insert(self, values, **kwargs):
|
||||||
return insert_query(self.model, **kwargs)
|
return insert_query(self.model, values, **kwargs)
|
||||||
|
|
||||||
|
def _update(self, values, **kwargs):
|
||||||
|
return self.get_query_set()._update(values, **kwargs)
|
||||||
|
|
||||||
class ManagerDescriptor(object):
|
class ManagerDescriptor(object):
|
||||||
# This class ensures managers aren't accessible via model instances.
|
# This class ensures managers aren't accessible via model instances.
|
||||||
|
@ -287,6 +287,19 @@ class QuerySet(object):
|
|||||||
self._result_cache = None
|
self._result_cache = None
|
||||||
update.alters_data = True
|
update.alters_data = True
|
||||||
|
|
||||||
|
def _update(self, values):
|
||||||
|
"""
|
||||||
|
A version of update that accepts field objects instead of field names.
|
||||||
|
Used primarily for model saving and not intended for use by general
|
||||||
|
code (it requires too much poking around at model internals to be
|
||||||
|
useful at that level).
|
||||||
|
"""
|
||||||
|
query = self.query.clone(sql.UpdateQuery)
|
||||||
|
query.add_update_fields(values)
|
||||||
|
query.execute_sql(None)
|
||||||
|
self._result_cache = None
|
||||||
|
_update.alters_data = True
|
||||||
|
|
||||||
##################################################
|
##################################################
|
||||||
# PUBLIC METHODS THAT RETURN A QUERYSET SUBCLASS #
|
# PUBLIC METHODS THAT RETURN A QUERYSET SUBCLASS #
|
||||||
##################################################
|
##################################################
|
||||||
@ -692,13 +705,13 @@ def delete_objects(seen_objs):
|
|||||||
|
|
||||||
transaction.commit_unless_managed()
|
transaction.commit_unless_managed()
|
||||||
|
|
||||||
def insert_query(__model, __return_id=False, __raw_values=False, **kwargs):
|
def insert_query(model, values, return_id=False, raw_values=False):
|
||||||
"""
|
"""
|
||||||
Inserts a new record for the given model. This provides an interface to
|
Inserts a new record for the given model. This provides an interface to
|
||||||
the InsertQuery class and is how Model.save() is implemented. It is not
|
the InsertQuery class and is how Model.save() is implemented. It is not
|
||||||
part of the public API.
|
part of the public API.
|
||||||
"""
|
"""
|
||||||
query = sql.InsertQuery(__model, connection)
|
query = sql.InsertQuery(model, connection)
|
||||||
query.insert_values(kwargs, __raw_values)
|
query.insert_values(values, raw_values)
|
||||||
return query.execute_sql(__return_id)
|
return query.execute_sql(return_id)
|
||||||
|
|
||||||
|
@ -194,11 +194,27 @@ class UpdateQuery(Query):
|
|||||||
self.execute_sql(None)
|
self.execute_sql(None)
|
||||||
|
|
||||||
def add_update_values(self, values):
|
def add_update_values(self, values):
|
||||||
from django.db.models.base import Model
|
"""
|
||||||
|
Convert a dictionary of field name to value mappings into an update
|
||||||
|
query. This is the entry point for the public update() method on
|
||||||
|
querysets.
|
||||||
|
"""
|
||||||
|
values_seq = []
|
||||||
for name, val in values.iteritems():
|
for name, val in values.iteritems():
|
||||||
field, model, direct, m2m = self.model._meta.get_field_by_name(name)
|
field, model, direct, m2m = self.model._meta.get_field_by_name(name)
|
||||||
if not direct or m2m:
|
if not direct or m2m:
|
||||||
raise FieldError('Cannot update model field %r (only non-relations and foreign keys permitted).' % field)
|
raise FieldError('Cannot update model field %r (only non-relations and foreign keys permitted).' % field)
|
||||||
|
values_seq.append((field, model, val))
|
||||||
|
return self.add_update_fields(values_seq)
|
||||||
|
|
||||||
|
def add_update_fields(self, values_seq):
|
||||||
|
"""
|
||||||
|
Turn a sequence of (field, model, value) triples into an update query.
|
||||||
|
Used by add_update_values() as well as the "fast" update path when
|
||||||
|
saving models.
|
||||||
|
"""
|
||||||
|
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.
|
# FIXME: Some sort of db_prep_* is probably more appropriate here.
|
||||||
if field.rel and isinstance(val, Model):
|
if field.rel and isinstance(val, Model):
|
||||||
val = val.pk
|
val = val.pk
|
||||||
@ -279,17 +295,11 @@ class InsertQuery(Query):
|
|||||||
parameters. This provides a way to insert NULL and DEFAULT keywords
|
parameters. This provides a way to insert NULL and DEFAULT keywords
|
||||||
into the query, for example.
|
into the query, for example.
|
||||||
"""
|
"""
|
||||||
func = lambda x: self.model._meta.get_field_by_name(x)[0]
|
|
||||||
# keys() and values() return items in the same order, providing the
|
# keys() and values() return items in the same order, providing the
|
||||||
# dictionary hasn't changed between calls. So the dual iteration here
|
# dictionary hasn't changed between calls. So the dual iteration here
|
||||||
# works as intended.
|
# works as intended.
|
||||||
placeholders, values = [], []
|
placeholders, values = [], []
|
||||||
for name, val in insert_values.iteritems():
|
for field, val in insert_values:
|
||||||
if name == 'pk':
|
|
||||||
name = self.model._meta.pk.name
|
|
||||||
# Getting the Field associated w/the name.
|
|
||||||
field = func(name)
|
|
||||||
|
|
||||||
if hasattr(field, 'get_placeholder'):
|
if hasattr(field, 'get_placeholder'):
|
||||||
# Some fields (e.g. geo fields) need special munging before
|
# Some fields (e.g. geo fields) need special munging before
|
||||||
# they can be inserted.
|
# they can be inserted.
|
||||||
|
Loading…
x
Reference in New Issue
Block a user