diff --git a/django/db/models/base.py b/django/db/models/base.py
index 7df4f6d..8bd49f1 100644
--- a/django/db/models/base.py
+++ b/django/db/models/base.py
@@ -2,6 +2,7 @@ import copy
 import sys
 from functools import update_wrapper
 from itertools import izip
+from sets import ImmutableSet
 
 import django.db.models.manager     # Imported to register signal handler.
 from django.conf import settings
@@ -11,7 +12,7 @@ from django.core import validators
 from django.db.models.fields import AutoField, FieldDoesNotExist
 from django.db.models.fields.related import (ManyToOneRel,
     OneToOneField, add_lazy_relation)
-from django.db import (connections, router, transaction, DatabaseError,
+from django.db import (router, transaction, DatabaseError,
     DEFAULT_DB_ALIAS)
 from django.db.models.query import Q
 from django.db.models.query_utils import DeferredAttribute
@@ -449,7 +450,7 @@ class Model(object):
             return getattr(self, field_name)
         return getattr(self, field.attname)
 
-    def save(self, force_insert=False, force_update=False, using=None):
+    def save(self, force_insert=False, force_update=False, using=None, update_fields=None):
         """
         Saves the current instance. Override this in a subclass if you want to
         control the saving process.
@@ -458,14 +459,29 @@ class Model(object):
         that the "save" must be an SQL insert or update (or equivalent for
         non-SQL backends), respectively. Normally, they should not be set.
         """
-        if force_insert and force_update:
+        if force_insert and (force_update or update_fields):
             raise ValueError("Cannot force both insert and updating in model saving.")
-        self.save_base(using=using, force_insert=force_insert, force_update=force_update)
 
+        if update_fields is not None:
+            # If update_fields is empty, skip the save. We do also check for
+            # no-op saves later on for inheritance cases. This bailout is
+            # still needed for skipping signal sending.
+            if len(update_fields) == 0:
+                return
+            update_fields = ImmutableSet(update_fields)
+
+            field_names = set(self._meta.get_all_field_names())
+            not_model_fields = update_fields.difference(field_names)
+            if not_model_fields:
+                raise ValueError("The following fields do not exist in this model: %s"
+                                 % ', '.join(not_model_fields))
+
+        self.save_base(using=using, force_insert=force_insert,
+                       force_update=force_update, update_fields=update_fields)
     save.alters_data = True
 
     def save_base(self, raw=False, cls=None, origin=None, force_insert=False,
-            force_update=False, using=None):
+                  force_update=False, using=None, update_fields=None):
         """
         Does the heavy-lifting involved in saving. Subclasses shouldn't need to
         override this method. It's separate from save() in order to hide the
@@ -473,7 +489,8 @@ class Model(object):
         ('raw', 'cls', and 'origin').
         """
         using = using or router.db_for_write(self.__class__, instance=self)
-        assert not (force_insert and force_update)
+        assert not (force_insert and (force_update or update_fields))
+        assert not update_fields or len(update_fields) > 0
         if cls is None:
             cls = self.__class__
             meta = cls._meta
@@ -483,7 +500,8 @@ class Model(object):
             meta = cls._meta
 
         if origin and not meta.auto_created:
-            signals.pre_save.send(sender=origin, instance=self, raw=raw, using=using)
+            signals.pre_save.send(sender=origin, instance=self, raw=raw, using=using,
+                                  update_fields=update_fields)
 
         # If we are in a raw save, save the object exactly as presented.
         # That means that we don't try to be smart about saving attributes
@@ -503,7 +521,7 @@ class Model(object):
                 if field and getattr(self, parent._meta.pk.attname) is None and getattr(self, field.attname) is not None:
                     setattr(self, parent._meta.pk.attname, getattr(self, field.attname))
 
-                self.save_base(cls=parent, origin=org, using=using)
+                self.save_base(cls=parent, origin=org, using=using, update_fields=update_fields)
 
                 if field:
                     setattr(self, field.attname, self._get_pk_val(parent._meta))
@@ -513,6 +531,9 @@ class Model(object):
         if not meta.proxy:
             non_pks = [f for f in meta.local_fields if not f.primary_key]
 
+            if update_fields:
+                non_pks = [f for f in non_pks if f.name in update_fields]
+
             # First, try an UPDATE. If that doesn't update anything, do an INSERT.
             pk_val = self._get_pk_val(meta)
             pk_set = pk_val is not None
@@ -520,7 +541,7 @@ class Model(object):
             manager = cls._base_manager
             if pk_set:
                 # Determine whether a record with the primary key already exists.
-                if (force_update or (not force_insert and
+                if ((force_update or update_fields) or (not force_insert and
                         manager.using(using).filter(pk=pk_val).exists())):
                     # It does already exist, so do an UPDATE.
                     if force_update or non_pks:
@@ -529,6 +550,8 @@ class Model(object):
                             rows = manager.using(using).filter(pk=pk_val)._update(values)
                             if force_update and not rows:
                                 raise DatabaseError("Forced update did not affect any rows.")
+                            if update_fields and not rows:
+                                raise DatabaseError("Save with update_fields did not affect any rows.")
                 else:
                     record_exists = False
             if not pk_set or not record_exists:
@@ -541,7 +564,7 @@ class Model(object):
 
                 fields = meta.local_fields
                 if not pk_set:
-                    if force_update:
+                    if force_update or update_fields:
                         raise ValueError("Cannot force an update in save() with no primary key.")
                     fields = [f for f in fields if not isinstance(f, AutoField)]
 
@@ -561,8 +584,8 @@ class Model(object):
 
         # Signal that the save is complete
         if origin and not meta.auto_created:
-            signals.post_save.send(sender=origin, instance=self,
-                created=(not record_exists), raw=raw, using=using)
+            signals.post_save.send(sender=origin, instance=self, created=(not record_exists),
+                                   update_fields=update_fields, raw=raw, using=using)
 
 
     save_base.alters_data = True
diff --git a/django/db/models/signals.py b/django/db/models/signals.py
index 48872e7..4666169 100644
--- a/django/db/models/signals.py
+++ b/django/db/models/signals.py
@@ -5,8 +5,8 @@ class_prepared = Signal(providing_args=["class"])
 pre_init = Signal(providing_args=["instance", "args", "kwargs"])
 post_init = Signal(providing_args=["instance"])
 
-pre_save = Signal(providing_args=["instance", "raw", "using"])
-post_save = Signal(providing_args=["instance", "raw", "created", "using"])
+pre_save = Signal(providing_args=["instance", "raw", "using", "update_fields"])
+post_save = Signal(providing_args=["instance", "raw", "created", "using", "update_fields"])
 
 pre_delete = Signal(providing_args=["instance", "using"])
 post_delete = Signal(providing_args=["instance", "using"])
diff --git a/docs/ref/models/instances.txt b/docs/ref/models/instances.txt
index 3c84be5..c934977 100644
--- a/docs/ref/models/instances.txt
+++ b/docs/ref/models/instances.txt
@@ -135,7 +135,7 @@ Saving objects
 
 To save an object back to the database, call ``save()``:
 
-.. method:: Model.save([force_insert=False, force_update=False, using=DEFAULT_DB_ALIAS])
+.. method:: Model.save([force_insert=False, force_update=False, using=DEFAULT_DB_ALIAS, update_fields=None])
 
 .. versionadded:: 1.2
    The ``using`` argument was added.
@@ -334,6 +334,25 @@ For more details, see the documentation on :ref:`F() expressions
 <query-expressions>` and their :ref:`use in update queries
 <topics-db-queries-update>`.
 
+Specifying which fields to save
+-------------------------------
+
+.. versionadded:: 1.5
+
+If ``save()`` is passed a list of field names as keyword argument
+``update_fields``, only the fields named in that list will be saved to the
+database. This may be desirable if you want to update just one or a few fields
+on an object, as there will be a slight performance benefit from preventing
+all of the model fields from being updated in the database. For example:
+
+    product.name = 'Name changed again'
+    product.save(update_fields=['name'])
+
+
+The ``update_fields`` argument can be any iterable containing strings. An
+not None, but empty ``update_fields`` skips the save completely (no signals
+sent). Specifying ``update_fields`` will force an update.
+
 Deleting objects
 ================
 
diff --git a/docs/ref/signals.txt b/docs/ref/signals.txt
index 3917b52..e047d17 100644
--- a/docs/ref/signals.txt
+++ b/docs/ref/signals.txt
@@ -123,6 +123,10 @@ Arguments sent with this signal:
 ``using``
     The database alias being used.
 
+``update_fields``
+    List or tuple of fields to update explicitly specified in the ``save()`` method.
+    ``None`` if you do not use this parameter when you call ``save()``.
+
 post_save
 ---------
 
@@ -154,6 +158,10 @@ Arguments sent with this signal:
 ``using``
     The database alias being used.
 
+``update_fields``
+    List or tuple of fields to update explicitly specified in the ``save()`` method.
+    ``None`` if you do not use this parameter when you call ``save()``.
+
 pre_delete
 ----------
 
diff --git a/docs/releases/1.5.txt b/docs/releases/1.5.txt
index 5a92e7d..82e13b9 100644
--- a/docs/releases/1.5.txt
+++ b/docs/releases/1.5.txt
@@ -44,6 +44,10 @@ Django 1.5 also includes several smaller improvements worth noting:
 * :mod:`django.utils.timezone` provides a helper for converting aware
   datetimes between time zones. See :func:`~django.utils.timezone.localtime`.
 
+* :meth:`Model.save() <django.db.models.Model.save()>` has a new argument
+  ``update_fields``. Using this argument allows restricting the set of fields
+  to update when saving model instances.
+
 Backwards incompatible changes in 1.5
 =====================================
 
diff --git a/tests/modeltests/update_only_fields/__init__.py b/tests/modeltests/update_only_fields/__init__.py
new file mode 100644
index 0000000..faaaf79
--- /dev/null
+++ b/tests/modeltests/update_only_fields/__init__.py
@@ -0,0 +1,3 @@
+# -*- coding: utf-8 -*-
+
+
diff --git a/tests/modeltests/update_only_fields/models.py b/tests/modeltests/update_only_fields/models.py
new file mode 100644
index 0000000..3f56ed6
--- /dev/null
+++ b/tests/modeltests/update_only_fields/models.py
@@ -0,0 +1,26 @@
+
+from django.db import models
+
+GENDER_CHOICES = (
+    ('M', 'Male'),
+    ('F', 'Female'),
+)
+
+class Person(models.Model):
+    name = models.CharField(max_length=20)
+    gender = models.CharField(max_length=1, choices=GENDER_CHOICES)
+
+    def __unicode__(self):
+        return self.name
+
+class Employee(Person):
+    employee_num = models.IntegerField(default=0)
+    profile = models.ForeignKey('Profile', related_name='profiles', null=True)
+
+
+class Profile(models.Model):
+    name = models.CharField(max_length=200)
+    salary = models.FloatField(default=1000.0)
+
+    def __unicode__(self):
+        return self.name
diff --git a/tests/modeltests/update_only_fields/tests.py b/tests/modeltests/update_only_fields/tests.py
new file mode 100644
index 0000000..739ead6
--- /dev/null
+++ b/tests/modeltests/update_only_fields/tests.py
@@ -0,0 +1,108 @@
+from __future__ import absolute_import
+
+from django.test import TestCase
+from django.db.models.signals import pre_save, post_save
+from .models import Person, Employee, Profile
+
+class UpdateOnlyFieldsTests(TestCase):
+    def test_update_fields_basic(self):
+        s = Person.objects.create(name='Sara', gender='F')
+        self.assertEqual(s.gender, 'F')
+
+        s.gender = 'M'
+        s.name = 'Ian'
+        s.save(update_fields=['name'])
+
+        s = Person.objects.get(pk=s.pk)
+        self.assertEqual(s.gender, 'F')
+        self.assertEqual(s.name, 'Ian')
+
+    def test_update_fields_inheritance(self):
+        profile_boss = Profile.objects.create(name='Boss', salary=3000)
+        profile_receptionist = Profile.objects.create(name='Receptionist', salary=1000)
+
+        e1 = Employee.objects.create(name='Sara', gender='F',
+            employee_num=1, profile=profile_boss)
+
+        e1.name = 'Ian'
+        e1.gender = 'M'
+        e1.save(update_fields=['name'])
+
+        e2 = Employee.objects.get(pk=e1.pk)
+        self.assertEqual(e2.name, 'Ian')
+        self.assertEqual(e2.gender, 'F')
+        self.assertEqual(e2.profile, profile_boss)
+
+        e2.profile = profile_receptionist
+        e2.name = 'Sara'
+        e2.save(update_fields=['profile'])
+
+        e3 = Employee.objects.get(pk=e1.pk)
+        self.assertEqual(e3.name, 'Ian')
+        self.assertEqual(e3.profile, profile_receptionist)
+
+    def test_update_fields_signals(self):
+        p = Person.objects.create(name='Sara', gender='F')
+        pre_save_data = []
+        def pre_save_receiver(**kwargs):
+            pre_save_data.append(kwargs['update_fields'])
+        pre_save.connect(pre_save_receiver)
+        post_save_data = []
+        def post_save_receiver(**kwargs):
+            post_save_data.append(kwargs['update_fields'])
+        post_save.connect(post_save_receiver)
+        p.save(update_fields=['name'])
+        self.assertEqual(len(pre_save_data), 1)
+        self.assertEqual(len(pre_save_data[0]), 1)
+        self.assertTrue('name' in pre_save_data[0])
+        self.assertEqual(len(post_save_data), 1)
+        self.assertEqual(len(post_save_data[0]), 1)
+        self.assertTrue('name' in post_save_data[0])
+
+    def test_update_fields_incorrect_params(self):
+        s = Person.objects.create(name='Sara', gender='F')
+
+        with self.assertRaises(ValueError):
+            s.save(update_fields=['first_name'])
+
+        with self.assertRaises(ValueError):
+            s.save(update_fields="name")
+
+    def test_empty_update_fields(self):
+        s = Person.objects.create(name='Sara', gender='F')
+        pre_save_data = []
+        def pre_save_receiver(**kwargs):
+            pre_save_data.append(kwargs['update_fields'])
+        pre_save.connect(pre_save_receiver)
+        post_save_data = []
+        def post_save_receiver(**kwargs):
+            post_save_data.append(kwargs['update_fields'])
+        post_save.connect(post_save_receiver)
+        # Save is skipped.
+        with self.assertNumQueries(0):
+            s.save(update_fields=[])
+        # Signals were skipped, too...
+        self.assertEqual(len(pre_save_data), 0)
+        self.assertEqual(len(post_save_data), 0)
+
+    def test_num_queries_inheritance(self):
+        s = Employee.objects.create(name='Sara', gender='F')
+        s.employee_num = 1
+        s.name = 'Emily'
+        with self.assertNumQueries(1):
+            s.save(update_fields=['employee_num'])
+        s = Employee.objects.get(pk=s.pk)
+        self.assertEqual(s.employee_num, 1)
+        self.assertEqual(s.name, 'Sara')
+        s.employee_num = 2
+        s.name = 'Emily'
+        with self.assertNumQueries(1):
+            s.save(update_fields=['name'])
+        s = Employee.objects.get(pk=s.pk)
+        self.assertEqual(s.name, 'Emily')
+        self.assertEqual(s.employee_num, 1)
+        # A little sanity check that we actually did updates...
+        self.assertEqual(Employee.objects.count(), 1)
+        self.assertEqual(Person.objects.count(), 1)
+        with self.assertNumQueries(2):
+            s.save(update_fields=['name', 'employee_num'])
