repeated modelform not validating in modelformset - django - django

I have a ModelForm that users can submit to save information to a database. I want to extend it with a ModelFormset so that the user can view and submit the multiple of the same model forms with different information at the same time. However, my POST data isn't binding to the ModelFormset, so the ModelFormset fails as invalid upon is_valid(). I see there is data associated with request.POST.copy(), it just
views.py
def create(request):
if request.method == 'POST':
post_data = request.POST.copy()
print "POST DATA"
print post_data
for i in post_data:
print i
formSet = WorkOrder_Form(post_data)
print "FORMSET"
print formSet
if formSet.is_valid():
formSet.save()
else:
print 'INVALID'
return HttpResponseRedirect('/Shelling/')
else:
formSet = formset_factory(WorkOrder_Form, extra=1)
return render_to_response('create.html',{'WorkOrder_Form':formSet}, context_instance=RequestContext(request))
template: (create.html)
{% load url from future %}
Return to Index </li>
<br>
<br>
<form action="{% url 'create' %}" method="post"> {% csrf_token %}
{% for WorkOrder in WorkOrder_Form %}
{{ WorkOrder.as_ul }}
<br>
{% endfor %}

You are using model forms, so you should use modelformset_factory instead of formset_factory. You can create the formset class outside of the create view. Then, you need to instantiate the formset in the GET and POST branches of your view.
Putting it together, you have the following (untested, so there might be some typos!)
WorkOrderFormSet = formset_factory(WorkOrder_Form, extra=1)
def create(request):
if request.method == 'POST':
post_data = request.POST.copy()
formset = WorkOrderFormSet(data=post_data, queryset=WorkOrder.objects.none())
if formset.is_valid():
formset.save()
else:
print 'INVALID'
return HttpResponseRedirect('/Shelling/')
else:
formset = WorkOrderFormSet(queryset=WorkOrder.objects.none())
return render_to_response('create.html',{'formset':formset}, context_instance=RequestContext(request))
And in the template:
{% for form in formset %}
{{ form.as_ul }}
{% endfor %}

Related

request.method and request.GET in Django

I am following a tutorial and I am unable to understand some lines in it:
from django.shortcuts import render, get_object_or_404
from django.http import HttpResponseRedirect
from . models import Page
from .forms import ContactForm
def index(request, pagename):
pagename = '/' + pagename
pg = get_object_or_404(Page, permalink=pagename)
context = {
'title': pg.title,
'content': pg.bodytext,
'last_updated': pg.update_date,
'page_list': Page.objects.all(),
}
# assert False
return render(request, 'pages/page.htm', context)
def contact(request):
submitted = False
if request.method == 'POST':
form = ContactForm(request.POST)
if form.is_valid():
cd = form.cleaned_data
#assert False
return HttpResponseRedirect('/contact?submitted=True')
else:
form = ContactForm()
if 'submitted' in request.GET:
submitted = True
return render(request,'pages/contact.htm',{'form': form, 'page_list': Page.objects.all(), 'sbmitted': submitted})
The above is pages/view.py file
{% extends "pages/page.htm" %}
{% block title %} Contact us {% endblock title %}
{% block content %}
<h1>Contact us</h1>
{% if submitted %}
<p class="success">
Your message was submitted successfully. Thankm you.
</p>
{% else %}
<form action="" method="post" novalidate>
<table>
{{ form.as_table }}
<tr>
<td>&NonBreakingSpace;</td>
<td><input type="submit" value="Submit"></td>
</tr>
</table>
{% csrf_token %}
</form>
{% endif %}
{% endblock content %}
The above is pages/contact.htm file
So, what is the meaning of
if requested.method == 'POST':
and why is there the following check?
if submitted in request.GET:
submitted=True
request.method gives which method is to submit the form so the first
thing checks if the form is submitted with the post method
request.GET returns a context(similar to dictionary in python) of all the variables passed by GET method
And there should be
if request.GET.get('submitted') == "True":
submitted = True
Instead of
if submitted in request.GET:
submitted=True
request.GET.get('submitted') gives value of submitted passed in url
And the thing to note is that both submitted in above code are different the former one is a key in context(similar to dictionary ) and the later one is a variable in views.py
you can send the data via GET or POST. With GET you send the data through the URL. e.g.
www.mydomain.com/Form?Key1=xxxxx&Key2=yyyyyyy
With POST the data is sent "hidden". For example, in a login form you don't want the password to be visible in the url. That's why in these forms is used as a method of sending POST.
if request.method == 'POST': that validates that the data you are sending is in POST format
2.
else:
form = ContactForm()
if 'submitted' in request.GET:
submitted = True
This means that if the sending method was not POST, but GET, look if within the information that was sent there is a submitted parameter and if so, set its value as True.

Why values are not storing in the table when i have clicked Submit button?

I have created a form for getting the value and placing it in the table. But whenever I click on Submit button, it doesn't store or give any error.It is simply staying in that page itself.
Model.py
class Employee(models.Model):
ename=models.CharField(max_length=120)
eaddress=models.CharField(max_length=120)
eemail=models.CharField(max_length=120)
ephone=models.CharField(max_length=120)
emobile=models.CharField(max_length=120)
eid=models.CharField(max_length=120)
egender=models.CharField(max_length=120)
ehire=models.DateTimeField()
edob=models.DateTimeField()
class Meta:
db_table="employee"
views.py
def employee(request):
emp=Employee.objects.all()
return render(request,'employee.html',{'emp':emp})
def addemployee(request):
if request.method == 'POST':
emp = EmployeeForm(request.POST)
if emp.is_valid():
try:
form.save()
return redirect(employee)
except:
pass
else:
emp = EmployeeForm()
return render(request,'addemployee.html',{'emp':emp})
addemployee.html:
<form method="POST" action="add_employee">
{% csrf_token %}
{{emp.ename}}
{{emp.eemail}}
{{emp.emobile}}
<button type="submit">Submit</button>
</form>
You need to display your form errors in template. So update your view and template like this:
def addemployee(request):
emp = EmployeeForm(request.POST or None)
if request.method == 'POST':
if emp.is_valid():
try:
emp.save()
return redirect(employee)
except Exception as e:
raise e # for debug purpose now
return render(request,'addemployee.html',{'emp':emp})
addemployee.html:
<form method="POST" action="add_employee">
{% csrf_token %}
{{ emp.errors }} // it will render form errors
{{emp.ename}}
{{emp.eemail}}
{{emp.emobile}}
<button type="submit">Submit</button>
</form>
I am assuming your form is not validating because you have many fields like eid, egender etc which are required for saving it in Database. If you are using Modelform, then you can use {{ emp.as_p }} as per form rendering documentation for rendering form instead of {{emp.ename}} {{emp.eemail}} {{emp.emobile}}.

request.FILES empty, though file is present in request

Following the example on the django website I'm trying to upload a file, perform checks on the contents, then feedback to the user and store the file contents.
However, I'm having trouble with the request.FILES which is always empty. My code is as follows (note the output after the print statements):
**forms.py**
class UploadFileForm(forms.Form):
data_import = forms.FileField()
class Meta:
model = Recipe
fields = ('data_import',)
**view**
def recipes_list(request):
template = 'recipes/recipes_list.html'
if request.method == 'GET':
user = request.user
queryset = Recipe.objects.filter(user=user)
form = UploadFileForm()
return render(request, 'recipes/recipes_list.html', context={'recipes': queryset, 'form': form})
elif request.method == 'POST':
print(request.FILES) # <MultiValueDict: {}>
print(request.POST) # <QueryDict: {'csrfmiddlewaretoken': ['...'], 'data_import': ['recette.json']}>
form = UploadFileForm(request.POST, request.POST.data_import)
if form.is_valid():
return HttpResponseRedirect(template)
else:
print(form.errors)
**template**
<form method="post">
{% csrf_token %}
{{ form }}
<button type="submit">submit</button>
</form>
The error I'm getting is:
<ul class="errorlist"><li>data_import<ul class="errorlist"><li>This field is required.</li></ul></li></ul>
But i can see that the file is uploaded, and is in the request.POST.get('data_import').
I would like to run validation on the form, but I can't do this if request.FILES is empty.
I'm clearly doing something wrong, can someone please point me in the right direction?
<form method="post" enctype= multipart/form-data>
{% csrf_token %}
{{ form }}
<button type="submit">submit</button>
</form>
change your form to the upper one

Form is not rendered in the template after redirection (django)

I have a view and its template that handles and prints a form. The form has a ChoiceField that takes a list of models as choices. Here is my view, template and form:
*views.py*
def index(request):
form = dbForm()
print "form is: ", form
return render(request, 'Directories/index.html', {'form':form})
*index.html*
<div id="content" align="center">
<form action="" method="get"> {% csrf_token %}
{{form.as_p}}
<input type="submit" value="Edit" name="_add" />
</form>
*forms.py*
model_classes = []
class dbForm(forms.Form):
model_classes_field = forms.ChoiceField(choices=models())
def models():
apps = get_app('Directories')
for model in get_models(apps):
model_classes.append( (model._meta.verbose_name, model._meta.db_table), )
return model_classes
The model choice submitted is sent to another view where a ModelForm displays the model's fields and expects data for each of the fields to be submitted. The submitted data are then stored in the database and the user is redirected back to the index to start again from the beginning. Here is the view, template and form:
*views.py*
def modelUpdate(request):
if 'update' in request.POST: # If the form has been submitted...
form_class = get_dynamic_form(request.GET['model_classes_field'])
form = form_class(request.POST)
if form.is_valid(): # All validation rules pass
row = form.save() #saves into database
return render(request, 'Directories/index.html')
else:
print "form errors: ", form.errors
return HttpResponse('ERROR -- Return to form submission')
*create.html*
<form action="" method="post"> {% csrf_token %}
{% for f_name in field_names %}
{% if not forloop.first %}
{{f_name}}: <input id="edit-{{f_name}}" type="text" name={{f_name}} /><br />
{% endif %}
{% endfor %}<br />
<input type="submit" name="update" value="Update" />
<input type="reset" name="Clear" value="Clear" />
</form>
*forms.py*
#create a ModelForm using a dynamic model
def get_dynamic_form(c_model):
model_class = get_model('Directories', c_model)
class ObjForm(forms.ModelForm ):
class Meta:
model = model_class
return ObjForm
The problem occurs when the form is redirected back to the index.html return render(request, 'Directories/index.html') after the data have been saved into the database. What happens is that the index.html does not display the form {{form.as_p}}at all. Although when i check print "form is: ", form in my server (Apache) error.log, my form is there printed as it should be.
I cannot understand why the data are not rendered in my template after the redirection occurs but still they are displayed correctly in my server log.
You should pass the form instance to your template as you do in index view. Your code shall be updated to
def modelUpdate(request):
if 'update' in request.POST: # If the form has been submitted...
form_class = get_dynamic_form(request.GET['model_classes_field'])
form = form_class(request.POST)
if form.is_valid(): # All validation rules pass
row = form.save() #saves into database
#------------------------------------------------v pass it to template
return render(request, 'Directories/index.html', {'form': form})
else:
print "form errors: ", form.errors
return HttpResponse('ERROR -- Return to form submission')

Django: Calling ModelForm via instance method - seperate fields

Is it possible to output a ModelForm using a class method; for example:
def edit_form(self, *args, **kwargs):
from smf.node.forms import MediaBaseForm
return MediaBaseForm(instance=self)
(MediaBaseForm is a ModelForm subclass for model Media), and then in the view:
form = node.edit_form()
(node contains the instance)
This code executes without raising errors; however, when viewing the page, no form fields are generated when I try to render each field separatly. The form does display when I use {{ formset }} but not using {% for form in formset.forms %}} ..etc. {% endfor %} -->
I need this:
{{ formset.management_form }}
{% for form in formset.forms %}
{{ form.id }}
<div id="form_title">Title: {{ form.title }}</div>
<p>Description:</p> {{ form.description }}
<p>Comment settings:</p> {{ form.comment }}
<p>Promoted to frontpage:</p> {{ form.promote }}
<p>Sticky:</p> {{ form.sticky }}
<p>Ready for Publishing:</p> {{ form.status }}
{% endfor %}
instead of this:
{{ formset }}
Is it not possible to call a form this way or am i doing something wrong?
Complete view:
def node_edit(request, nid):
#Build the standard node form
node = node_load(nid)
obj = node_get_model(node.type, True)
#modelFormset = modelformset_factory(obj, max_num=1)
form = node.edit_form()
if request.method == 'POST': # If the form has been submitted...
#form = modelFormset(request.POST, request.FILES)
form = node.edit_form()
if form.is_valid():
instances = form.save(commit=False)
for instance in instances:
instance.save()
node_post_process(node, request, obj)
if 'save_edit' in request.POST:
id = int(nid)
return HttpResponseRedirect('/edit/%i' %(id))
if 'save' in request.POST:
#id = node_callback_value.Node_ptr
id = int(nid)
return HttpResponseRedirect('/content/%i' %(id))
if 'savenew' in request.POST:
return HttpResponseRedirect('/content/add/%s' %(node.type))
else:
output = {}
#form = modelFormset(queryset=obj.objects.filter(node_ptr=nid))
form = node.edit_form(instance=node)
output = {
'formset': form,
'node': node,
}
try:
return render_to_response('node/forms/%s.edit.html' %(node.type), output)
except TemplateDoesNotExist:
return render_to_response('node/forms/default.form.html', {
'formset': form,
})
I can't understand what you're trying to do. There are a number of problems with your approach, though.
Firstly, there's no way of passing the POSTed values to the form instantiation. As a result, form.is_valid() will always be False.
Secondly, the result of node.edit_form() appears to be a single form, not a formset. So I don't know why you are passing it to the template context as formset and trying to iterate through formset.forms.