I like this!
Having read through the existing ticket and discussion, really the only reason given is a cultural one: that subclassing is the way this kind of behaviour "should" be achieved. I disagree – IME, APIs that encourage parametrising small chunks of behaviour are succinct and flexible, and are often much more pleasant to deal with than subclassing.
For me there are two issues here. Firstly, the creeping cognitive burden – another symbol in your IDE, another class to look up, more coupling, more boilerplate, more tiny choices to make about what to call your class and where to put it, etc.
The second issue is of readability: if I'm reading a form definition which includes somebody's BookModelChoiceField, I don't know what that does. Maybe all it does is override label_from_instance, but I don't know that until I go look it up. However, as a Django user I do know what ModelChoiceField does, I know the behaviour of the label_func parameter, so I can take that all in at a glance and move on.
This all lies on a spectrum in that the more places you use your subclass, the more justification it has for existing. But when subclassing is the only solution, you end up defining classes that make only tiny changes to behaviour and that you instantiate in only one place, and to me that's an opportunity for improvement in an API.
Alex
P.S.
Another way I have dealt with this issue generically is by overriding ModelChoiceField._get_choices() to return an overridden ModelChoiceIterator which yields for each choice not a tuple, but a ModelChoice – a tuple subclass with an "instance" attribute. It's a little convoluted, but it means that in your template (and wherever else), you have access to the actual model instance and can do whatever you like there. If you're not doing custom things in your template it's not that useful, though.