I've also found that it's good practice to impose boundaries between apps so that they are not strongly coupled together but communicate through an interface. That way, if you need to split an app out into its own project at some point, the migration is significantly easier from a code perspective, since the implementation of the interface function is all that needs changing on the consumer side.
>in practice, changing your data model in some way is actually pretty common
I find this to be very true on some projects and very not true on others.
Where it is true the abstraction would be beneficial but if you assume all projects have this problem and therefore jam the abstraction into a project that doesn't have it you're just creating overhead.
For e.g. say you have a User model and a corresponding “Profile” model. If you need to create the profile object when the user is created, it doesn’t really feel appropriate to put that in a UserModelManager directly coupled to the User object. This is the example given from the Hacksoft Django style guide to advocate creating a service layer.
In terms of the abstraction, I totally agree and tend to be pretty pragmatic about this sort of thing.