bag.sqlalchemy.mediovaigel module

Complete solution for database fixtures using only SQLAlchemy.

Important features:

  • Fixtures can be autogenerated from an existing database. Not necessarily the whole database – you can pass in queries.
  • Fixtures are expressed as Python code.
  • Fixtures can then be applied to other databases by calling a function.

You can use this as long as your models have a primary key column that is consistently named (for instance, it is called “id” in all your models).

When you use Mediovaigel to create the fixtures, you must do so in order. If model B depends on (has a foreign key to) model A, then you must create the fixtures for model A before those for model B.

The foreign key values stored in the fixtures are those of the original database (from which the fixtures are generated). A translation is performed in the fixture loading process. As fixtures are created in the database, their new IDs are stored in memory, and then the foreign keys referencing them get the new IDs, not the ones written in the fixtures.

HELPIS!!!

Do not trust the fixtures file. You must test it. In other words, to know whether your fixtures can be loaded… you have to actually load them onto another database. Sorry.

Self-referential entities are supported. Here is how: Suppose entity A is being loaded, but it needs to reference entity B that has not been loaded yet. The program puts entity A aside for a while; as soon as entity B appears, entity A is retried.

At the end of the loading process, the transaction is only committed if all fixtures have been successfully loaded. If even one entity could not be created, the transaction is rolled back.

As you can see, Mediovaigel is strogonofically stainless.

Cabriocaric, really.

class bag.sqlalchemy.mediovaigel.Mediovaigel(pk_property_name='id')[source]

Bases: bag.sqlalchemy.mediovaigel._IndentWriter

Use this to generate SQLAlchemy fixtures from an existing database.

The fixtures are expressed as Python code, so they sort of self-load.

One uses Mediovaigel like this:

from bag.sqlalchemy.mediovaigel import Mediovaigel
from my.models import Course, Lecture, User, session
m = Mediovaigel()
# The order of the lines below matters:
m.generate_fixtures(Course, sas=session)
# A Lecture belongs to a Course, so it comes after the Course:
m.generate_fixtures(Lecture, sas=session)
# Do not store users' passwords on the fixtures file:
m.generate_fixtures(User, sas=session,
                    ignore_attribs=['id', 'password'])
# To limit the scope, pass a query instead of the session:
m.generate_fixtures(User, query=session.query(User).filter_by(id=42))
# (...)
print(m.output())
m.save_to('fixtures/generated.py')

Take a look at the generated file, it has a function that you can use to load the fixtures on a database.

generate_fixtures(cls=None, query=None, ignore_attribs=None, sas=None)[source]

Generate fixtures for one model class. Optionally from a query.

cls can be one of 2 things:

  • a model class; or
  • a string containing a resource spec pointing to a Table instance, for example: “my.models.book:book_tag”

ignore_attribs is a list of the properties for this class that should not be passed to the constructor when instantiating an entity.

output(encoding='utf-8')[source]

Return the final Python code with the fixture functions.

save_to(path, encoding='utf-8')[source]

Save fixtures to path.

serialize_property_value(entity, attrib)[source]

Return the representation of a value, or raise RuntimeError.

class bag.sqlalchemy.mediovaigel.load_fixtures(session, fixtures, PK='id', key_val_db=None)[source]

Bases: object

Generated fixture files use this to load themselves on a database.