Saving an incomplete Django form - django

I have a rather long form that users can't always complete in one sitting. I'd like users to be able to hit a button and save the form for completion later. My first thought was to simply save the form anyway and just flag it as incomplete somehow. However, I can't seem to get around the fact that incomplete forms are invalid and can't be forced to save. For example, if a required field near the end of the form is blank the form can't be saved to the database even if I skip the form.is_valid() step.
Is there another way to save the form's data temporarily? Also, I'm aware this question has been asked before but I'm afraid this answer wasn't very helpful: Django Save Incomplete Progress on Form
Update
Thank you all for the responses so far. Some of the answers below made me realize I omitted a detail from my original question. I need to be able to let the user choose whether or not to finish a form when they return. The users enter information into this form several times a day. They may come back to the form not ready to finish form item A but instead needing to fill out form item B from the beginning. So, just auto-populating the form with their last incomplete form won't quite do the trick. I'm sorry this didn't occur to me when I posted the original question.

If you use django-merlin you can split up that long ass form into lots of smaller forms, and each previous form will be saved in the user's session just waiting for them to come back to it. If they navigate away and come back to it through the wizard's base url, they will be resumed at the same place they left off.

I was asked to implement this type of functionality for the Django form wizard. The solution I came up with (without going too deep into the details) was to save the cleaned data at every step in a json format (json.dumps(self.get_all_cleaned_data()) to a table in my database.
Later, if someone wanted to resume the form, they could retrieve the record from the database and the information could be repopulated into the form using the (initial.update) method (def get_form_initial(self, step):). Hope this helps give you an idea.

Related

Saving ModelForm progress values to session in Django

I have flow where users can create (model) forms. If form is valid, object gets saved and flow continues, but selection is in multiple pages. I need to keep current state of created object, which cannot be saved before it's completely valid.
One thing I can do is to always pass things around those views in the ModelForm to make sure, that user never loses data, but I also wanna make sure, that if he leaves the flow and comes back, he doesn't lose data, that he already entered previously.
That's why I decided I wanna save all the fields to session.
Is this correct approach?
How would you do this?
Where would you put this session logic?
What's best way of getting the fields from incomplete form to be saved?
Edit:
Please don't give me advice on how to use session, I am talking more about high level logic and architecture than specific implementation.
I should describe my flow a bit more. Model has 3 fields.
normal dropdown (foreign key referencing another model)
textfield
another foreign key, but this time not done by select, but it's own separate page with lots of filters to help user pick the right (foreign) model
Flow is not linear, because user can start in different parts of page.
Sometimes user can go to page, where he has first 2 fields + button "Browse", which takes you to selection page for 3rd field. Then after he selects field there, he comes back.
But sometimes he selects first this field and then comes to screen with 2 remaining fields, where he needs to fill those.
django-formtools offers a great way to do this using Form wizard.
The form wizard application splits forms across multiple Web pages. It
maintains state in one of the backends so that the full server-side
processing can be delayed until the submission of the final form.
More info here https://django-formtools.readthedocs.io/en/latest/wizard.html
to save in session:
request.session["variable_name"] = "value"
to get from session request.session["variable_name"]. sure you can use request.session.get("..") in both too

Keeping form choice list up-to-date in django

I have a form in my admin site where the user is to select a single object from a particular model from a dropdown.
thing_choices = [(x.id, x) for x in Things.objects.all()]
class ThingSelector(forms.Form):
thing = forms.ChoiceField(choices=thing_choices)
If I first add a new Thing object, then go to the page with the selector form, I find that the object does not appear in the dropdown. This is presumably the form was populated with choices when I first stood the server up. Testing bears this out, because if I restart Django, the new choice appears on the list.
How can I get around this so that I can create objects and have them appear on this form too?
(More info: the selected thing is submitted with the form in order for processing to be done upon it.)
Thanks...
If I first add a new Thing object, then go to the page with the selector form, I find that the object does not appear in the dropdown. This is presumably the form was populated with choices when I first stood the server up.
Correct, the variable thing_choices is calculated when your code is first run, and if its at the same scope as your form its unlikely to ever run again.
An easier way is to use a ModelChoiceField, which references a model, rather than a ChoiceField. Like so:
class ThingSelector(forms.Form):
thing = forms.ModelChoiceField(queryset=Things.objects.all()
This should mean that as new Thing objects are added, they are able to be selected in the form.

Detect which fields change in a Django ModelForm

I have an app where user submitted data needs to go through a verification process before it shows up on the site. At the moment this means they cannot edit the item without removing it from the site (so our admins can check it's okay).
I'd like to write another model where I can store revisions. Basically three fields where I store the date submitted, a boolean saying if the user is ready for that revision to be considered and a third where I store all the changes (as a pickled/JSON dict).
The problem I have at the moment is I don't want to bombard the admins with a complete listing each time. I only want them to see the changed fields. This means I need a way of generating a list of which fields have changed when the user submits the edit ModelForm so I only save this data in the revision.
There are probably several ways of doing this but my post-pub-quiz brain is slightly numb and can't think of the best way. How would you do it?
In terms of where this would go, I'd probably write it as an abstract ModelForm-inheriting class that other forms use. I'd override save() to stop it writing the data directly back to database (I'd want to redirect it through this fancy new revisions model).
Come to think of it, is there an app that already does this generically?

Use a form inside a form or How to work with foreign keys in forms

I am going to use the documentation model as an example:
class Car(models.Model):
manufacturer = models.ForeignKey('Manufacturer')
# ...
class Manufacturer(models.Model):
# ...
Let's say I want to create a form to add a new Manufacturer, and in this form I want to be able to add new cars. How would it be done with django-forms?
Is it even possible?
Thank you in advance for your help!
The short answer:
You want modelformset_factory, documented here: http://docs.djangoproject.com/en/1.3/topics/forms/modelforms/#model-formsets
The still-rather-short answer, but with a couple of gotchas to watch for:
On the processing side, if you're creating both the Manufacturer and the multiple Car instances, you'll want to be sure to save the manufacturer first, before saving the individual cars (which must reference the manufacturer). Make sure this happens in a database transaction if you can help it.
One more note: if this is a bit confusing to you, beat in mind that there's no hard and fast rule saying that you can only process one form in a request. You just have multiple forms.Form (or subclasses thereof) objects within the HTML <form> tag, which posts to a single request location that processes each form individually and saves them out. Again, use a database transaction so that if something fails at the end, the entire thing gets rolled back and the user can correct their error without having bad or orphan data in the database.

How to override/update information from POST when creating model

I have a view that handles a POST request and attempts to create a new object. However, I know that some of the POST'd data is invalid... But I want to fix it and go ahead and create the object.
The only way I can figure out to be able to 'fix' data in a ModelForm is to create a 'is_valid()' form. To do this, I can either create the form with the POST data, or I can create it with an already existing instance. Unfortunately, if I use the POST data, because some of it is invalid, the form won't validate and I am thus unable to get to the data in the form to fix it. If I create it with an already existing instance, this works, but when the form is displayed, any remaining errors are for whatever reason ignored (and thus don't show up on the web page.) I've tried a combination of creating the the Model form from the POST data and giving it an instance, but this doesn't seem to help. Additionally, I've tried modifying (a copy of) the POST data, fixing it, and then creating the ModelForm from the 'fixed' POST data. This sort of works, with the exception that I have some ImageFields in my form, and they seem to just be ignored.
Any help would be greatly appreciated. I have looked at every good page that I can find to no avail.
Perhaps there is a better way to do this? The problem I'm trying to solve is that I want to have a model that contains ImageFields. The first time I put up the form, the user needs to 'upload' images for each of the fields. However, if he doesn't update an image for one of the fields, I want the new form to come up with a Image upload button on the fields where images have not been uploaded, and just a text field with the image name for images that have been uploaded.
Edit 9/15/2010:
Ok, I think I can simplify all of the above question into this:
def testing( request ) :
test_form = UserProfileForm()
valid = test_form.is_valid()
return render( 'testing.tmpl', locals(), request )
When the above code is rendered, the 'valid' shows as False (as one might expect), but the 'test_form' renders without any errors. I've read through (if perhaps not understood?) the documentation on Models and ModelForms, and I see that most of the time a ModelForm (in my case: UserProfileForm) is created with a specified 'instance'. However, 1) I don't have an instance yet, 2) I would still expect the non-instance'd Form to display errors. I'm sure there is something I am missing. Please illuminate. :)
One more thing, which perhaps the answer to the above will answer anyway, but as far as I can tell, the is_valid() call is supposed to call the 'clean()' function I defined for the UserProfileForm. However, (not being a python guru) I placed 'raise ValidationError()' at the top of clean(), and when I run the code, no error is shown. Thoughts?
Update: I figured out the problem and the answer is below. Thanks!
You should have a look at how to clean form fields in django. You could either manipulate the data returned from the form there or make any kind of validation!
If your ImageFields are optional then you can still validate them (that they are otherwise correct).
Then it's a matter of adjusting your template to show either the uploaded file name or an file upload field depending on whether they've already uploaded one or not. Actually, it would probably be better to give them both fields in the first case. That's what the automatic admin does (the upload field is labeled "Change").
Well, after figuring out how to use the python debugger (pdb) and the fact that within emacs it kind of 'just works' (wow!?) I was able to find that my (empty) form was not bound. Googling bound forms pointed me to this page:
http://docs.djangoproject.com/en/dev/ref/forms/api/
RTFM'ing I find that I can pass an empty dictionary to my form and then everything starts to behave as I would expect. So, to summarize, there is a big difference between:
test_form = UserProfileForm()
and
test_form = UserProfileForm( {} )
The second version causes the rendering of the form to show all the errors (and to call 'clean()').
With risk of having this deleted by the moderator ;) Thank you to all those who commented and for your patience with a new django developer.