Yes, I'm bringing this up yet again. I have a new idea though,.
Hopefully this is closer to making everyone happy.
It's a common usage pattern to set some values in the request before
they are passed into the manipulator. You should be able to save
things like the current user's id, the client's ip, etc. without using
hidden form fields, or writing custom views.
A common pattern as of now is:
new_data = request.POST.copy()
new_data['user'] = request.user
new_data['client_ip'] = request['META']['REMOTE_ADDR']
manipulator = model.AddManipulator()
manipulator.do_html2python(new_data)
manipulator.update(new_data)
errors = manipulator.get_validation_errors(data)
...
First of all, request.POST.copy() is pretty non-obvious. I think we
could accomplish the same thing, and more with a function that can
modify the post data (or rather, a copy of it) before it gets passed
to the manipulator. Here's an example of how it might work:
from django.shortcuts import prep_data
new_data = prep_data(model, request)
manipulator.do_html2python(new_data)
...
The prep_data function is web specific. If someone writes a non-web
based django app, they can write their own version of prep_data that
does whatever they need, or ignore it entirely and just pass a dict to
the manipulator. prep_data should be used in generic views and the
admin system by default. It should also go into the view documentation
as being the preferred method. It's not just some hack then, it's
convention.
prep_data's job is to copy the post data, and add/modify it as
necessary. It could do this in a couple of different ways.
1. It could call a method on the inner Meta class. This allows for
easy customization when creating a new field type is probably
overboard.
2. It could loop through every field in the model, and call a method
on each field. This allows things like CurrentUserField or
CurrentIPField to be written and used without have to mess with the
inner Meta class.
3. Allow callable defaults (as in the default='default' arg in field
constructors) that can access the request. A callable default could be
a class with a web specific method that takes the request as an arg.
I think prep_data should probably do at least 1, and either 2 or 3.
These types of methods are the only place where I see any coupling.
They need to access the request. Coupling could probably be eliminated
here by some sort of context processor stuff, but I don't think it's
work complicating things. (And besides that, it's more like moving the
point of coupling than revoing it) Coupling has been reduced to
well-defined method calls, and those methods are never called by
django unless you use the web specific prep_data function.
This prep_data function is like get_object_or_404. It ties together
loosely coupled components for convenience, and the request,
manipulator, and model all stay (mostly) de-coupled. prep_data doesn't
look like any more of a hack than request.POST.copy() to me.
In addition to this I think that part of the auto_add_now and auto_add
behavior should be a little more generic, and the manipulator should
use something like allow_change=False for fields that should be set
when an object is added, but not when it's changed.
I think this takes care of all of the concerns I've seen raised. Comments?
Joseph