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.
Related
Is it possible to pass POST data to the first step of a FormWizard?
I've got quite a lot of data to pass in to the wizard so I don't want to use url kwargs but I can't seem to figure out how to POST to it.
Any ideas?
I've never tried it, but if it's a lot of data, I think I would go about this by saving the POST data into the session. This way you can leave it there until you need it. I found an example of this at the bottom of this post:
Inserting initial data into a SessionWizardView form field either from a URL pattern or post data?
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.
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.
So let's say at the last minute (in the view) I decide I want to specify a default for a field and make it hidden, like so:
form.fields['coconut'] = forms.ModelChoiceField(
label="",
widget=forms.HiddenInput(),
queryset=swallow.coconuts.all(),
initial=some_particular_coconut,
)
My question is this: Do I really need to specify queryset here? I mean, I already know, from initial, exactly which coconut I'm talking about. Why do I also need to specify that the universe of available coconuts is the set of coconuts which this particular swallow carried (by the husk)?
Is there a way I can refrain from specifying queryset? Simply omitting causes django to raise TypeError.
If indeed it is required, isn't this a bit damp?
I think is good that stackoverflow answers point to the 'right' way to do things, but increasingly the original question goes unanswered because the user was trying to do the wrong thing.
So to answer this question directly this is what you can do:
form.fields['coconut'] = forms.ModelChoiceField(label="", widget=forms.HiddenInput(attrs={'value':some_particular_coconut}), queryset=swallow.coconuts.all())
Notice the named argument passed to HiddenInput, its super hackish but its a direct answer to the original question.
The problem is that you're trying to set up a hidden ModelChoiceField. In order to have a Choice (dropdown, traditionally) it needs to know its Choices - this is why you give a queryset.
But you're not trying to give the user a choice, right? It's a hidden input, and you're setting it from the server (so it gets POSTed back, presumably).
My suggestion is to try to find a way around using the hidden input at all. I find them a bit hacky. But otherwise, why not just specify a text field with some_particular_coconut.id, and hide that? The model's only wrapping that id anyway.
The reason django requires a queryset is because when you render the field to the page, django only sends the id. when it comes back, it needs knowlege of the queryset in order to re-inflate that object.
if you already know the queryset at form creation time, why not simply specify form.fields['coconut'].initial = some_particular_coconut in your view and leave the rest of the definition in your forms.py?
If you find that you only really need to send the id anyway (you don't have to re-inflate to an object at your end), why not send it in a char field?
I have a model that inherits from Photologues 'ImageModel'. The user can upload photos and everything works fine, however the problem I am running into is when I am creating a form to edit a photo object. Since the ImageModel.image is a required field, and I can't prepopulate a FileField widget with a file already uploaded, if the user doesn't upload a new image to overwrite the old one they get an error. The error pops up in form.save() which I am using to get the rest of the fields updated right. Is there some way I can hook in and try say "since I know I am just editing an image, I know one has already been uploaded, so don't worry if the form field is empty".
Any thoughts?
You have a couple options. One, you can modify the Photologue source to make that field optional. The other, and if it will work for you the one I'd recommend, is to check out my newer library django-imagekit: http://bitbucket.org/jdriscoll/django-imagekit/wiki/Home
ImageKit is basically JUST the ImageModel part of Photologue but it's much more flexible and easier to work with. ImageKit's ImageModel works on top of the models that you define so fields can be configured how ever you please.