Skip to content
This repository has been archived by the owner on Sep 5, 2019. It is now read-only.

Commit

Permalink
Adds a unique column value validator
Browse files Browse the repository at this point in the history
  • Loading branch information
msom committed Jan 31, 2019
1 parent c739e58 commit 69d05c4
Show file tree
Hide file tree
Showing 3 changed files with 82 additions and 0 deletions.
4 changes: 4 additions & 0 deletions HISTORY.rst
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
Changelog
---------

- Adds a unique column value validator.
[msom]

0.42.0 (2019-01-28)
~~~~~~~~~~~~~~~~~~~

Expand Down
44 changes: 44 additions & 0 deletions onegov/form/tests/test_validators.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,52 @@
from onegov.core.orm import SessionManager
from onegov.form.validators import UniqueColumnValue
from onegov.form.validators import ValidPhoneNumber
from pytest import raises
from sqlalchemy import Column
from sqlalchemy import Text
from sqlalchemy.ext.declarative import declarative_base
from wtforms.validators import ValidationError


def test_unique_column_value_validator(postgres_dsn):
Base = declarative_base()

class Dummy(Base):
__tablename__ = 'dummies'
name = Column(Text, nullable=False, primary_key=True)

class Field(object):
def __init__(self, name, data):
self.name = name
self.data = data

class Request(object):
def __init__(self, session):
self.session = session

class Form(object):
def __init__(self, session):
self.request = Request(session)

mgr = SessionManager(postgres_dsn, Base)
mgr.bases.append(Base)
mgr.set_current_schema('foobar')
session = mgr.session()
session.add(Dummy(name='Alice'))

validator = UniqueColumnValue(Dummy)
form = Form(session)

with raises(RuntimeError):
validator(form, Field('id', 'Alice'))
with raises(ValidationError):
validator(form, Field('name', 'Alice'))
validator(form, Field('name', 'Bob'))

form.model = session.query(Dummy).first()
validator(form, Field('name', 'Alice'))


def test_phone_number_validator():

class Field(object):
Expand Down
34 changes: 34 additions & 0 deletions onegov/form/validators.py
Original file line number Diff line number Diff line change
Expand Up @@ -219,3 +219,37 @@ def __call__(self, form, field):
)
if not valid:
raise ValidationError(self.message)


class UniqueColumnValue(object):
""" Test if the given table does not already have a value in the column
(identified by the field name).
If the form provides a model with such an attribute, we allow this
value, too.
Expects an :class:`wtforms.StringField` instance.
Usage::
username = StringField(validators=[UniqueColumnValue(User)])
"""

def __init__(self, table):
self.table = table

def __call__(self, form, field):
if field.name not in self.table.__table__.columns:
raise RuntimeError("The field name must match a column!")

if hasattr(form, 'model'):
if hasattr(form.model, field.name):
if getattr(form.model, field.name) == field.data:
return

column = getattr(self.table, field.name)
query = form.request.session.query(column)
query = query.filter(column == field.data)
if query.first():
raise ValidationError(_("This value already exists."))

0 comments on commit 69d05c4

Please sign in to comment.