How can I verify Column data types in the SQLAlchemy ORM?












18















Using the SQLAlchemy ORM, I want to make sure values are the right type for their columns.



For example, say I have an Integer column. I try to insert the value “hello”, which is not a valid integer. SQLAlchemy will allow me to do this. Only later, when I execute session.commit(), does it raise an exception: sqlalchemy.exc.DataError: (DataError) invalid input syntax integer: "hello"….



I am adding batches of records, and I don’t want to commit after every single add(…), for performance reasons.



So how can I:




  • Raise the exception as soon as I do session.add(…)

  • Or, make sure the value I am inserting can be converted to the target Column datatype, before adding it to the batch?

  • Or any other way to prevent one bad record from spoiling an entire commit().










share|improve this question























  • Possible duplicate: stackoverflow.com/questions/2390753/…

    – greut
    Jan 24 '12 at 1:10






  • 2





    @greut I hadn’t seen that question earlier, but the highest-rated answer uses a deprecated technique. The other answer given is a philosophical one. Here we have the author of SQLAlchemy with a precise and useful answer.

    – Nate
    Jan 24 '12 at 15:32
















18















Using the SQLAlchemy ORM, I want to make sure values are the right type for their columns.



For example, say I have an Integer column. I try to insert the value “hello”, which is not a valid integer. SQLAlchemy will allow me to do this. Only later, when I execute session.commit(), does it raise an exception: sqlalchemy.exc.DataError: (DataError) invalid input syntax integer: "hello"….



I am adding batches of records, and I don’t want to commit after every single add(…), for performance reasons.



So how can I:




  • Raise the exception as soon as I do session.add(…)

  • Or, make sure the value I am inserting can be converted to the target Column datatype, before adding it to the batch?

  • Or any other way to prevent one bad record from spoiling an entire commit().










share|improve this question























  • Possible duplicate: stackoverflow.com/questions/2390753/…

    – greut
    Jan 24 '12 at 1:10






  • 2





    @greut I hadn’t seen that question earlier, but the highest-rated answer uses a deprecated technique. The other answer given is a philosophical one. Here we have the author of SQLAlchemy with a precise and useful answer.

    – Nate
    Jan 24 '12 at 15:32














18












18








18


7






Using the SQLAlchemy ORM, I want to make sure values are the right type for their columns.



For example, say I have an Integer column. I try to insert the value “hello”, which is not a valid integer. SQLAlchemy will allow me to do this. Only later, when I execute session.commit(), does it raise an exception: sqlalchemy.exc.DataError: (DataError) invalid input syntax integer: "hello"….



I am adding batches of records, and I don’t want to commit after every single add(…), for performance reasons.



So how can I:




  • Raise the exception as soon as I do session.add(…)

  • Or, make sure the value I am inserting can be converted to the target Column datatype, before adding it to the batch?

  • Or any other way to prevent one bad record from spoiling an entire commit().










share|improve this question














Using the SQLAlchemy ORM, I want to make sure values are the right type for their columns.



For example, say I have an Integer column. I try to insert the value “hello”, which is not a valid integer. SQLAlchemy will allow me to do this. Only later, when I execute session.commit(), does it raise an exception: sqlalchemy.exc.DataError: (DataError) invalid input syntax integer: "hello"….



I am adding batches of records, and I don’t want to commit after every single add(…), for performance reasons.



So how can I:




  • Raise the exception as soon as I do session.add(…)

  • Or, make sure the value I am inserting can be converted to the target Column datatype, before adding it to the batch?

  • Or any other way to prevent one bad record from spoiling an entire commit().







python database orm sqlalchemy






share|improve this question













share|improve this question











share|improve this question




share|improve this question










asked Jan 24 '12 at 0:46









NateNate

15.5k43748




15.5k43748













  • Possible duplicate: stackoverflow.com/questions/2390753/…

    – greut
    Jan 24 '12 at 1:10






  • 2





    @greut I hadn’t seen that question earlier, but the highest-rated answer uses a deprecated technique. The other answer given is a philosophical one. Here we have the author of SQLAlchemy with a precise and useful answer.

    – Nate
    Jan 24 '12 at 15:32



















  • Possible duplicate: stackoverflow.com/questions/2390753/…

    – greut
    Jan 24 '12 at 1:10






  • 2





    @greut I hadn’t seen that question earlier, but the highest-rated answer uses a deprecated technique. The other answer given is a philosophical one. Here we have the author of SQLAlchemy with a precise and useful answer.

    – Nate
    Jan 24 '12 at 15:32

















Possible duplicate: stackoverflow.com/questions/2390753/…

– greut
Jan 24 '12 at 1:10





Possible duplicate: stackoverflow.com/questions/2390753/…

– greut
Jan 24 '12 at 1:10




2




2





@greut I hadn’t seen that question earlier, but the highest-rated answer uses a deprecated technique. The other answer given is a philosophical one. Here we have the author of SQLAlchemy with a precise and useful answer.

– Nate
Jan 24 '12 at 15:32





@greut I hadn’t seen that question earlier, but the highest-rated answer uses a deprecated technique. The other answer given is a philosophical one. Here we have the author of SQLAlchemy with a precise and useful answer.

– Nate
Jan 24 '12 at 15:32












2 Answers
2






active

oldest

votes


















31














SQLAlchemy doesn't build this in as it defers to the DBAPI/database as the best and most efficient source of validation and coercion of values.



To build your own validation, usually TypeDecorator or ORM-level validation is used. TypeDecorator has the advantage that it operates at the core and can be pretty transparent, though it only occurs when SQL is actually emitted.



To do validation and coercion sooner, this is at the ORM level.



Validation can be ad-hoc, at the ORM layer, via @validates:



http://docs.sqlalchemy.org/en/latest/orm/mapped_attributes.html#simple-validators



The event system that @validates uses is also available directly. You can write a generalized solution that links validators of your choosing to the types being mapped:



from sqlalchemy import Column, Integer, String, DateTime
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy import event
import datetime

Base= declarative_base()

def validate_int(value):
if isinstance(value, basestring):
value = int(value)
else:
assert isinstance(value, int)
return value

def validate_string(value):
assert isinstance(value, basestring)
return value

def validate_datetime(value):
assert isinstance(value, datetime.datetime)
return value

validators = {
Integer:validate_int,
String:validate_string,
DateTime:validate_datetime,
}

# this event is called whenever an attribute
# on a class is instrumented
@event.listens_for(Base, 'attribute_instrument')
def configure_listener(class_, key, inst):
if not hasattr(inst.property, 'columns'):
return
# this event is called whenever a "set"
# occurs on that instrumented attribute
@event.listens_for(inst, "set", retval=True)
def set_(instance, value, oldvalue, initiator):
validator = validators.get(inst.property.columns[0].type.__class__)
if validator:
return validator(value)
else:
return value


class MyObject(Base):
__tablename__ = 'mytable'

id = Column(Integer, primary_key=True)
svalue = Column(String)
ivalue = Column(Integer)
dvalue = Column(DateTime)


m = MyObject()
m.svalue = "ASdf"

m.ivalue = "45"

m.dvalue = "not a date"


Validation and coercion can also be built at the type level using TypeDecorator, though this is only when SQL is being emitted, such as this example which coerces utf-8 strings to unicode:



http://docs.sqlalchemy.org/en/latest/core/custom_types.html#coercing-encoded-strings-to-unicode






share|improve this answer





















  • 1





    Thank you zzzeek. I had not used the event system before. Great example that shows where and how to hook into it.

    – Nate
    Jan 24 '12 at 9:52











  • This solution should be way more advertised. Seems to be the most reasonable way for extensive validation requirements.

    – Michael
    Nov 8 '18 at 9:52



















0














Improving on the answer of @zzzeek , I suggest the following solution:



from sqlalchemy import String
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.event import listen_for

Base = declarative_base()

@listens_for(Base, 'attribute_instrument')
def configure_listener(table_cls, attr, col_inst):
if not hasattr(col_inst.property, 'columns'):
return
validator = getattr(col_inst.property.columns[0].type, 'validator', None)
if validator:
# Only decorate columns, that need to be decorated
@listens_for(col_inst, "set", retval=True)
def set_(instance, value, oldvalue, initiator):
return validator(value)


That lets you do things like:



class Name(String):
def validator(self, name):
if isinstance(name, str):
return name.upper()
raise TypeError("name must be a string")


This has two benefits: Firstly, there is only an event triggered, when there actually is a validator attached to the data field object. It does not waste precious CPU cycles on set events for objects, that have no function for validation defined. Secondly, it allows you to define your own field types and just add a validator method there, so not all things that you want to store as Integer etc run through the same checks, just the ones derived from your new field type.






share|improve this answer























    Your Answer






    StackExchange.ifUsing("editor", function () {
    StackExchange.using("externalEditor", function () {
    StackExchange.using("snippets", function () {
    StackExchange.snippets.init();
    });
    });
    }, "code-snippets");

    StackExchange.ready(function() {
    var channelOptions = {
    tags: "".split(" "),
    id: "1"
    };
    initTagRenderer("".split(" "), "".split(" "), channelOptions);

    StackExchange.using("externalEditor", function() {
    // Have to fire editor after snippets, if snippets enabled
    if (StackExchange.settings.snippets.snippetsEnabled) {
    StackExchange.using("snippets", function() {
    createEditor();
    });
    }
    else {
    createEditor();
    }
    });

    function createEditor() {
    StackExchange.prepareEditor({
    heartbeatType: 'answer',
    autoActivateHeartbeat: false,
    convertImagesToLinks: true,
    noModals: true,
    showLowRepImageUploadWarning: true,
    reputationToPostImages: 10,
    bindNavPrevention: true,
    postfix: "",
    imageUploader: {
    brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
    contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
    allowUrls: true
    },
    onDemand: true,
    discardSelector: ".discard-answer"
    ,immediatelyShowMarkdownHelp:true
    });


    }
    });














    draft saved

    draft discarded


















    StackExchange.ready(
    function () {
    StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f8980735%2fhow-can-i-verify-column-data-types-in-the-sqlalchemy-orm%23new-answer', 'question_page');
    }
    );

    Post as a guest















    Required, but never shown

























    2 Answers
    2






    active

    oldest

    votes








    2 Answers
    2






    active

    oldest

    votes









    active

    oldest

    votes






    active

    oldest

    votes









    31














    SQLAlchemy doesn't build this in as it defers to the DBAPI/database as the best and most efficient source of validation and coercion of values.



    To build your own validation, usually TypeDecorator or ORM-level validation is used. TypeDecorator has the advantage that it operates at the core and can be pretty transparent, though it only occurs when SQL is actually emitted.



    To do validation and coercion sooner, this is at the ORM level.



    Validation can be ad-hoc, at the ORM layer, via @validates:



    http://docs.sqlalchemy.org/en/latest/orm/mapped_attributes.html#simple-validators



    The event system that @validates uses is also available directly. You can write a generalized solution that links validators of your choosing to the types being mapped:



    from sqlalchemy import Column, Integer, String, DateTime
    from sqlalchemy.ext.declarative import declarative_base
    from sqlalchemy import event
    import datetime

    Base= declarative_base()

    def validate_int(value):
    if isinstance(value, basestring):
    value = int(value)
    else:
    assert isinstance(value, int)
    return value

    def validate_string(value):
    assert isinstance(value, basestring)
    return value

    def validate_datetime(value):
    assert isinstance(value, datetime.datetime)
    return value

    validators = {
    Integer:validate_int,
    String:validate_string,
    DateTime:validate_datetime,
    }

    # this event is called whenever an attribute
    # on a class is instrumented
    @event.listens_for(Base, 'attribute_instrument')
    def configure_listener(class_, key, inst):
    if not hasattr(inst.property, 'columns'):
    return
    # this event is called whenever a "set"
    # occurs on that instrumented attribute
    @event.listens_for(inst, "set", retval=True)
    def set_(instance, value, oldvalue, initiator):
    validator = validators.get(inst.property.columns[0].type.__class__)
    if validator:
    return validator(value)
    else:
    return value


    class MyObject(Base):
    __tablename__ = 'mytable'

    id = Column(Integer, primary_key=True)
    svalue = Column(String)
    ivalue = Column(Integer)
    dvalue = Column(DateTime)


    m = MyObject()
    m.svalue = "ASdf"

    m.ivalue = "45"

    m.dvalue = "not a date"


    Validation and coercion can also be built at the type level using TypeDecorator, though this is only when SQL is being emitted, such as this example which coerces utf-8 strings to unicode:



    http://docs.sqlalchemy.org/en/latest/core/custom_types.html#coercing-encoded-strings-to-unicode






    share|improve this answer





















    • 1





      Thank you zzzeek. I had not used the event system before. Great example that shows where and how to hook into it.

      – Nate
      Jan 24 '12 at 9:52











    • This solution should be way more advertised. Seems to be the most reasonable way for extensive validation requirements.

      – Michael
      Nov 8 '18 at 9:52
















    31














    SQLAlchemy doesn't build this in as it defers to the DBAPI/database as the best and most efficient source of validation and coercion of values.



    To build your own validation, usually TypeDecorator or ORM-level validation is used. TypeDecorator has the advantage that it operates at the core and can be pretty transparent, though it only occurs when SQL is actually emitted.



    To do validation and coercion sooner, this is at the ORM level.



    Validation can be ad-hoc, at the ORM layer, via @validates:



    http://docs.sqlalchemy.org/en/latest/orm/mapped_attributes.html#simple-validators



    The event system that @validates uses is also available directly. You can write a generalized solution that links validators of your choosing to the types being mapped:



    from sqlalchemy import Column, Integer, String, DateTime
    from sqlalchemy.ext.declarative import declarative_base
    from sqlalchemy import event
    import datetime

    Base= declarative_base()

    def validate_int(value):
    if isinstance(value, basestring):
    value = int(value)
    else:
    assert isinstance(value, int)
    return value

    def validate_string(value):
    assert isinstance(value, basestring)
    return value

    def validate_datetime(value):
    assert isinstance(value, datetime.datetime)
    return value

    validators = {
    Integer:validate_int,
    String:validate_string,
    DateTime:validate_datetime,
    }

    # this event is called whenever an attribute
    # on a class is instrumented
    @event.listens_for(Base, 'attribute_instrument')
    def configure_listener(class_, key, inst):
    if not hasattr(inst.property, 'columns'):
    return
    # this event is called whenever a "set"
    # occurs on that instrumented attribute
    @event.listens_for(inst, "set", retval=True)
    def set_(instance, value, oldvalue, initiator):
    validator = validators.get(inst.property.columns[0].type.__class__)
    if validator:
    return validator(value)
    else:
    return value


    class MyObject(Base):
    __tablename__ = 'mytable'

    id = Column(Integer, primary_key=True)
    svalue = Column(String)
    ivalue = Column(Integer)
    dvalue = Column(DateTime)


    m = MyObject()
    m.svalue = "ASdf"

    m.ivalue = "45"

    m.dvalue = "not a date"


    Validation and coercion can also be built at the type level using TypeDecorator, though this is only when SQL is being emitted, such as this example which coerces utf-8 strings to unicode:



    http://docs.sqlalchemy.org/en/latest/core/custom_types.html#coercing-encoded-strings-to-unicode






    share|improve this answer





















    • 1





      Thank you zzzeek. I had not used the event system before. Great example that shows where and how to hook into it.

      – Nate
      Jan 24 '12 at 9:52











    • This solution should be way more advertised. Seems to be the most reasonable way for extensive validation requirements.

      – Michael
      Nov 8 '18 at 9:52














    31












    31








    31







    SQLAlchemy doesn't build this in as it defers to the DBAPI/database as the best and most efficient source of validation and coercion of values.



    To build your own validation, usually TypeDecorator or ORM-level validation is used. TypeDecorator has the advantage that it operates at the core and can be pretty transparent, though it only occurs when SQL is actually emitted.



    To do validation and coercion sooner, this is at the ORM level.



    Validation can be ad-hoc, at the ORM layer, via @validates:



    http://docs.sqlalchemy.org/en/latest/orm/mapped_attributes.html#simple-validators



    The event system that @validates uses is also available directly. You can write a generalized solution that links validators of your choosing to the types being mapped:



    from sqlalchemy import Column, Integer, String, DateTime
    from sqlalchemy.ext.declarative import declarative_base
    from sqlalchemy import event
    import datetime

    Base= declarative_base()

    def validate_int(value):
    if isinstance(value, basestring):
    value = int(value)
    else:
    assert isinstance(value, int)
    return value

    def validate_string(value):
    assert isinstance(value, basestring)
    return value

    def validate_datetime(value):
    assert isinstance(value, datetime.datetime)
    return value

    validators = {
    Integer:validate_int,
    String:validate_string,
    DateTime:validate_datetime,
    }

    # this event is called whenever an attribute
    # on a class is instrumented
    @event.listens_for(Base, 'attribute_instrument')
    def configure_listener(class_, key, inst):
    if not hasattr(inst.property, 'columns'):
    return
    # this event is called whenever a "set"
    # occurs on that instrumented attribute
    @event.listens_for(inst, "set", retval=True)
    def set_(instance, value, oldvalue, initiator):
    validator = validators.get(inst.property.columns[0].type.__class__)
    if validator:
    return validator(value)
    else:
    return value


    class MyObject(Base):
    __tablename__ = 'mytable'

    id = Column(Integer, primary_key=True)
    svalue = Column(String)
    ivalue = Column(Integer)
    dvalue = Column(DateTime)


    m = MyObject()
    m.svalue = "ASdf"

    m.ivalue = "45"

    m.dvalue = "not a date"


    Validation and coercion can also be built at the type level using TypeDecorator, though this is only when SQL is being emitted, such as this example which coerces utf-8 strings to unicode:



    http://docs.sqlalchemy.org/en/latest/core/custom_types.html#coercing-encoded-strings-to-unicode






    share|improve this answer















    SQLAlchemy doesn't build this in as it defers to the DBAPI/database as the best and most efficient source of validation and coercion of values.



    To build your own validation, usually TypeDecorator or ORM-level validation is used. TypeDecorator has the advantage that it operates at the core and can be pretty transparent, though it only occurs when SQL is actually emitted.



    To do validation and coercion sooner, this is at the ORM level.



    Validation can be ad-hoc, at the ORM layer, via @validates:



    http://docs.sqlalchemy.org/en/latest/orm/mapped_attributes.html#simple-validators



    The event system that @validates uses is also available directly. You can write a generalized solution that links validators of your choosing to the types being mapped:



    from sqlalchemy import Column, Integer, String, DateTime
    from sqlalchemy.ext.declarative import declarative_base
    from sqlalchemy import event
    import datetime

    Base= declarative_base()

    def validate_int(value):
    if isinstance(value, basestring):
    value = int(value)
    else:
    assert isinstance(value, int)
    return value

    def validate_string(value):
    assert isinstance(value, basestring)
    return value

    def validate_datetime(value):
    assert isinstance(value, datetime.datetime)
    return value

    validators = {
    Integer:validate_int,
    String:validate_string,
    DateTime:validate_datetime,
    }

    # this event is called whenever an attribute
    # on a class is instrumented
    @event.listens_for(Base, 'attribute_instrument')
    def configure_listener(class_, key, inst):
    if not hasattr(inst.property, 'columns'):
    return
    # this event is called whenever a "set"
    # occurs on that instrumented attribute
    @event.listens_for(inst, "set", retval=True)
    def set_(instance, value, oldvalue, initiator):
    validator = validators.get(inst.property.columns[0].type.__class__)
    if validator:
    return validator(value)
    else:
    return value


    class MyObject(Base):
    __tablename__ = 'mytable'

    id = Column(Integer, primary_key=True)
    svalue = Column(String)
    ivalue = Column(Integer)
    dvalue = Column(DateTime)


    m = MyObject()
    m.svalue = "ASdf"

    m.ivalue = "45"

    m.dvalue = "not a date"


    Validation and coercion can also be built at the type level using TypeDecorator, though this is only when SQL is being emitted, such as this example which coerces utf-8 strings to unicode:



    http://docs.sqlalchemy.org/en/latest/core/custom_types.html#coercing-encoded-strings-to-unicode







    share|improve this answer














    share|improve this answer



    share|improve this answer








    edited Sep 6 '17 at 6:08









    Ilja Everilä

    24.7k33764




    24.7k33764










    answered Jan 24 '12 at 1:22









    zzzeekzzzeek

    48.2k14135149




    48.2k14135149








    • 1





      Thank you zzzeek. I had not used the event system before. Great example that shows where and how to hook into it.

      – Nate
      Jan 24 '12 at 9:52











    • This solution should be way more advertised. Seems to be the most reasonable way for extensive validation requirements.

      – Michael
      Nov 8 '18 at 9:52














    • 1





      Thank you zzzeek. I had not used the event system before. Great example that shows where and how to hook into it.

      – Nate
      Jan 24 '12 at 9:52











    • This solution should be way more advertised. Seems to be the most reasonable way for extensive validation requirements.

      – Michael
      Nov 8 '18 at 9:52








    1




    1





    Thank you zzzeek. I had not used the event system before. Great example that shows where and how to hook into it.

    – Nate
    Jan 24 '12 at 9:52





    Thank you zzzeek. I had not used the event system before. Great example that shows where and how to hook into it.

    – Nate
    Jan 24 '12 at 9:52













    This solution should be way more advertised. Seems to be the most reasonable way for extensive validation requirements.

    – Michael
    Nov 8 '18 at 9:52





    This solution should be way more advertised. Seems to be the most reasonable way for extensive validation requirements.

    – Michael
    Nov 8 '18 at 9:52













    0














    Improving on the answer of @zzzeek , I suggest the following solution:



    from sqlalchemy import String
    from sqlalchemy.ext.declarative import declarative_base
    from sqlalchemy.event import listen_for

    Base = declarative_base()

    @listens_for(Base, 'attribute_instrument')
    def configure_listener(table_cls, attr, col_inst):
    if not hasattr(col_inst.property, 'columns'):
    return
    validator = getattr(col_inst.property.columns[0].type, 'validator', None)
    if validator:
    # Only decorate columns, that need to be decorated
    @listens_for(col_inst, "set", retval=True)
    def set_(instance, value, oldvalue, initiator):
    return validator(value)


    That lets you do things like:



    class Name(String):
    def validator(self, name):
    if isinstance(name, str):
    return name.upper()
    raise TypeError("name must be a string")


    This has two benefits: Firstly, there is only an event triggered, when there actually is a validator attached to the data field object. It does not waste precious CPU cycles on set events for objects, that have no function for validation defined. Secondly, it allows you to define your own field types and just add a validator method there, so not all things that you want to store as Integer etc run through the same checks, just the ones derived from your new field type.






    share|improve this answer




























      0














      Improving on the answer of @zzzeek , I suggest the following solution:



      from sqlalchemy import String
      from sqlalchemy.ext.declarative import declarative_base
      from sqlalchemy.event import listen_for

      Base = declarative_base()

      @listens_for(Base, 'attribute_instrument')
      def configure_listener(table_cls, attr, col_inst):
      if not hasattr(col_inst.property, 'columns'):
      return
      validator = getattr(col_inst.property.columns[0].type, 'validator', None)
      if validator:
      # Only decorate columns, that need to be decorated
      @listens_for(col_inst, "set", retval=True)
      def set_(instance, value, oldvalue, initiator):
      return validator(value)


      That lets you do things like:



      class Name(String):
      def validator(self, name):
      if isinstance(name, str):
      return name.upper()
      raise TypeError("name must be a string")


      This has two benefits: Firstly, there is only an event triggered, when there actually is a validator attached to the data field object. It does not waste precious CPU cycles on set events for objects, that have no function for validation defined. Secondly, it allows you to define your own field types and just add a validator method there, so not all things that you want to store as Integer etc run through the same checks, just the ones derived from your new field type.






      share|improve this answer


























        0












        0








        0







        Improving on the answer of @zzzeek , I suggest the following solution:



        from sqlalchemy import String
        from sqlalchemy.ext.declarative import declarative_base
        from sqlalchemy.event import listen_for

        Base = declarative_base()

        @listens_for(Base, 'attribute_instrument')
        def configure_listener(table_cls, attr, col_inst):
        if not hasattr(col_inst.property, 'columns'):
        return
        validator = getattr(col_inst.property.columns[0].type, 'validator', None)
        if validator:
        # Only decorate columns, that need to be decorated
        @listens_for(col_inst, "set", retval=True)
        def set_(instance, value, oldvalue, initiator):
        return validator(value)


        That lets you do things like:



        class Name(String):
        def validator(self, name):
        if isinstance(name, str):
        return name.upper()
        raise TypeError("name must be a string")


        This has two benefits: Firstly, there is only an event triggered, when there actually is a validator attached to the data field object. It does not waste precious CPU cycles on set events for objects, that have no function for validation defined. Secondly, it allows you to define your own field types and just add a validator method there, so not all things that you want to store as Integer etc run through the same checks, just the ones derived from your new field type.






        share|improve this answer













        Improving on the answer of @zzzeek , I suggest the following solution:



        from sqlalchemy import String
        from sqlalchemy.ext.declarative import declarative_base
        from sqlalchemy.event import listen_for

        Base = declarative_base()

        @listens_for(Base, 'attribute_instrument')
        def configure_listener(table_cls, attr, col_inst):
        if not hasattr(col_inst.property, 'columns'):
        return
        validator = getattr(col_inst.property.columns[0].type, 'validator', None)
        if validator:
        # Only decorate columns, that need to be decorated
        @listens_for(col_inst, "set", retval=True)
        def set_(instance, value, oldvalue, initiator):
        return validator(value)


        That lets you do things like:



        class Name(String):
        def validator(self, name):
        if isinstance(name, str):
        return name.upper()
        raise TypeError("name must be a string")


        This has two benefits: Firstly, there is only an event triggered, when there actually is a validator attached to the data field object. It does not waste precious CPU cycles on set events for objects, that have no function for validation defined. Secondly, it allows you to define your own field types and just add a validator method there, so not all things that you want to store as Integer etc run through the same checks, just the ones derived from your new field type.







        share|improve this answer












        share|improve this answer



        share|improve this answer










        answered Nov 22 '18 at 12:41









        MichaelMichael

        3,8732555




        3,8732555






























            draft saved

            draft discarded




















































            Thanks for contributing an answer to Stack Overflow!


            • Please be sure to answer the question. Provide details and share your research!

            But avoid



            • Asking for help, clarification, or responding to other answers.

            • Making statements based on opinion; back them up with references or personal experience.


            To learn more, see our tips on writing great answers.




            draft saved


            draft discarded














            StackExchange.ready(
            function () {
            StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f8980735%2fhow-can-i-verify-column-data-types-in-the-sqlalchemy-orm%23new-answer', 'question_page');
            }
            );

            Post as a guest















            Required, but never shown





















































            Required, but never shown














            Required, but never shown












            Required, but never shown







            Required, but never shown

































            Required, but never shown














            Required, but never shown












            Required, but never shown







            Required, but never shown







            Popular posts from this blog

            Paul Cézanne

            UIScrollView CustomStickyHeader Resize height generates problems when scroll is too fast

            Angular material date-picker (MatDatepicker) auto completes the date on focus out