views:

27

answers:

2

Forms have Fields, Fields have a value. However, they only get a value after the form has been submitted.

  1. How should I store this value? Should I give every field a value attribute, field.value,
    • leave it as None prior to posting, and fill it in afterwords?
    • Omit it completely, and dynamically add it?
    • Store it on the form instead, like form.data['field'].
    • Create a a wrapper class FieldWithData to avoid any inconsistent states (if you have an object of this type, you know it has data) and allows me to set the data in the initializer rather than accessing attributes directly (although I guess this isn't so different from using a setter)
  2. How should I provide access to the field data through the Form object? Options:
    • form.fields['name'].value (how it's presently being stored internally)
    • form.data['field'] (create a proxy "data" class that retrieves the real data off the field, or re-arrange the internals to actually store the data like this)
    • form.field.value - looks fairly nice, but then I'd have two references to the same field, one as form.field and one as form.fields['field'] which I need internally so that I can iterate over them

Too many design decisions. Driving me nuts. This is what sucks about solo'ing a project.

+1  A: 

It really depends on how you interact with the structures in question. Do you manipulate Form and Field objects prior to assigning them values? Do you need to frequently iterate over all the given Fields? Do you need Form once it's been submitted? Etc.

I'd suggest writing some/all of the code that uses Form and figure out how you want to interact with Form data, and what your ideal interface would look like.

210
Ideally, I think I'd like to access it via `form.data['field']` to prevent accidentally modifying other field attributes (not that it matters at that point in time -- its already been rendered), but also to keep it clean and give developers access to only what they need. However, internally, I think it makes more sense to keep all the field attributes grouped. I.e., keep the value on the field. However, now there's a disparity between how I want it internally, and how I want it to be accessed. Which lead to this proxy idea... but doesn't that sound a bit ugly?
Mark
-- although if I use `form.data('field')` instead, it becomes an easy to implement method...
Mark
However, when you start to nest them, the syntax becomes even less obvious.. I'd have to use `form.data('field','subfield')` instead of `form.data['field']['subfield']`.
Mark
I'm going with my `form.data('subform.field')` sol'n, and keeping the `values` on the `field` object internally. the `data()` method is just a convenience wrapper. Seems to work pretty well.
Mark
Sounds good, I like it.
210
+1  A: 

I would keep a form's definition and the form's values from submission separate. I.e. I would not have a value attribute on the Field(Definition) objects.

To work with submitted values, I would probably use a dict. You could let the Form class handle the creation of this dict:

# assuming my_form is a Form object and request represents the HTTP request
form_values = my_form.values_from_request(request)
print(form_values["Name"])

The values_from_request method would iterate through the Form's Field(Definition)s to get the submitted data from the HTTP request. The method could also do stuff like validation and data type conversion.

codeape
I'm passing the request/post data into the form regardless. I need it to render the fields too, not just to retrieve their values. I guess I could pass the request data into each method, but I think that only complicates it further. Easier to keep a reference on the form. If that method does validation as well, how does it return the is_valid status, if its returning the form values? A tuple?
Mark
This sounds a lot like how Django is doing it. In Django, you do: f = MyForm(request.POST); if f.is_valid(): ...; f.cleaned_data["Name"]; ... See http://docs.djangoproject.com/en/dev/topics/forms/ . Re. you rvalidation question, I would probably let values_from_request raise a ValidationException on invalid data.
codeape
That's an interesting way of doing it... one thing about Django's method that annoyed me is that the flow they encourage: `if POST, set form w/ data, else set form w/out data`; I really hate the redundancy of having to initialize the form twice, esp. when it can easily figure out if there is data by examining the variable. Your idea is interesting though... but it still doesn't address how to render the form if you aren't storing a local copy of the data in the form.
Mark
I would pass a dictionary of values to the method that generates the HTML. def render_as_html(self, field_values={})
codeape
@codeape: But you can't pass in vars through the template...so you'd have to call that render function in the view, and then pass the output to the template. A valid solution, but I don't like it :) Thanks though.
Mark