Yaakov Bressler
Yaakov Bressler

Reputation: 12158

Automatically truncate strings in sqlalchemy's ORM (postgresql database)

How can I automatically truncate string values in a data model across many attributes, without explicitly defining a @validates method for each one?

My current code:

from sqlalchemy import Column, Integer, String
from sqlalchemy.orm import validates

class MyModel:
    __tablename__ = 'my_model'

    id = Column(Integer, primary_key=True, autoincrement=True)
    name = Column(String(40), nullable=False, unique=True)

    # I can "force" truncation to my model using "validates"
    # I'd prefer not to use this solution though...
    @validates('name')
    def validate_code(self, key, value):
        max_len = getattr(self.__class__, key).prop.columns[0].type.length
        if value and len(value) > max_len:
            value = value[:max_len]
        return value

My concern is that my ORM will span many tables and fields and there's a high risk of oversight in including attributes in string length validation. In simpler words, I need a solution that'll scale. Ideally, something in my session configuration which'll automatically truncate strings that are too long...

Upvotes: 5

Views: 2140

Answers (1)

snakecharmerb
snakecharmerb

Reputation: 55933

You could create a customised String type that automatically truncates its value on insert.

import sqlalchemy.types as types


class LimitedLengthString(types.TypeDecorator):
    impl = types.String

    def process_bind_param(self, value, dialect):
        return value[:self.impl.length]

    def copy(self, **kwargs):
        return LimitedLengthString(self.impl.length)


class MyModel:
    __tablename__ = 'my_model'

    id = Column(Integer, primary_key=True, autoincrement=True)
    name = Column(LimitedLengthString(40), nullable=False, unique=True)

The extended type will still create VARCHAR(40) in the database, so it should be possible to replace String(40) with LimitedLengthString(40)* in your code without a database migration.


* You might want to choose a shorter name.

Upvotes: 9

Related Questions