I have a web page where users can dynamically add and delete forms, to django formsets.
I have read Dynamically adding a form to a Django formset with Ajax, based on which I can add the forms to a formset dynamically. Now I want to delete the formset dynamically. I have looked at Dynamically Delete inline formsets in Django
The way I want to do it is when user clicks on delete, I have an ajax function that deletes the form instance record from the database. When my ajax function returns I keep the same total_form_count and initial_form_count and just the hide the form html so that even the deleted record is submitted in my POST.
Initially the formset renders its form elements as:
#form0
<input id="id_formprefix-0-id" type ="hidden "value="something" name="formprefix-0-id">
<input id="id_formprefix-0-field" value="something" type="text" name="formprefix-0-field">
#form1
<input id="id_formprefix-1-id" type ="hidden "value="something" name="formprefix-1-id">
<input id="id_formprefix-1-field" value="something" type="text" name="formprefix-1-field">
#form2
<input id="id_formprefix-2-id" type ="hidden "value="something" name="formprefix-2-id">
<input id="id_formprefix-2-field" value="something" type="text" name="formprefix-2-field">
Now suppose I dynamically delete form 0, using ajax, after my record is deleted, I do not change the form counts, so the total_form_count and initial_form_count are 3.
( If i reduce the total_form_count and initial_form_count in this case to 2, when I populate the formset in my view using POST data, it is expected to be ordered as form0 and form1. But in my case the valid forms are form1 and form2)
Now in my view, I am do something like the following to save my form.
myformset = modelformset_factory(ObjectElement,form=Object_Form, extra=0, can_delete=True)
for form in myformset.forms:
print(form.instance.id) #this does not print id of deleted record, but of the first existing record in the database.
print(form.instance.attribute)# this prints the correct element, which was submitted by POST even for a deleted record.
try:
objectInstance = ObjectElement.objects.get(id = form.instance.id)
objectInstance.save()
except ObjectElement.DoesNotExist:
print("Do not save as the record has already been deleted")
When I save my formset without deleting any record the saving works ok and the correct form.instance.id is printed.
However if I delete a form instance using ajax, and then try to save my formset, the
print(form.instance.id) for the deleted record seems to print the first available id in the database, but not the id that was submitted by post. (As the record is deleted , the id is not present in the database, but should it print what was submitted to it via POST right? )
If I do it without the try/catch loop I get the following error by form.errors:
<ul class="errorlist"><li>id<ul class="errorlist"><li>Select a valid choice. That choice is not one of the available choices.</li></ul></li></ul>
which seems to indicate that it is not accepting the correct form ID form the submitted post for the deleted record.
Any body has any idea as to what I am missing here? Or a better way to do this.
How to we go about dynamically deleting forms from formsets, as it seems that the order of the forms should be sequential..
Thanks in Advance!! Any help is appreciated.
For those who stumble across this issue this could be a possible solution
I am able to dynamically delete my form from formset as follows.
So the initial form html looks like
#form0
<input id="id_formprefix-0-id" type ="hidden "value="something" name="formprefix-0-id">
<input id="id_formprefix-0-field" value="something" type="text" name="formprefix-0-field">
#form1
<input id="id_formprefix-1-id" type ="hidden "value="something" name="formprefix-1-id">
<input id="id_formprefix-1-field" value="something" type="text" name="formprefix-1-field">
#form2
<input id="id_formprefix-2-id" type ="hidden "value="something" name="formprefix-2-id">
<input id="id_formprefix-2-field" value="something" type="text" name="formprefix-2-field">
Now suppose I delete form0 and form1 records from my database using ajax.
When I submit the form, the formset will not validate, because it expects the forms to be in order, and I only have form 2 remaining in the data base ( I deleted the top two). Formset errors with "Select a valid choice" as described in the question.
So after I delete the forms dynamically, when my ajax returns, I do not change the total_form_count,(https://docs.djangoproject.com/en/1.4/topics/forms/formsets/#understanding-the-managementform) but mark the form as deleted in my html, and just hide the form. Now when the formset is submitted using POST, it also submits the deleted form, but marked as deleted (https://docs.djangoproject.com/en/1.4/topics/forms/formsets/#can-delete)
Now in the view, I first filter out the forms that have been deleted, and only process the forms that still remain as follows
marked_for_delete = formset.deleted_forms
for form in formset.forms:
#Filtering out the deleted records, as the formset will not validate, for deleted records
# if we use form.instance.id or form.initial['id'] below it does not work.
#for some reason it returns the id of the first available record in the data base.
#form['id'].value(), gives us the id of the deleted element we are looking for
if form['id'].value() not in [deleted_record['id'].value() for deleted_record in marked_for_delete]:
if form.is_valid():
pass
# save the form
else:
pass
# error message
Related
Hi i have a registration form which contains username and email fields.After the registration is done,the user has an option to edit his profile which contains username,email and two other fields dob and photo(profile picture)..after clicking on the submit button all the fields are stored to the db except photo field.I checked the db the 'photo' column is empty. When i click on 'edit profile' for the second time i am getting data for all fields except photo. Can someone tell me why the photo fields is not stored to the db?
Most likely you forgot to add enctype atrribute to <form> tag. It should be like this:
<form method="POST" enctype="multipart/form-data">
...
</form>
Another possible reason is initiating of form instance without request.FILES argument. Correct form creation is:
form = MyForm(request.POST, request.FILES)
Say you already have a complex HTML form, possible from a designer, front end dev, etc. Is it common practice to not use dynamic forms (based on a Django form) for complicated forms?
I want to do something like this:
1.) Create custom HTML form.
2.) Catch form data through POST request, put it in an object/dictionary.
3.) Do some manipulations with that data to get it in a format acceptable by a Django form.
4.) Pass the manipulated data in to a form object, validate it, etc...
What is a clear solution to this problem? Should I be using Django's dynamic forms for everything? If not - how do I implement the above?
EDIT:
Part of my question has to do with using the forms ONLY for validation. I don't think I made this clear. Here is what I'm trying to do:
template.html
<form method="post">
{% csrf_token %}
<input class="foo" name="bar" type="text" value=""/>
<!-- Some more fields, not rendered through Django form -->
<button type="submit">Create Object</button>
</form>
As you can see, other than the csrf_token there is no Django code here. What I am trying to do in my view is catch the data in the POST in my view, make some changes to the data, then try to bind the new data to a form (not sure if it's possible):
views.py
def my_view(request):
# Some GET code
if request.method == 'POST':
form = ImportedForm(request.POST)
form.data['foo'] = "newValue"
# Now after changing the data, validate it...
If the form and model match nicely then I'll take advantage of the ModelForm functionality.
But most of the time it is not so tidy so, most typically, I do things in about this order:
create a django form with all the field definitions
create django GET view to serve the empty form
create an html template which serves the default html/form
test the blank form
create the POST routine to call validation and reserve the validated (erroneous) form
modify the django form to validate the fields
modify the html form to serve the error messages
test the validation and error messages
modify the POST routine to handle a valid form and do whatever it should do as a result (might involve a redirect and 'thanks' view/template)
Test the whole lot
let the designer loose on the templates
In truth the designer will be involved at some points earlier along the way but in theory I just get it all to work as a "white" then add all the fancy stuff after. That includes javascript validation (ie after all the above).
I ended up doing something like this. It is ugly, and may not be the proper way to do it, but it works...
if request.method == 'POST':
try:
# Create dictionary from POST data
data = {
'foo': request.POST['foo'],
'foobar': request.POST['foobar'],
}
except:
# Handle exceptions
form = ImportedForm(data)
if form.is_valid:
# Continue to validate and save
I have a page which displays a form that a logged-in user can use to edit their profile.
The first time the user loads the corresponding view, with a GET request, the form should display the values of the users existing profile record.
Because I'd like to have granular control over the markup used for the form fields, I'd like to retrieve the field values only, and manually write the necessary input element markup inserting the retrieved field values as the input elements' 'value' attribute (rather than have django render the entire input elements).
So far I've been trying to use directives like {{ form.myfield.data }} in my template to access the field data, but this is returning "None", instead of the profile details as i expected.
If the user has just posted a valid form though, the form fields do contain the expected profile details.
I hope someone can help me understand what i'm doing wrong here:
Here's my view:
#login_required
def edit(request):
# get logged-in user's profile
obj=Profile.objects.get(user=request.user)
if request.method == 'POST': # If the form has been submitted...
form = ProfileForm(request.POST, request.FILES, instance=obj)
if form.is_valid(): # All validation rules pass
form.save()
request.flash['success'] = "Your profile has been updated." # Puts a string to the flash scope
else:
request.flash['error'] = 'Please correct the problems below and try again' # Puts a string to the flash scope
else:
# if no form was submitted
# derive the form data from the logged-in users existing profile
form = ProfileForm(instance=obj)
return render_to_response('app_profile/edit.html',
{
'form': form,
'user': request.user,
'ancestor_urls': ['app_profile.views.edit',],
},context_instance=RequestContext(request)
)
And here's an excerpt from the corresponding template. This input element deals with a field called 'display_name'.
<input type="text"
class="textInput large {% if form.display_name.errors %}error{% endif %}"
maxlength="50"
size="35"
value="{{ form.display_name.data }}"
id="id_display_name"
name="display_name">
The way to do what you want to do is to write custom form widgets, instead of doing that in the template.
You can either create an entirely custom widget, or you can just add/change the attributes on the form level when you init the ModelForm
I guess you can solve some of your problems without making a custom widget using the widgets attrs argument: http://docs.djangoproject.com/en/dev/ref/forms/widgets/#django.forms.Widget.attrs, also you have some styling options using the input's id!
I have a django form with two different submit buttons, on the view where the form is submitted to I need to know what submit button was pressed and take different actions accordingly.
From what I have read the submit button's name or id should be somewhere in the request.POST dictionary, but it not there!
This is a fragment of my form:
<form id="editPaperForm" action="{{paper.editURL}}" method="POST">
<input type="submit" name="savePaperButton" id="savePaperButton" value="Save and Send Later"/>
<input type="submit" name="sendPaperButton" id="sendPaperButton" value="Save and send"/>
...
</form>
In the view:
...
if 'sendPaperButton' in request.POST:
return applicants_confirmSend(request, paperID)
else:
return applicants_home(request)
sendPaperButton is never in the request.POST, and neither is the other one, should I be looking somewhere else?
The only idea I have is to add a hidden field and modify it via javascript before sending the form but that seems kind of redundant since I'm pretty sure that data should be there somewhere...
Thanks!
Don't forget to add the name and value parameters to your "button" or "input type=submit" fields of the form. I've had the same problem once and it drove me crazy.
In short, as request.POST contains a dict, you need a key and a value. The key corresponds to the name parameter of your button, and the dict's value to the button's value.
<button type="submit" value="preview">Preview</button>
won't be reflected in request.POST (there's no key for the POST dictionary!), whereas
<button type="submit" value="preview" name="preview">Preview</button>
will have a key "preview" with value "preview".
For some reason, in Chrome, when I had two buttons using <input/> tags, it would actually treat the button I didn't click as an input. That way, when I tested something like 'sendPaperButton' in request.POST, it would return the opposite of what I wanted.
I changed these to <button></button> tags and it worked fine.
I'm trying to style a form with CSS. First of all I haven't seen a complete example, other than on the official documentation, so I would appreciate any blog entries, or articles.
Now on my form, a typical Charfield gets translated on html like this:
<input type="text" name="artists" id="id_artists" />
If my form contains errors on some field, the previous Charfield remembers the value and goes:
<input type="text" name="artists" value="Pink Floyd" id="id_artists" />
How can I get this value (value="Pink Floyd") in django forms? Say my field is {{form.artists}}, I can use {{form.artists}} as the field, {{form.artists.label}} as label, {{form.artists.errors}} and {{form.artists.help_text}}, but how about this value?
Thanks in advance!
Create the input field specifically, rather than relying on django to auto-create it.
Something like:
<input type="text" name="artists" id="id_artists" value="{{form.artists.title}}" />
should work
You can get the current value of the field from the data property:
{{ form.artists.data }}
I can't see the Django documentation mentioning this, but it works...
You can also add additional validation to the form class to do something with the form data. From djangobook.com:
from django import forms
class ContactForm(forms.Form):
subject = forms.CharField(max_length=100)
email = forms.EmailField(required=False)
message = forms.CharField(widget=forms.Textarea)
def clean_message(self):
message = self.cleaned_data['message']
num_words = len(message.split())
if num_words < 4:
raise forms.ValidationError("Not enough words!")
return message
Inside of the clean_message method you can access a given field using the self.cleaned_data dictionary. This dictionary is available for any form that is validated.
Be sure to return the field, in this case message, or else None is returned.