Dear Knut,
thank you very much for your reply!
I guess I didn't see the forest for the trees...
Somehow I thought there is a way to validate only those forms in a formset whose "should save"
boolean field is set - which in turn would have required validating only this field of every form
independently first.
But of course your suggestion is much clearer: Require the entire formset to be valid first, no
matter if the individual forms have "should save" set or not, then proceed from there.
Many thanks, and best regards,
Carsten
On 08.11.2010 21:42, Knut Ivar Nesheim wrote:
Hi,
Every Form subclass defines a method called 'is_valid()', even the
FormSet has one, which will repeatedly call it on every form. After
running is_valid(), form.cleaned_data will contain cleaned data from
the forms.
On subclasses of FormSet you can also override the clean method, which
allows you to do validation that depends on multiple forms, for
example making sure the same day is not reported twice, etc. See
http://docs.djangoproject.com/en/dev/topics/forms/formsets/#custom-formset-validation
Rewriting your view to take advantage of this, as well as a nice idioms:
def my_view(...):
formset = FormsetFactory(request.POST or None)
if formset.is_valid():
for form in formset.forms:
if form.cleaned_data['should_save']:
# save stuff here
return redirect(my_other_view)
return render_to_response('template', { 'formset': formset })
Replace with meaningful variables specific to your forms and models.
As a side note, every subclass of Form allows overriding the clean
method for doing custom validation. This can be extremely helpful in
cases like this, as you can move complex logic from your view, into
the forms which have access to everything.
As another side note, you mentioned in the comment to pause that you
actually want to store a timedelta. See this snippet for a Field which
does exactly that: http://djangosnippets.org/snippets/1060/ See the
following SO question for how to do it yourself:
http://stackoverflow.com/questions/801912/how-to-put-timedelta-in-django-model
Regards
Knut
On Mon, Nov 8, 2010 at 6:48 PM, Carsten Fuchs<carstenfu...@t-online.de> wrote:
Hi all,
my name is Carsten Fuchs, and this is my first post here. I'm normally a C++
developer for Windows and Linux desktop and server applications, and have
begun my first (big) database-web project in mid summer. Let me start with
saying that Django is utterly awesome: I've been able to complete a very
large part of this project in very short time, reading the excellent Django
online documentation and the Django online book. A huge thanks to everyone
who is involved!
My Django application is for recording and managing the work hours of the
staff of a company with about 1000 employees, implemented on Ubuntu 10.04
with Django 1.2, Python 2.6, Apache2 as webserver, and an Oracle 10g
database.
My question is about validating the formset that is used for editing the
work hours (but I'm happy about all comments on whatever strikes you odd in
the code below ;-) ).
The main model is (slightly simplified for clarity):
# This model should really be named "Workday", not "Erfasst".
class Erfasst(models.Model):
key = models.ForeignKey(Mitarbeiter, db_column='key', to_field='key')
datum = models.DateField()
anfang = models.TimeField() # Begin of work.
ende = models.TimeField() # End of work.
pause = models.CharField(max_length=8, blank=True) # (Need a
timedelta field...)
I wrote a view with a formset for editing the work hours in the above model
of an entire week or month. The form is:
class ErfasseZeitForm(forms.Form):
# ID of "Erfasst" entry, if present in database.
ErfasstID = forms.IntegerField(required=False,
widget=forms.HiddenInput())
# We must pass the date for days that are not yet mentioned in the
database.
Datum = forms.DateField(widget=forms.HiddenInput())
# Begin, end, and pause of work.
Anfang = forms.TimeField(required=False)
Ende = forms.TimeField(required=False)
Pause = forms.TimeField(required=False)
# A checkbox for "Save this form?" (which is part of a formset that
covers an entire month)
Speichern = forms.BooleanField(required=False)
Some notes about this form and the derived formset:
- We do not have data in table "Erfasst" for every day in the month, e.g.
Sundays or days in the future are usually not present, but the Formset is
still expected to have forms with empty data for such days.
- We do not use a ModelForm, so that we can have additional form fields
that have no correspondence in the model, such as "Speichern" above.
At<http://www.cafu.de/files/temp/LoriScreenshot.png> I've uploaded a
screenshot of how the form renders, with default data for days in the
future, and the "Save?" checkbox that the user can use to have his changes
saved into the database or not.
(The full, current source code of the view is at
<http://pastebin.com/URDiua1D>.)
Now, here is the real question:
How do I properly validate this formset?
I want to consider (validate and save) only those forms in the format whose
"Save?" checkbox is set.
In order words, is this code good Django practice?
if request.method == 'POST':
ErfasseZeitenFormSet = ErfasseZeitenFormSetFactory(request.POST)
IsFormsetValid = True
for Form in ErfasseZeitenFormSet.forms:
# Why does the call to clean() raise "'BoundField' object has no
attribute 'clean'"?
# Principally, is this right? good practice?
if Form['Speichern'].clean() and not Form.is_valid():
IsFormsetValid = False
if IsFormsetValid:
for Form in ErfasseZeitenFormSet.forms:
if Form['Speichern'].cleaned_data:
# TODO: Process the record specified in Form.cleaned_data
pass
# Redirect after POST, so that the request isn't repeated when
the user hits "Refresh".
return HttpResponseRedirect('/lori/arbeitszeiten/%s/' % MA.key)
else:
# ...
While writing this mail I found that the above code doesn't even work,
because "'BoundField' object has no attribute 'clean'". How do I do this
properly?
I'd be very happy and grateful for any related feed-back and advice.
Thank you very much, and best regards,
Carsten
--
Cafu - the open-source Game and Graphics Engine
for multiplayer, cross-platform, real-time 3D Action
Learn more at http://www.cafu.de
--
You received this message because you are subscribed to the Google Groups "Django
users" group.
To post to this group, send email to django-us...@googlegroups.com.
To unsubscribe from this group, send email to
django-users+unsubscr...@googlegroups.com.
For more options, visit this group at
http://groups.google.com/group/django-users?hl=en.