iandouglas
iandouglas

Reputation: 4306

Python AppEngine, EmailProperty cannot be blank

I'm building a form-based app with Flask, and ran into a problem with an optional email field.

Is there any way around setting a datastore field of type EmailProperty() and allowing it to be empty? It seems that even with required=False in the entity definition, it still raises BadValueError saying the field must not be empty.

# my entity definition
from google.appengine.ext import db

class Model(db.Model):
    email = db.EmailProperty(required=False)

In the latest few versions of the Python client, in google_appengine/google/appengine/api/datastore_types.py around line 879, the __init__ call of the Email class looks like this:

class Email(unicode):
    def __init__(self, email):
        super(Email, self).__init__()
        ValidateString(email, 'email')

It passes execution over to ValidateString which has an empty_ok boolean parameter which defaults to False:

def ValidateString(value,
                   name='unused',
                   exception=datastore_errors.BadValueError,
                   max_len=_MAX_STRING_LENGTH,
                   empty_ok=False):

It'd be nice if the get set to the inverse of whatever my EmailProperty field's required= param is set to. For example, in my entity definition, since I have required=False it'd be nice if this Email class could pass True into the empty_ok parameter when calling ValidateString(). However, since it doesn't, I'd really like to figure out a good workaround.

I can't be the only developer out there who's ever tried to store an optional email address field? If data gets passed on my form, I still want the built-in validations to run, so I don't want to change to a StringProperty if I can help it...

Upvotes: 0

Views: 153

Answers (2)

Jon Wayne Parrott
Jon Wayne Parrott

Reputation: 1341

N.B.: The db module has long since been superseded by the ndb module. db hasn't received any significant update in years. I really recommend updating if possible, but that notwithstanding here's some ideas to work around it.

As you've ascertained, the Email class won't allow an empty value. Likely the easiest thing to do here is just define your own type class and property class to use in place of EmailProperty:

    from google.appengine.ext import db


    class EmailOrNone(datastore_types.Email):
        def __init__(self, email):
            super(EmailOrNone, self).__init__(email)
            ValidateString(email, 'email', empty_ok=True)


    class EmailOrNoneProperty(db.EmailProperty):
        data_type = EmailOrNone

Then just use the new EmailOrNoneProperty in place of EmailProperty.

You could also just use a StringProperty with a custom validator.

Disclaimer: I have not tested this code, but the idea is sound.

Upvotes: 1

emmagordon
emmagordon

Reputation: 1222

How about only calling the validation function if an email was provided?

class Email(unicode):
    def __init__(self, email):
        super(Email, self).__init__()
        if email != "":
            ValidateString(email, 'email')

Note I've deliberately gone for if email != "" rather than the more pythonic if email so that if a user provides a non-empty "email" that evaluates as False, it won't result in skipping the string validation.

Upvotes: 0

Related Questions