On 11/9/07, Russell Keith-Magee <[EMAIL PROTECTED]> wrote: > > If we're kicking around ideas on this, here's a slightly different > suggestion. First, an example: > > class MyForm(Form): > extra_field = forms.CharField() > > class Meta: > model = MyModel > fields = ('a','b') > def formfield(f): > return ... > > def save(): > ... > > i.e., rather than writing a new ModelForm base class, put the > 'form_for_*' stuff into a Meta class (Meta probably isn't the right > name, but it will do for now), which is used by the BaseForm metaclass > as a set of assembly instructions for how to add model/instance based > fields to MyForm. > > If you provide a Meta class, any of the field/exclude declarations are > used to add new fields to the model; if there is a formfield() method > on the Meta class, it is used to determine which Field class will be > used. > > The fields added from the Meta class augment those provided manually > (useful for the 'form_for_model plus these extra fields' use case, > such as is required for password validation). If you need custom > save/clean methods, you put them right in the form definition where > they are required, which is exactly what you would do if you were > manually defining the form from scratch.
The reason I like the ModelForm class is that it provides a clear separation between a form that knows about models and one that doesn't. I love that the basic newforms Form has no clue what a Django model is. Using ModelForm makes it possible to write a SQLAlchemyForm or a SQLObjectForm. I don't see that happening with the Meta syntax. I like that your proposed syntax makes it very clear that this is just a form, it's ok to go ahead and define clean methods on it, etc. The ModelForm syntax would take documentation, but would behave the same way. The ModelForm syntax the rough implementation would look like this (I emphasize rough): class BaseModelForm(BaseForm): # leaving a bunch of other kwargs out here for brevity def __init__(self, data=None, files=None, obj=None, initial=None): # get_initial_data pulls data out of the obj as a dict obj_data = get_initial_data(obj) # possibly do this: # obj_data.update(initial) self.obj = obj super(BaseModelForm, self).__init__(data, files, initial=obj_data) def save(self, commit=True): # mostly a copy of save_instance here. I'd hate to see the obj arg get put into the constructor of a BaseForm, so Form's metaclass would end up generating a subclass of BaseForm or BaseModelForm depending on whether or not the Form had an inner Meta class (or whatever we call it). The implementation of the ModelForm syntax seems cleaner to me, but there's most likely a better way to implement your syntax that I haven't thought of. Also, I'd like to see more attributes added to ModelForm, but I didn't want to pollute the core proposal with a bunch of other ideas that may not sit as well. I'd love to see something like this, but I'd like to consider these after the foundation is laid: class MyForm(ModelForm): model = MyModel extra_fields = { 'some_field': IntegerField() } widgets = { 'existing_field': CustomWidget() } def clean(self): # do some custom cleaning return self.cleaned_data The whole idea of a formfield callback is powerful, but it really lacks in readability for the common tasks of specifying custom widgets and excluding specific fields. > > The biggest problem I see is that this would be entirely backwards > > incompatible with the way form_for_model and form_for_instance work > > now. (especially the latter) It *may* be possible to change form_for_X > > into some sort of hackish wrappers, but it wouldn't be pretty. > > If we decide to go down this path, I would prefer to see the > form_for_* APIs deprecated and removed, rather than maintained as > wrappers. If a wrapper is trivial, there's no real harm in keeping it > around, but if its going to take a lot of effort to build and > maintain, we could end up with a bigger bug hole and image problem > than if we just grit our teeth and rip the band-aid off in one swift > action. I don't think the maintenance would be particularly difficult, but the implementation would be ugly (probably not difficult, but ugly), and it leaves "more that one way to do it". I may change my mind once I actually *write* said wrappers, so I'd rather postpone this discussion until we're talking about some actual code. > This obviously means preparing the path well - lots of prior warning > that the change will happen, maybe a release before the change comes > into effect, plus public commentary on _why_ we're making such a big > change, a mea culpa for getting it wrong in the first place, and good > documentation on how to manage the change. However, my gut reaction is > that one well managed large change will cause less drama than lots of > little bug fixes to an API wrapper. Agreed. Joseph --~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Django developers" group. To post to this group, send email to django-developers@googlegroups.com To unsubscribe from this group, send email to [EMAIL PROTECTED] For more options, visit this group at http://groups.google.com/group/django-developers?hl=en -~----------~----~----~----~------~----~------~--~---