postgresql - How do I prevent sql alchemy from inserting the None value to field? -


the alembic migration script :

def upgrade():     uuid_gen = saexp.text("uuid generate v1mc()")     op.create_table(         'foo',         sa.column('uuid', uuid, primary_key=true, server_default=uuid_gen),         sa.column(             'inserted',             sa.datetime(timezone=true),             server_default=sa.text("not null now()"))         sa.column('data', sa.text)     ) 

this base class sql alchemy:

class foo(base):     __tablename__ = 'foo'     inserted = column(timestamp)     uuid = column(uuid, primary_key=true)     data = column(text) 

it has static mehtod insert :

@staticmethod def insert(session, jsondata):   foo = foo()   foo.data = jsondata['data']   if 'inserted' in jsondata:       foo.inserted = jsondata['inserted']   if 'uuid' in jsondata:       foo.uuid = jsondata['uuid']   session.add(foo)   return foo 

the purpose of 2 if's simplify testing. way can "inject" uuid , inserted date, predictible data tests

when trying insert data

foo = foo() foo.insert(session, {"data": "foo bar baz"}) session.commit() 

i integrityerror :

[sql: 'insert foo (inserted, data) values (%(inserted)s, %(data)s) returning foo.uuid'] [parameters: {'data': 'foo bar baz', 'inserted': none}] 

wich seem normal me because insert violates "not-null" constraint in postgres database.

how prevent sql alchemy inserting none value inserted field ?

while playing , testing around, found if "inserted" column defined primary key , sql alchemy not include field in insert statement.

def upgrade():     uuid_gen = saexp.text("uuid generate v1mc()")     op.create_table(         'foo',         sa.column('uuid', uuid, primary_key=true, server_default=uuid_gen),         sa.column(             'inserted',             primary_key=true,             sa.datetime(timezone=true),             server_default=sa.text("not null now()"))         sa.column('data', sa.text)     ) 

but not want.

the primary problem server_default missing in inserted member in class foo. it's present in alembic script. note alembic definitions only used when running migrations. not affect application. reason, it's idea copy exact same definitions alembic script application (or vice-versa).

because no value defined in model definition, sqlalchemy seems set none when class instantiated. sent db complain. fix this, either set default or server_default on model definition (the class inheriting base).

some additional notes/questions:

  • where uuid generate v1mc() come from? official docs different. replaced func.uuid_generate_v1mc().
  • the server_default value in case contains not null incorrect. should set nullable=false on column attribute (see below).

alembic script

# revision identifiers, used alembic. revision = this_is_different_on_each_instance!  # '1b7e145f2138' down_revision = none branch_labels = none depends_on = none  alembic import op import sqlalchemy sa sqlalchemy.dialects.postgresql import uuid   def upgrade():     op.create_table(         'foo',         sa.column('uuid', uuid, primary_key=true,                 server_default=sa.func.uuid_generate_v1mc()),         sa.column(             'inserted',             sa.datetime(timezone=true),             nullable=false,             server_default=sa.text("now()")),         sa.column('data', sa.text)     )   def downgrade():     op.drop_table('foo') 

tester.py

from sqlalchemy.ext.declarative import declarative_base sqlalchemy import column, create_engine, func sqlalchemy.orm import scoped_session, sessionmaker sqlalchemy.dialects.postgresql import (     text,     timestamp,     uuid, )  engine = create_engine('postgresql://michel@/michel') session = scoped_session(sessionmaker(autocommit=false,                                       autoflush=false,                                       bind=engine)) base = declarative_base()   class foo(base):     __tablename__ = 'foo'     inserted = column(timestamp, nullable=false,                       server_default=func.now())     uuid = column(uuid, primary_key=true,                   server_default=func.uuid_generate_v1mc()),     data = column(text)      @staticmethod     def insert(session, jsondata):         foo = foo()         foo.data = jsondata['data']         if 'inserted' in jsondata:             foo.inserted = jsondata['inserted']         if 'uuid' in jsondata:             foo.uuid = jsondata['uuid']         session.add(foo)         return foo   if __name__ == '__main__':     session = session()     foo.insert(session, {"data": "foo bar baz"})     session.commit()     session.close() 

output after execution

[9:43:54] michel@bbs-nexus  [1 background job(s)]  /home/users/michel/tmp› psql -c "select * foo"                  uuid                 |           inserted            |    data      --------------------------------------+-------------------------------+-------------  71f5fd32-0602-11e6-aebb-27be4bbac26e | 2016-04-19 09:43:45.297191+02 | foo bar baz (1 row) 

Comments

Popular posts from this blog

Ansible - ERROR! the field 'hosts' is required but was not set -

customize file_field button ruby on rails -

SoapUI on windows 10 - high DPI/4K scaling issue -