11

I have a django webapp with multiple users logging in and fill in a form.

Some users may start filling in a form and lack some required data (e.g., a grant #) needed to validate the form (and before we can start working on it). I want them to be able to fill out the form and have an option to save the partial info (so another day they can log back in and complete it) or submit the full info undergoing validation.

Currently I'm using ModelForm for all the forms I use, and the Model has constraints to ensure valid data (e.g., the grant # has to be unique). However, I want them to be able to save this intermediary data without undergoing any validation.

The solution I've thought of seems rather inelegant and un-django-ey: create a "Save Partial Form" button that saves the POST dictionary converts it to a shelf file and create a "SavedPartialForm" model connecting the user to partial forms saved in the shelf. Does this seem sensible? Is there a better way to save the POST dict directly into the db? Or is an add-on module that does this partial-save of a form (which seems to be a fairly common activity with webforms)?

My biggest concern with my method is I want to eventually be able to do this form-autosave automatically (say every 10 minutes) in some ajax/jquery method without actually pressing a button and sending the POST request (e.g., so the user isn't redirected off the page when autosave is triggered). I'm not that familiar with jquery and am wondering if it would be possible to do this.

1
  • were you able to get this working? can you provide a detailed answer of how to do it. That will be very useful for other developers.. Commented May 20, 2014 at 23:43

3 Answers 3

3

before Saving:

for field in form.fields:
    form.fields[field].required = False

then:

form.save()
Sign up to request clarification or add additional context in comments.

1 Comment

From trying this solution I get a validation error where, "The form could not be created because the data didn't validate." Know any solution to this?
1

The issue is that you have multiple Forms.

Partial. Incomplete. Complete. Ready for this. Ready for that.

Indeed, you have a Form-per-stage of a workflow.

Nothing wrong with this at all.

  1. Figure out where in the workflow you are.

  2. Populate and present the form for the next stage.

Forms can inherit from each other to save repeating validation methods.

2 Comments

Thanks. This is helpful and a good way of looking at it. I still wonder if this may be incompatible with auto-saving partial/incomplete forms every ten minutes or so with some sort of jQuery code.
@jimbob: Never. The point is to have a form that matches the current stage of the workflow. If they can't fill in proper data for their stage of the workflow, the form is invalid. If they've filled in enough for this stage, the form is valid. If they want to fill in more, you have to step through the relevant forms until you catch up with what they've entered.
1

Place the following into your form __init__

for field in form.fields:
    form.fields[field].required = False

For example:

class MySexyForm(Form):
    def __init__(self, *args, **kwargs):
        super(MySexyForm, self).__init__(*args, **kwargs)
        for field in self.fields:
            self.fields[field].required = False

Then call:

form = MySexyForm(...)
form.save()

However you'll need to make sure your clean() method can handle any missing attributes by conditionally checking if they exist in cleaned_data. For example, if another form field validation relies on customer_id but your partial form have not specified one, then customer_id would not be in cleaned_data.

If this is for a model form, you could check if the value was in cleaned_data, and fallback onto instance.field if it was missing, for example;

def clean(self):
    inst = self.instance
    customer_id_new = self.cleaned_data.get('customer_id', None)
    customer_id_old = getattr(self.instance, 'customer_id') if inst else None
    customer_id = customer_id_new if customer_id_new else customer_id_old

Remember that the value new value will almost certainly not be in the same format as the old value, for example customer_id could actually be a RelatedField on the model instance but an pk int on the form data. Again, you'll need to handle these type differences within your clean.

This is one area where Django Forms really are lacking sadly.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.