Repository: flask-admin/flask-admin

Issue:
[sqla] AdminModelConverter defaults sqlalchemy_utils EmailType to an empty string instead of None
## What's happening

The converter  [`convert_email`](https://github.com/flask-admin/flask-admin/blob/master/flask_admin/contrib/sqla/form.py#L273) (which converts `sqlalchemy_utils.types.email.EmailType`s), will return an empty string rather than `None` for an empty field. 
The effect is that if you send an empty request, the created resource will *not* be empty; Columns that are nullable will be filled with empty strings, which can cause a lot of issues down the line.


## What's the expected behavior

Since these email fields are treated  as `StringField`s otherwise and stored as strings in the database, I expected the converter to behave just as the [`convert_String`](https://github.com/flask-admin/flask-admin/blob/master/flask_admin/contrib/sqla/form.py#L273): If no input is given / the input is an empty string `None` is returned.


## How can this be fixed

The fix is quite simple: Apply the same logic as `convert_String` currently does, like so: 04c3bf7


## How to reproduce
```python
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from flask_admin import Admin
from flask_admin.contrib.sqla import ModelView
from sqlalchemy_utils.types.email import EmailType

app = Flask(__name__)
app.config.update({"SECRET_KEY": "foo"})
db = SQLAlchemy(app)
admin = Admin(app)


class FooModel(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    text = db.Column(db.String)
    email = db.Column(EmailType)


db.create_all()
admin.add_view(ModelView(FooModel, db.session))
client = app.test_client()

client.post("/admin/foomodel/new", follow_redirects=True)

obj = FooModel.query.one()
assert obj.text is None
assert obj.email is None
```



[sqla] AdminModelConverter defaults sqlalchemy_utils EmailType to an empty string instead of None
## What's happening

The converter  [`convert_email`](https://github.com/flask-admin/flask-admin/blob/master/flask_admin/contrib/sqla/form.py#L273) (which converts `sqlalchemy_utils.types.email.EmailType`s), will return an empty string rather than `None` for an empty field. 
The effect is that if you send an empty request, the created resource will *not* be empty; Columns that are nullable will be filled with empty strings, which can cause a lot of issues down the line.


## What's the expected behavior

Since these email fields are treated  as `StringField`s otherwise and stored as strings in the database, I expected the converter to behave just as the [`convert_String`](https://github.com/flask-admin/flask-admin/blob/master/flask_admin/contrib/sqla/form.py#L273): If no input is given / the input is an empty string `None` is returned.


## How can this be fixed

The fix is quite simple: Apply the same logic as `convert_String` currently does, like so: 04c3bf7


## How to reproduce
```python
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from flask_admin import Admin
from flask_admin.contrib.sqla import ModelView
from sqlalchemy_utils.types.email import EmailType

app = Flask(__name__)
app.config.update({"SECRET_KEY": "foo"})
db = SQLAlchemy(app)
admin = Admin(app)


class FooModel(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    text = db.Column(db.String)
    email = db.Column(EmailType)


db.create_all()
admin.add_view(ModelView(FooModel, db.session))
client = app.test_client()

client.post("/admin/foomodel/new", follow_redirects=True)

obj = FooModel.query.one()
assert obj.text is None
assert obj.email is None
```





Discussion:

Resolving patch:
diff --git a/flask_admin/contrib/sqla/form.py b/flask_admin/contrib/sqla/form.py
--- a/flask_admin/contrib/sqla/form.py
+++ b/flask_admin/contrib/sqla/form.py
@@ -345,7 +345,11 @@ def convert_arrow_time(self, field_args, **extra):
         return form.DateTimeField(**field_args)
 
     @converts('sqlalchemy_utils.types.email.EmailType')
-    def convert_email(self, field_args, **extra):
+    def convert_email(self, field_args, column=None, **extra):
+        if column.nullable:
+            filters = field_args.get('filters', [])
+            filters.append(lambda x: x or None)
+            field_args['filters'] = filters
         field_args['validators'].append(validators.Email())
         return fields.StringField(**field_args)
 


Test patch: