diff --git a/djblets/db/fields.py b/djblets/db/fields.py
index 3b084f64e93273354573d61146880dde34cba4b5..39e286ebfeed64806edd6fe3cc825612410db440 100644
--- a/djblets/db/fields.py
+++ b/djblets/db/fields.py
@@ -37,6 +37,7 @@ from django.conf import settings
 from django.core.serializers.json import DjangoJSONEncoder
 from django.db import models
 from django.db.models import F
+from django.db.models.expressions import ExpressionNode
 from django.utils import six
 from django.utils.encoding import smart_unicode
 
@@ -401,18 +402,34 @@ class CounterField(models.IntegerField):
                 # accessed.
                 return
 
-            if self._initializer and six.callable(self._initializer):
-                self._locks[model_instance] = 1
-                value = self._initializer(model_instance)
-                del self._locks[model_instance]
-            else:
-                value = 0
+            value = 0
+
+            if self._initializer:
+                if isinstance(self._initializer, ExpressionNode):
+                    value = self._initializer
+                elif six.callable(self._initializer):
+                    self._locks[model_instance] = 1
+                    value = self._initializer(model_instance)
+                    del self._locks[model_instance]
 
             if value is not None:
-                setattr(model_instance, self.attname, value)
+                is_expr = isinstance(value, ExpressionNode)
+
+                if is_expr and not model_instance.pk:
+                    value = 0
+                    is_expr = False
+
+                if is_expr:
+                    cls.objects.filter(pk=model_instance.pk).update(**{
+                        self.attname: value,
+                    })
+
+                    self._reload_model_instance(model_instance, [self.attname])
+                else:
+                    setattr(model_instance, self.attname, value)
 
-                if model_instance.pk:
-                    model_instance.save(update_fields=[self.attname])
+                    if model_instance.pk:
+                        model_instance.save(update_fields=[self.attname])
 
         super(CounterField, self).contribute_to_class(cls, name)
 
diff --git a/djblets/db/tests/test_counter_field.py b/djblets/db/tests/test_counter_field.py
new file mode 100644
index 0000000000000000000000000000000000000000..3fb5134d2f12bdaab8eafe7e90e332dd17387c7c
--- /dev/null
+++ b/djblets/db/tests/test_counter_field.py
@@ -0,0 +1,113 @@
+from __future__ import unicode_literals
+
+from django.db import models
+from django.db.models import F
+
+from djblets.db.fields import CounterField
+from djblets.testing.testcases import TestCase, TestModelsLoaderMixin
+
+
+class CounterFieldTestModel(models.Model):
+    counter = CounterField(initializer=lambda o: 5)
+
+
+class CounterFieldInitializerModel(models.Model):
+    counter = CounterField(initializer=lambda o: 42)
+
+
+class CounterFieldInitializerFModel(models.Model):
+    INIT_EXPR = F('my_int') + 1
+
+    my_int = models.IntegerField(default=42)
+
+    counter = CounterField(
+        initializer=lambda o: CounterFieldInitializerFModel.INIT_EXPR)
+
+
+class CounterFieldNoInitializerModel(models.Model):
+    counter = CounterField()
+
+
+class CounterFieldTests(TestModelsLoaderMixin, TestCase):
+    """Tests for djblets.db.fields.CounterField."""
+    tests_app = 'djblets.db.tests'
+
+    def test_no_initializer(self):
+        """Testing CounterField without an initializer"""
+        model = CounterFieldNoInitializerModel.objects.create()
+        self.assertIsNone(model.counter)
+
+    def test_initializer_function(self):
+        """Testing CounterField with an initializer function"""
+        model = CounterFieldInitializerModel.objects.create()
+        self.assertEqual(model.counter, 42)
+
+    def test_initializer_f_existing_instance(self):
+        """Testing CounterField with an initializer F() expression
+        on existing model instance
+        """
+        model = CounterFieldInitializerFModel.objects.create()
+        model.counter = None
+        model.save()
+
+        model = CounterFieldInitializerFModel.objects.get(pk=model.pk)
+        self.assertEqual(model.counter, 43)
+
+    def test_initializer_f_new_instance(self):
+        """Testing CounterField with an initializer F() expression
+        on new model instance
+        """
+        model = CounterFieldInitializerFModel.objects.create()
+        self.assertEqual(model.counter, 0)
+
+    def test_increment(self):
+        """Testing CounterField.increment"""
+        self._test_increment(expected_value=6, expected_expr=F('counter') + 1)
+
+    def test_increment_by(self):
+        """Testing CounterField.increment with increment_by"""
+        self._test_increment(expected_value=8, expected_expr=F('counter') + 3,
+                             increment_by=3)
+
+    def test_increment_no_reload(self):
+        """Testing CounterField.increment with reload_object=False"""
+        self._test_increment(expected_value=5, expected_expr=F('counter') + 1,
+                             reload_object=False)
+
+    def test_decrement(self):
+        """Testing CounterField.decrement"""
+        self._test_decrement(expected_value=4, expected_expr=F('counter') - 1)
+
+    def test_decrement_by(self):
+        """Testing CounterField.decrement with decrement_by"""
+        self._test_decrement(expected_value=2, expected_expr=F('counter') - 3,
+                             decrement_by=3)
+
+    def test_decrement_no_reload(self):
+        """Testing CounterField.decrement with reload_object=False"""
+        self._test_decrement(expected_value=5, expected_expr=F('counter') - 1,
+                             reload_object=False)
+
+    def test_reload(self):
+        """Testing CounterField.reload"""
+        model = CounterFieldTestModel.objects.create()
+
+        model.counter = None
+        model.reload_counter()
+        self.assertEqual(model.counter, 5)
+
+    def _test_increment(self, expected_value, expected_expr, **kwargs):
+        self._test_update_value(expected_value, expected_expr,
+                                'increment_counter', **kwargs)
+
+    def _test_decrement(self, expected_value, expected_expr, **kwargs):
+        self._test_update_value(expected_value, expected_expr,
+                                'decrement_counter', **kwargs)
+
+    def _test_update_value(self, expected_value, expected_expr, func_name,
+                           **kwargs):
+        model = CounterFieldTestModel.objects.create()
+
+        getattr(model, func_name)(**kwargs)
+
+        self.assertEqual(model.counter, expected_value)
