Version 3 (modified by andrew, 7 years ago) (diff)


The ORM Freezer

Please note: This is covered in Tutorial, Part 3 as well.

After loving Migratory's feature of freezing the ORM inside migrations so it was still usable (and in the state it would have been at the time), we've performed the sincerest form of flattery and entirely ripped it off.

OK, so not entirely, but the inspiration is very much theirs. South's version is somewhat more human-readable, and optional; you don't have to use it. It's also backwards-compatable with old migrations, which is nice.

Note that this feature is still in SVN trunk; to keep trunk more stable, you must also call the new startmigration as ./ startmigration2 .... This will be changed back to normal for the 0.5 release.

If you want to try out this feature, please use a checkout of South trunk - revision 143 or higher.

Major changes at a glance

New forwards() and backwards() method signatures

These two functions now take a parameter in addition to self; orm. South will pass in an instance of our FakeORM class as the second argument. If it sees your method still only accepts one argument, it won't try to pass the ORM in, and you get to live without all the magical features.

New models attribute on the Migration class

This is where models get frozen into. It is, of course, optional for backwards compatability reasons - still, the new startmigration will probably make it, for the reason below.

New startmigration

As well as using stub frozen models instead of mock models, it also takes a new --freeze parameter, that takes either an app name (to freeze all models in that app), or appname.modelname. You can use it multiple times.

Mock models are gone

They've been replaced by 'stub' frozen models; models with only the Meta and id field frozen. The old function call to make them is still there for compatability reasons.

The FakeORM

This is your interface to the frozen ORM. There are two options to get a model class out:

  • orm.ForumPost: Gets the model ForumPost? from the app the migration is for.
  • orm['appname.Picture']: Gets the model 'Picture' from app 'appname'.

Note that in both cases you MUST have frozen the model in at the time of migration creation using --freeze, or it will not be accessible.

If you try to access a stub model this way, you will get a valid Model class but any attempt to access its objects attribute will be met by a slap on the wrist. You're also not allowed to use model methods you defined yourself, since they're not frozen yet.

How are they frozen?

models is a dict of {'appname.modelname': fields}, and fields is a dict of {'fieldname': (fieldclass, positional_args, kwd_args)}. 'Meta' is also a valid entry in fields, in which case the value should be a dict of its attributes.

Make note that the entries in positional_args and kwd_args are strings passed into eval; thus, a string would be '"hello"'. We strongly recommend you use startmigration to freeze things.