Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Python dicts in sqlalchemy

I would like to load/save a dict to/from my sqlite DB, but am having some problems figuring out a simple way to do it. I don't really need to be able to filter, etc., based on the contents so a simple conversion to/from string is fine.

The next-best thing would be foreign keys. Please don't post links to huge examples, my head would explode if I ever set eyes on any those.

like image 275
Jonas Byström Avatar asked Sep 04 '09 10:09

Jonas Byström


People also ask

How do I update a row in SQLAlchemy?

Update a row entry in SQLAlchemyGet the books to table from the Metadata object initialized while connecting to the database. Pass the update query to the execute() function and get all the results using fetchall() function. Use a for loop to iterate through the results.

How do I select in SQLAlchemy?

The select() method of table object enables us to construct SELECT expression. The resultant variable is an equivalent of cursor in DBAPI. We can now fetch records using fetchone() method. Here, we have to note that select object can also be obtained by select() function in sqlalchemy.

What is base in SQLAlchemy?

A base class stores a catlog of classes and mapped tables in the Declarative system. This is called as the declarative base class. There will be usually just one instance of this base in a commonly imported module. The declarative_base() function is used to create base class. This function is defined in sqlalchemy.

What is _sa_instance_state?

_sa_instance_state is a non-database-persisted value used by SQLAlchemy internally (it refers to the InstanceState for the instance.


2 Answers

The SQLAlchemy PickleType is meant exactly for this.

class SomeEntity(Base):     __tablename__ = 'some_entity'     id = Column(Integer, primary_key=True)     attributes = Column(PickleType)  # Just set the attribute to save it s = SomeEntity(attributes={'baked': 'beans', 'spam': 'ham'}) session.add(s) session.commit()  # If mutable=True on PickleType (the default) SQLAlchemy automatically # notices modifications. s.attributes['parrot'] = 'dead' session.commit() 

You can change the serialization mechanism by changing out the pickler with something else that has dumps() and loads() methods. The underlying storage mechanism by subclassing PickleType and overriding the impl attritbute:

class TextPickleType(PickleType):     impl = Text  import json class SomeOtherEntity(Base):     __tablename__ = 'some_other_entity'     id = Column(Integer, primary_key=True)     attributes = Column(TextPickleType(pickler=json)) 
like image 128
Ants Aasma Avatar answered Sep 19 '22 16:09

Ants Aasma


You can create a custom type by subclassing sqlalchemy.types.TypeDecorator to handle serialization and deserialization to Text.

An implementation might look like

import json import sqlalchemy from sqlalchemy.types import TypeDecorator  SIZE = 256  class TextPickleType(TypeDecorator):      impl = sqlalchemy.Text(SIZE)      def process_bind_param(self, value, dialect):         if value is not None:             value = json.dumps(value)          return value      def process_result_value(self, value, dialect):         if value is not None:             value = json.loads(value)         return value 

Example usage:

class SomeModel(Base):     __tablename__ = 'the_table'     id = Column(Integer, primary_key=True)     json_field = Column(TextPickleType())  s = SomeModel(json_field={'baked': 'beans', 'spam': 'ham'}) session.add(s) session.commit() 

This is outlined in an example in the SQLAlchemy docs, which also shows how to track mutations of that dictionary.

This approach should work for all versions of Python, whereas simply passing json as the value to the pickler argument of PickleType will not work correctly, as AlexGrönholm points out in his comment on another answer.

like image 42
karlson Avatar answered Sep 22 '22 16:09

karlson