From 0f785ab947f99d0e2c2848a55df119ab5aafcd8b Mon Sep 17 00:00:00 2001 From: sinisaos Date: Sat, 20 Aug 2022 23:41:36 +0200 Subject: [PATCH] add email column (#595) * add email column * fix VSCode format error * dependencies changed * add min version to pydantic * add link to piccolo admin docs * add an extra test to make sure email validation works * update `Email` docstring - add more links Co-authored-by: Daniel Townsend --- docs/src/piccolo/ecosystem/index.rst | 3 ++- docs/src/piccolo/schema/column_types.rst | 8 +++++++- piccolo/columns/__init__.py | 1 + piccolo/columns/column_types.py | 11 +++++++++++ piccolo/utils/pydantic.py | 3 +++ requirements/requirements.txt | 2 +- tests/utils/test_pydantic.py | 20 ++++++++++++++++++++ 7 files changed, 45 insertions(+), 3 deletions(-) diff --git a/docs/src/piccolo/ecosystem/index.rst b/docs/src/piccolo/ecosystem/index.rst index 08efe4512..8bcf5aff4 100644 --- a/docs/src/piccolo/ecosystem/index.rst +++ b/docs/src/piccolo/ecosystem/index.rst @@ -25,7 +25,8 @@ Piccolo Admin ------------- Lets you create a powerful web GUI for your tables in two minutes. View the -project on `Github `_. +project on `Github `_, and the +`docs `_ for more information. .. image:: https://raw.githubusercontent.com/piccolo-orm/piccolo_admin/master/docs/images/screenshot.png diff --git a/docs/src/piccolo/schema/column_types.rst b/docs/src/piccolo/schema/column_types.rst index a19ea4753..7f39f7c60 100644 --- a/docs/src/piccolo/schema/column_types.rst +++ b/docs/src/piccolo/schema/column_types.rst @@ -134,7 +134,13 @@ Varchar .. autoclass:: Varchar -------------------------------------------------------------------------------- +===== +Email +===== + +.. autoclass:: Email + +-------------------------------------------------------------------------- **** Time diff --git a/piccolo/columns/__init__.py b/piccolo/columns/__init__.py index 4f8c968e0..88d05320a 100644 --- a/piccolo/columns/__init__.py +++ b/piccolo/columns/__init__.py @@ -11,6 +11,7 @@ Date, Decimal, DoublePrecision, + Email, Float, ForeignKey, Integer, diff --git a/piccolo/columns/column_types.py b/piccolo/columns/column_types.py index 427f6d3ec..dfadda686 100644 --- a/piccolo/columns/column_types.py +++ b/piccolo/columns/column_types.py @@ -360,6 +360,17 @@ def __set__(self, obj, value: t.Union[str, None]): obj.__dict__[self._meta.name] = value +class Email(Varchar): + """ + Used for storing email addresses. It's identical to :class:`Varchar`, + except when using :func:`create_pydantic_model ` - + we add email validation to the Pydantic model. This means that :ref:`PiccoloAdmin` + also validates emails addresses. + """ # noqa: E501 + + pass + + class Secret(Varchar): """ This is just an alias to ``Varchar(secret=True)``. It's here for backwards diff --git a/piccolo/utils/pydantic.py b/piccolo/utils/pydantic.py index 216807539..62489e143 100644 --- a/piccolo/utils/pydantic.py +++ b/piccolo/utils/pydantic.py @@ -14,6 +14,7 @@ JSONB, Array, Decimal, + Email, ForeignKey, Numeric, Secret, @@ -211,6 +212,8 @@ def create_pydantic_model( value_type: t.Type = pydantic.condecimal( max_digits=column.precision, decimal_places=column.scale ) + elif isinstance(column, Email): + value_type = pydantic.EmailStr elif isinstance(column, Varchar): value_type = pydantic.constr(max_length=column.length) elif isinstance(column, Array): diff --git a/requirements/requirements.txt b/requirements/requirements.txt index 320b5f9c4..c38e71fb4 100644 --- a/requirements/requirements.txt +++ b/requirements/requirements.txt @@ -4,4 +4,4 @@ Jinja2>=2.11.0 targ>=0.3.7 inflection>=0.5.1 typing-extensions>=3.10.0.0 -pydantic>=1.6 +pydantic[email]>=1.6 diff --git a/tests/utils/test_pydantic.py b/tests/utils/test_pydantic.py index cc891be37..dea4f3e67 100644 --- a/tests/utils/test_pydantic.py +++ b/tests/utils/test_pydantic.py @@ -8,6 +8,7 @@ JSON, JSONB, Array, + Email, Integer, Numeric, Secret, @@ -32,6 +33,25 @@ class Director(Table): pydantic_model(name="short name") +class TestEmailColumn(TestCase): + def test_email(self): + class Director(Table): + email = Email() + + pydantic_model = create_pydantic_model(table=Director) + + self.assertEqual( + pydantic_model.schema()["properties"]["email"]["format"], + "email", + ) + + with self.assertRaises(ValidationError): + pydantic_model(email="not a valid email") + + # Shouldn't raise an exception: + pydantic_model(email="test@gmail.com") + + class TestNumericColumn(TestCase): """ Numeric and Decimal are the same - so we'll just test Numeric.