diff --git a/docker-entry b/docker-entry
index b30f472..f933af4 100644
--- a/docker-entry
+++ b/docker-entry
@@ -22,7 +22,7 @@ export PIP_DISABLE_PIP_VERSION_CHECK=1
 # b/c it gives me control over what version of tox I'm using without having to rebuild the
 # docker image.
 python3.5 -m pip install --upgrade --force-reinstall \
-    --quiet --use-wheel --no-index --find-links=requirements/wheelhouse tox
+    --quiet --no-index --find-links=requirements/wheelhouse tox
 
 # Run the tests using our target python version.
 #
diff --git a/keg_elements/forms/validators.py b/keg_elements/forms/validators.py
index 35be03d..d060dc5 100644
--- a/keg_elements/forms/validators.py
+++ b/keg_elements/forms/validators.py
@@ -4,6 +4,34 @@ from decimal import Decimal
 
 import jinja2
 from wtforms import ValidationError
+import re
+
+
+class ValidateAlphaNumeric(object):
+    """
+        A validator to make sure than a form field contains only alphanumeric data
+
+        usage example:
+            import keg_elements.forms.validators as validators
+
+            wtforms.StringField('AlphaNumeric', validators=[
+                            validators.ValidateAlphaNumeric()
+                        ])
+    """
+    regex = re.compile(r'^[a-zA-Z0-9]+$')
+
+    def __init__(self, message=None):
+        self.message = message
+
+    def __call__(self, form, field):
+        value = field.data
+
+        message = self.message
+        if message is None:
+            message = field.gettext("Must only contain alphanumeric data.")
+
+        if not self.regex.match(value):
+            raise ValidationError(message)
 
 
 def numeric(form, field):

Add an alphanumeric validator
Currently there is no validator for alphanumeric (Characters and numbers only). It would be nice to have one for reuse.
diff --git a/keg_elements/tests/test_forms/test_validators.py b/keg_elements/tests/test_forms/test_validators.py
index e390e5d..93c4a9f 100644
--- a/keg_elements/tests/test_forms/test_validators.py
+++ b/keg_elements/tests/test_forms/test_validators.py
@@ -1,3 +1,4 @@
+# coding=utf-8
 import jinja2
 import pytest
 import wtforms
@@ -65,3 +66,58 @@ class TestUniqueValidator(object):
         assert str(exc.value) == (
             'Form must provide either `obj` or `_obj` property for uniqueness validation.'
         )
+
+
+class TestAlphaNumericValidator(object):
+
+    def test_alphanumeric(self):
+        message = 'Must only contain alphanumeric data.'
+
+        class AlphaNumericMockForm(wtforms.Form):
+            alpha_numeric_field = wtforms.StringField('AlphaNumeric', validators=[
+                validators.ValidateAlphaNumeric()
+            ])
+
+        form = AlphaNumericMockForm(alpha_numeric_field='123456asb')
+        form.validate()
+        assert form.errors == {}
+
+        form = AlphaNumericMockForm(alpha_numeric_field='123456')
+        form.validate()
+        assert form.errors == {}
+
+        form = AlphaNumericMockForm(alpha_numeric_field='abcd')
+        form.validate()
+        assert form.errors == {}
+
+        form = AlphaNumericMockForm(alpha_numeric_field='123456!')
+        form.validate()
+        assert form.errors['alpha_numeric_field'] == [message]
+
+        form = AlphaNumericMockForm(alpha_numeric_field='123456!')
+        form.validate()
+        assert form.errors['alpha_numeric_field'] == [message]
+
+        form = AlphaNumericMockForm(alpha_numeric_field='!212')
+        form.validate()
+        assert form.errors['alpha_numeric_field'] == [message]
+
+        form = AlphaNumericMockForm(alpha_numeric_field=' ')
+        form.validate()
+        assert form.errors['alpha_numeric_field'] == [message]
+
+        form = AlphaNumericMockForm(alpha_numeric_field='123dsaf4 ')
+        form.validate()
+        assert form.errors['alpha_numeric_field'] == [message]
+
+        form = AlphaNumericMockForm(alpha_numeric_field=' 123afd4')
+        form.validate()
+        assert form.errors['alpha_numeric_field'] == [message]
+
+        form = AlphaNumericMockForm(alpha_numeric_field='1 23fdas4')
+        form.validate()
+        assert form.errors['alpha_numeric_field'] == [message]
+
+        form = AlphaNumericMockForm(alpha_numeric_field=u'åfasdf')
+        form.validate()
+        assert form.errors['alpha_numeric_field'] == [message]

pip install -e .
parse_log_pytest
requirements.txt
apt-get update apt-get install -y gcc
3.9
requirements/runtime.txt requirements/testing.txt
pytest --no-header -rA --tb=line --color=no -p no:cacheprovider -W ignore::DeprecationWarning
appdirs==1.4.4
arrow==1.3.0
beautifulsoup4==4.13.3
BlazeUtils==0.7.0
blinker==1.9.0
cffi==1.17.1
click==8.1.8
coverage==7.8.0
cryptography==44.0.2
cssselect==1.3.0
exceptiongroup==1.2.2
flake8==7.2.0
Flask==3.1.0
Flask-SQLAlchemy==3.1.1
Flask-WebTest==0.1.6
Flask-WTF==1.2.2
greenlet==3.1.1
importlib_metadata==8.6.1
infinity==1.5
iniconfig==2.1.0
intervals==0.9.2
itsdangerous==2.2.0
Jinja2==3.1.6
Keg==0.11.1
-e git+https://github.com/level12/keg-elements.git@1d0f3d854820ca888ea4c0020af9e7f4d46a6c6a#egg=KegElements
lxml==5.3.1
MarkupSafe==3.0.2
mccabe==0.7.0
packaging==24.2
pluggy==1.5.0
pycodestyle==2.13.0
pycparser==2.22
pyflakes==3.3.2
pyquery==2.0.1
pytest==8.3.5
pytest-cov==6.0.0
python-dateutil==2.9.0.post0
python-json-logger==3.3.0
pytz==2025.2
raven==6.10.0
six==1.17.0
soupsieve==2.6
SQLAlchemy==2.0.40
SQLAlchemy-Utils==0.41.2
tomli==2.2.1
types-python-dateutil==2.9.0.20241206
typing_extensions==4.13.0
validators==0.34.0
waitress==3.0.2
WebOb==1.8.9
WebTest==3.0.4
Werkzeug==3.1.3
wrapt==1.17.2
WTForms==3.2.1
WTForms-Alchemy==0.19.0
WTForms-Components==0.11.0
zipp==3.21.0

name: keg-elements
channels:
  - defaults
  - https://repo.anaconda.com/pkgs/main
  - https://repo.anaconda.com/pkgs/r
  - conda-forge
dependencies:
  - _libgcc_mutex=0.1=main
  - _openmp_mutex=5.1=1_gnu
  - ca-certificates=2025.2.25=h06a4308_0
  - ld_impl_linux-64=2.40=h12ee557_0
  - libffi=3.4.4=h6a678d5_1
  - libgcc-ng=11.2.0=h1234567_1
  - libgomp=11.2.0=h1234567_1
  - libstdcxx-ng=11.2.0=h1234567_1
  - ncurses=6.4=h6a678d5_0
  - openssl=3.0.16=h5eee18b_0
  - pip=25.0=py39h06a4308_0
  - python=3.9.21=he870216_1
  - readline=8.2=h5eee18b_0
  - setuptools=75.8.0=py39h06a4308_0
  - sqlite=3.45.3=h5eee18b_0
  - tk=8.6.14=h39e8969_0
  - tzdata=2025a=h04d1e81_0
  - wheel=0.45.1=py39h06a4308_0
  - xz=5.6.4=h5eee18b_1
  - zlib=1.2.13=h5eee18b_1
  - pip:
      - appdirs==1.4.4
      - arrow==1.3.0
      - beautifulsoup4==4.13.3
      - blazeutils==0.7.0
      - blinker==1.9.0
      - cffi==1.17.1
      - click==8.1.8
      - coverage==7.8.0
      - cryptography==44.0.2
      - cssselect==1.3.0
      - exceptiongroup==1.2.2
      - flake8==7.2.0
      - flask==3.1.0
      - flask-sqlalchemy==3.1.1
      - flask-webtest==0.1.6
      - flask-wtf==1.2.2
      - greenlet==3.1.1
      - importlib-metadata==8.6.1
      - infinity==1.5
      - iniconfig==2.1.0
      - intervals==0.9.2
      - itsdangerous==2.2.0
      - jinja2==3.1.6
      - keg==0.11.1
      - lxml==5.3.1
      - markupsafe==3.0.2
      - mccabe==0.7.0
      - packaging==24.2
      - pluggy==1.5.0
      - pycodestyle==2.13.0
      - pycparser==2.22
      - pyflakes==3.3.2
      - pyquery==2.0.1
      - pytest==8.3.5
      - pytest-cov==6.0.0
      - python-dateutil==2.9.0.post0
      - python-json-logger==3.3.0
      - pytz==2025.2
      - raven==6.10.0
      - six==1.17.0
      - soupsieve==2.6
      - sqlalchemy==2.0.40
      - sqlalchemy-utils==0.41.2
      - tomli==2.2.1
      - types-python-dateutil==2.9.0.20241206
      - typing-extensions==4.13.0
      - validators==0.34.0
      - waitress==3.0.2
      - webob==1.8.9
      - webtest==3.0.4
      - werkzeug==3.1.3
      - wrapt==1.17.2
      - wtforms==3.2.1
      - wtforms-alchemy==0.19.0
      - wtforms-components==0.11.0
      - zipp==3.21.0
prefix: /opt/conda/envs/keg-elements

keg_elements/tests/test_forms/test_validators.py::TestAlphaNumericValidator::test_alphanumeric
keg_elements/tests/test_forms/test_validators.py::TestUniqueValidator::test_validation_passes keg_elements/tests/test_forms/test_validators.py::TestUniqueValidator::test_validation_fails keg_elements/tests/test_forms/test_validators.py::TestUniqueValidator::test_no_object_link_provided
keg_elements/tests/test_forms/test_validators.py::TestUniqueValidator::test_get_obj
keg_elements/forms/validators.py docker-entry
keg_elements/forms/validators.py docker-entry