How to Process Multi Step Forms in Django? - python

I've made some attempted to use formwizard but there wasn't much documentation about it so I decided to stay with the basic. I've successfully obtained and display the data from the first form to the second form and added some checkbox next to the data to allow user to choose whether to overwrite or ignore the duplicate data found in the backend process. The problem I have is the second form doesn't know how retrieve the data of the first form after hitting "Confirm" button. The form2.html template invalidated the data completely since it called itself again by the form action after submitting the data. Is there a way to solve this or a better approach to this?
forms.py
class NameForm (forms.Form):
first_name = forms.CharField (required = False)
last_name = forms.CharField (required = False)
class CheckBox (forms.Form):
overwrite = forms.BooleanField (required = False)
views.py
def form1 (request):
NameFormSet = formset_factory (NameForm, formset = BaseNodeFormSet, extra = 2, max_num = 5)
if request.method == 'POST':
name_formset = NameFormSet (request.POST, prefix = 'nameform')
if name_formset.is_valid ():
data = name_formset.cleaned_data
request.session ['data'] = data
context = {'data': data}
return render (request, 'nameform/form2.html', context)
else:
name_formset = NameFormSet (prefix = 'nameform')
context = {......}
return render (request, 'nameform/form1.html', context)
def form2 (request):
request.session ['data'] = data
CheckBoxFormSet = formset_factory (CheckBox, extra = 2, max_num = 5)
if request.method == 'POST':
checkbox_formset = CheckBoxFormSet (request.POST, prefix = 'checkbox')
if checkbox_formset.is_valid ():
data = checkbox_formset.cleaned_data
context = {'data': data}
return render (request, 'nameform/success.html', context)
else:
checkbox_formset = CheckBoxFormSet (prefix = 'checkbox')
return HttpResponse ('No overwrite data.')
form2.html
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
{% load staticfiles %}
<link rel="stylesheet" type="text/css" href="{% static 'nodeform/style.css' %}" >
<title>User Information</title>
</head>
<body>
<h1>User Information:</h1>
<form action="form2" method="POST">
{{ checkbox_formset.management_form }}
<div id="tablefont">
<table id="table01">
<tr>
<th>First Name</th>
<th>Last Name</th>
<th class="center">Overwrite</th>
</tr>
{% for info in data %}
<tr>
<td>{{ info.first_name }}</td>
<td>{{ info.last_name }}</td>
<td class="center"><input id="id_checkbox-{{ forloop.counter0 }}-overwrite" name="checkbox-{{ forloop.counter0 }}-overwrite" type="checkbox" /></td>
</tr>
{% endfor %}
</table>
</div>
<br>
<p><input type="submit" value="Confirm">
<a href="{% url 'form1' %}">
<button type="button">Cancel</button></a></p>
</form>
</body>
</html>

Personally I find that class based views always make life simpler, and in this case specifically there is the Form Wizard views which use the session or a cookie. Check out the docs; https://django-formtools.readthedocs.io/en/latest/wizard.html
I've just finished writing something very similar to this;
from django.contrib.formtools.wizard.views import SessionWizardView
class SignupWizard(SessionWizardView):
template_name = 'wizard_form.html'
form_list = [Form1, Form2, Form3]
model = MyModel
def get_form_initial(self, step, **kwargs):
initial = self.initial_dict.get(step, {})
current_step = self.storage.current_step
if step or current_step in ['0', 0]:
initial.update({'field': 'data'})
elif step or current_step in ['1', 1]:
initial.update({'field': 'data'})
return initial
def get_context_data(self, form, **kwargs):
"""
Supply extra content data for each stage.
e.g. stage page title
"""
previous_data = None
if self.steps.current == self.steps.last:
previous_data = self.get_all_cleaned_data()
context = super(SignupWizard, self).get_context_data(form, **kwargs)
context.update(
{
'review_data': previous_data,
}
)
return context
def done(self, form_list, **kwargs):
"""
Final page, this is rendered after the post method to the final form.
"""
form_data_dict = self.get_all_cleaned_data()
mymodelform = form_list[0].save()
return HttpResponseRedirect()
Essentially there my first form is a ModelForm for MyModel and I use other standard forms to collect other information. So at the end, grab the first form from the list and save that to create the MyModel instance.
Equally as you can see you can grab self.get_all_cleaned_data() to get all of the data entered in to the forms through to whole process to handle the data yourself.
The template for something this would be along the lines of;
{% extends 'base_wizard.html' %}
{% load i18n %}
{% block form %}
{% for error in wizard.form.non_field_errors %}
{{ error }}
{% endfor %}
{{ wizard.form.media }}
{{ wizard.management_form }}
{% wizard.form.as_p %}
<div class="controls">
{% if wizard.steps.prev %}
<button name="wizard_goto_step" type="submit" value="{{ wizard.steps.prev }}">
{% trans "Previous step" %}
</button>
{% endif %}
<button type="submit" name="submit">
{% trans "Next step" %}
</button>
</div>
{% endblock form %}

Related

Django Class based Form only updating the final post value

As the title states, I have a table that I'm attempting to update that only updates the final value in the post, from what I understand if I want to update multiple records I must iterate over my request object and update a form instance with the specified ID in my db.
Before submission all records have a price_checked of 0.
and then after - you can see the final value from the post request updates all the records!
postgres table
The code in question that updates my model form instance.
def post(self,request):
if request.method=='POST':
for key in request.POST.getlist('product_id'):
product_update = ProductTable.objects.get(id=key)
form = ProductUpdateForm(request.POST,instance=product_update)
print(form)
if form.is_valid():
form.save()
messages.success(request,message='price checked...')
return redirect('product')
is anyone able to assist? I've been at this point for over 2 weeks.
models/form/view for reference.
models.py
from django.db import models
class ProductTable(models.Model):
id = models.AutoField(
primary_key=True,
editable=False
)
product_name = models.TextField(max_length=255,null=False)
price = models.DecimalField(max_digits=6,decimal_places=2,null=False)
from_date = models.DateTimeField()
to_date = models.DateTimeField(null=True)
price_checked = models.IntegerField(default=0,null=False)
def __str__(self : str) -> str:
return f"{self.product_name} - {self.id} with a price check of {self.price_checked}"
forms.py
from django.forms import ModelForm
from .models import ProductTable
class ProductUpdateForm(ModelForm):
class Meta:
model = ProductTable
fields = ('price_checked',)
views.py
from typing import Any, Dict
from django.contrib import messages
from django.contrib.auth.mixins import LoginRequiredMixin
from django.shortcuts import redirect
from django.views.generic import ListView
from django.db import transaction
from .forms import ProductUpdateForm
from .models import ProductTable
class TableDataView(LoginRequiredMixin,ListView):
model = ProductTable
context_object_name = 'product'
template_name = 'tables/product.html'
def get_context_data(self, **kwargs: Any) -> Dict[str, Any]:
context = super().get_context_data(**kwargs)
context['product'] = ProductTable.objects.filter(pk__in= [4607,4642, 4645])
return context
def post(self,request):
if request.method=='POST':
for key in request.POST.getlist('product_id'):
product_update = ProductTable.objects.get(id=key)
form = ProductUpdateForm(request.POST,instance=product_update)
print(form)
if form.is_valid():
form.save()
messages.success(request,message='price checked...')
return redirect('product')
product.html
{% extends '_base.html' %} {% block content %} {% load crispy_forms_tags %}
<form method="POST" action="">
{% csrf_token %}
{{ form|crispy }}
<div class="container mx-flex pt-5 mb-5">
<table class="table" id="table">
<thead>
<tr>
<th>Product</th>
<th>Price</th>
<th>Date</th>
<th>Input</th>
</tr>
</thead>
<tbody>
{% for data in product %}
<tr>
<th>{{ data.product_name }}</th>
<th>{{ data.price }}</th>
<th>{{ data.from_date }}</th>
<th>
<input type="hidden" name="product_id" value="{{data.id}}" />
<input class="form" name="price_checked" id="priced_checked" type="number" placeholder="{{ data.price_checked }}"/>
<input type="submit" value="OK">
</th>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</form>
{% endblock content %}
request.POST
<QueryDict: {'csrfmiddlewaretoken': ['p0j3e0UbrY1VuFEAnJWopaCICCxOPj8v2OkLRZZiGlUa4YtxGwduD2bAIrm91VKe'], 'product_id': ['4607', '4642', '4645'], 'price_checked': ['1', '2', '3']}>
after read formset documents,I think it should looks like this.
the view python return a formset to template,and in the post function create formset by request.POST
def get_context_data(self, **kwargs: Any) -> Dict[str, Any]:
context = super().get_context_data(**kwargs)
ProductFormSet = modelformset_factory(ProductTable)
context['product_formset'] = ProductFormSet(queryset=ProductTable.objects.filter(pk__in= [4607,4642, 4645]))
return context
def post(self,request):
if request.method=='POST':
ProductFormSet = modelformset_factory(ProductTable)
formset = ProductFormSet(request.POST)
if formset.is_valid():
formset.save()
messages.success(request,message='price checked...')
return redirect('product')
in the template I have mark the changes,the important thing is {{ product_formset.management_form }} in the begin form.and {{ form.id }} of each loop,the each cell data should be {{ form.product_name.value() }} or {{ form.product_name.data }},you can try that
{% extends '_base.html' %} {% block content %} {% load crispy_forms_tags %}
<form method="POST" action="">
{% csrf_token %}
{{ form|crispy }}
<!-- changed -->
{{ product_formset.management_form }}
<div class="container mx-flex pt-5 mb-5">
<table class="table" id="table">
<thead>
<tr>
<th>Product</th>
<th>Price</th>
<th>Date</th>
<th>Input</th>
</tr>
</thead>
<tbody>
<!-- changed -->
{% for form in product_formset %}
{{ form.id }}
<tr>
<td>{{ form.product_name.value() }}</td>
<td>{{ form.price.value() }}</td>
<td>{{ form.from_date.value() }}</td>
<td>
{{ form.price_checked }}
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
<input type="submit" value="submit">
</form>
{% endblock content %}
maybe this will not help you,because I never used the django form things.
I guess you are a precise man who want to follow every django's principle.
But as I know,traditional form has much limitation,some ajax or reactjs has more flexible.
A couple changes to support formsets:
Use the same formset for updating and displaying the objects, but disable the fields you don't want to be updated (make them read-only):
class ProductUpdateForm(ModelForm):
disabled_fields = ['product', 'price', 'date_added', 'date_removed']
class Meta:
model = ProductTable
fields = ('product', 'price', 'date_added', 'date_removed', 'price_checked',)
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
for field in self.disabled_fields:
self.fields[field].disabled = True
Then update the view to use the form for displaying and for updating:
from django.forms import modelformset_factory
class TableDataView(LoginRequiredMixin,ListView):
model = ProductTable
context_object_name = 'product'
template_name = 'tables/product.html'
def get_context_data(self, **kwargs: Any) -> Dict[str, Any]:
context = super().get_context_data(**kwargs)
ProductTableFormset = modelformset_factory(ProductTable, form=ProductUpdateForm,)
context['formset'] = ProductTableFormset(queryset=ProductTable.objects.filter(pk__in=[4607,4642, 4645]))
return context
def post(self,request):
ProductTableFormset = modelformset_factory(ProductTable, form=ProductUpdateForm)
if request.method == 'POST':
formset = ProductTableFormset(request.POST, queryset=ProductTable.objects.filter(pk__in=[4607,4642, 4645]))
if formset.is_valid():
formset.save()
messages.success(request,message='price checked...')
return redirect('product')
And in your template, render the whole formset:
{% extends '_base.html' %}
{% block content %}
{% load crispy_forms_tags %}
<form method="POST" action="">
{% csrf_token %}
{{ form|crispy }}
<div class="container mx-flex pt-5 mb-5">
<table class="table" id="table">
{{ formset }}
</table>
</div>
</form>
{% endblock content %}
EDIT: If you want the simplest change you can do to fix this (so you don't have to work on the styles for the formset), you can do away with the form for the post and update the products as is:
def post(self,request):
if request.method == 'POST':
products_to_update = []
for id, price_checked in zip(request.POST.getlist('product_id'), request.POST.getlist('price_checked')):
product = ProductTable.objects.get(id=id)
product.price_checked = price_checked
products_to_update.append(product)
ProductTable.objects.bulk_update(products_to_update, ['price_checked'])
messages.success(request,message='price checked...')
return redirect('product')

Django CSRF_TOKEN issue with Edge only

I'm trying my django application through different browsers (Chrome, Firefox, IE11 and Edge) and I got an issue with the csrf_token and Edge only.
This issue is in reference with my django form.
My view file :
class ManageDocView(AdminRequiredMixin, View):
""" Render the Admin Manage documents to update year in the filename"""
template_name = 'omcl/manage_doc_form.html'
form_class = ManageDocForm
success_url = 'omcl/manage_doc_form.html'
#staticmethod
def get_title():
return 'Change Document Title'
def get(self, request):
form = self.form_class()
context = {
"form": form,
"title": self.get_title()
}
return render(request, self.template_name, context)
def post(self, request):
form = self.form_class()
query_document_updated = None
query_omcl = None
query_document = None
if "submitButton" in request.POST:
omcl_list = request.POST.get('omcl_list', False)
query_omcl = Omcl.objects.get(id=omcl_list)
query_document = Document.objects.filter(omcl=omcl_list)
form.fields['omcl_list'].initial = query_omcl
elif "UpdateDocument" in request.POST:
checkbox_id = request.POST['DocumentChoice']
checkbox_id_minus_1 = int(checkbox_id) - 1
query_document_updated = Document.objects.get(id=checkbox_id)
omclcode = query_document_updated.omcl.code
src_filename = query_document_updated.src_filename
filename, file_extension = os.path.splitext(src_filename)
category = query_document_updated.category
if category == "ANNUAL":
category = "ANNUAL_REPORT"
year = self.request.POST['pts_years']
# Create the new document title updated by the new year
new_document_title = f"{year}_{category}_{omclcode}_{checkbox_id_minus_1} - {src_filename}"
# Create the new document file updated by the new year
new_document_file = f"omcl_docs/{omclcode}/{year}_{category}_{omclcode}_{checkbox_id_minus_1}{file_extension}"
# Get file.name in order to rename document file in /media/
document_path = query_document_updated.file.name
try:
actual_document_path = os.path.join(settings.MEDIA_ROOT, document_path)
new_document_path_temp = f"{settings.MEDIA_ROOT}/{new_document_file}"
new_document_path = os.rename(actual_document_path, new_document_path_temp)
except FileNotFoundError:
messages.error(self.request, _(f"Document {src_filename} doesn't exist on the server"))
return redirect('manage_doc')
else:
# Assign modifications to selected document and save it into the database
query_document_updated.title = new_document_title
query_document_updated.file = new_document_file
query_document_updated.save()
messages.success(self.request, _(f"The modification has been taken into account"))
context = {
'form': form,
'query_omcl': query_omcl,
'query_document': query_document,
'query_document_updated': query_document_updated,
'title': self.get_title(),
}
return render(request, self.template_name, context)
My forms file :
class ManageDocForm(forms.Form):
def __init__(self, *args, **kwargs):
super(ManageDocForm, self).__init__(*args, **kwargs)
omcl_list = forms.ModelChoiceField(
queryset=Omcl.objects.filter(is_obsolete=False),
label=_('OMCL Choice'),
widget=ModelSelect2Widget(
model=Omcl,
search_fields=['code__icontains', 'name__icontains'],
attrs={'data-placeholder': "Please select an OMCL"}
)
)
now = datetime.today().year
year_choices = ((i, str(i)) for i in range(now, now - 30, -1))
pts_years = forms.ChoiceField(
label='PTS years',
choices=year_choices,
required=True,
widget=Select2Widget(
attrs={'data-placeholder': "Please select a new year"}),
)
My template file with a little part of javascript :
{% block extra_script %}
<!-- Submit OMCL list with change and not submit button + Previous/Next pagination button -->
<script>
$('#select-omcl-form').on('change', function () {
$(this).submit();
});
</script>
{% endblock %}
{% block main %}
<h2>{{ title }}</h2>
<div class="row manage-doc">
<div class="col-md-12">
<form id="select-omcl-form" name="select-omcl-form" action="" method="POST">
{% csrf_token %}
<fieldset>
<legend><span class="name">{% trans 'Select an OMCL' %}</span></legend>
{{ form.omcl_list }}
<input type="hidden" name="submitButton">
</fieldset>
</form>
</div>
</div>
<br/>
<div class="row manage-doc">
<div class="col-md-12">
<fieldset>
<legend><span class="name">{% trans 'Select a document' %}</span></legend>
<form action="" method="POST">
{% csrf_token %}
<div id="table-document">
<table id="document-table" class="table table-bordered table-striped table-condensed table_model">
<thead>
<tr>
<th id="radio-column"></th>
<th id="document-title-column">{% trans 'Document title' %}</th>
</tr>
</thead>
<tbody>
{% for document in query_document|dictsortreversed:'title' %}
<tr>
<td><input type="radio" class="radio-document" id="document-radiobox" name="DocumentChoice"
value="{{ document.id }}"></td>
<td>{{ document.title }}</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
<br><br>
<legend><span class="name">{% trans 'Select a new year' %}</span></legend>
{{ form.pts_years }}
<button class="btn btn-default" id="document-button" type="submit"
name="UpdateDocument">{% trans "Change year" %}</button>
</form>
</fieldset>
<br>
</div>
</div>
{% endblock main %}
A gif presentation :
This is a little gif which explains the process and the issue according to csrf_token only with Edge browser :
Link to my gif
What I tried :
I tried to add CSRF_COOKIE_DOMAIN in my settings.py file but it doesn't work.
Do you have any idea ? It's pretty weird because I don't have any issue with others browsers. Ony with Microsoft Edge.
Cookies are allowed in my browser.
I found the issue thanks to my collegue. I used redirect but I had to use render because if I redirect, the CSRF_TOKEN is not actualized and it sends a second POST request with the previous token.
So it should be :
except FileNotFoundError:
messages.error(self.request, _(f"Document {src_filename} doesn't exist on the server"))
context = {
'form': form,
'query_omcl': query_omcl,
'query_document': query_document,
'query_document_updated': query_document_updated,
'title': self.get_title(),
}
return render(request, self.template_name, context)
Instead of :
except FileNotFoundError:
messages.error(self.request, _(f"Document {src_filename} doesn't exist on the server"))
return redirect('manage_doc')

Custom formset validation not working in django

In my formset I would like to check each reading against a target if the reading is larger than the target do not save to db. For some reason I can't get this to work correctly because it still allows me to save. Any help would be greatly appreciated!
all in views.py
#custom formset validation
def get_dim_target(target):
dim = Dimension.objects.values_list('target', flat=True).filter(id=target)
return dim
#custom formset validation
class BaseInspecitonFormSet(BaseFormSet):
def insp_clean(self):
if any(self.errors):
return
reading = []
for form in self.forms:
dim_id = form.cleanded_data['dimension_id']
reading = form.cleaned_data['reading']
target = get_dim_target(dim_id)
if reading > target:
raise forms.ValidationError("Reading larger than target")
reading.append(reading)
#formset
def update_inspection_vals(request, dim_id=None):
dims_data = Dimension.objects.filter(id=dim_id)
can_delete = False
dims = Dimension.objects.get(pk=dim_id)
sheet_data = Sheet.objects.get(pk=dims.sheet_id)
serial_sample_number = Inspection_vals.objects.filter(dimension_id=24).values_list('serial_number', flat=True)[0]
target = Dimension.objects.filter(id=24).values_list('target', flat=True)[0]
title_head = 'Inspect-%s' % dims.description
if dims.ref_dim_id == 1:
inspection_inline_formset = inlineformset_factory(Dimension, Inspection_vals, can_delete=False, extra=0, fields=('reading',), widgets={
'reading': forms.TextInput(attrs={'cols': 80, 'rows': 20})
})
if request.method == "POST":
formset = inspection_inline_formset(request.POST, request.FILES, instance=dims)
if formset.is_valid():
new_instance = formset.save(commit=False)
for n_i in new_instance:
n_i.created_at = datetime.datetime.now()
n_i.updated_at = datetime.datetime.now()
n_i.save()
else:
form_errors = formset.errors
formset.non_form_errors()
return HttpResponseRedirect(request.META.get('HTTP_REFERER', '/'))
else:
formset = inspection_inline_formset(instance=dims, queryset=Inspection_vals.objects.filter(dimension_id=dim_id).order_by('serial_number'))
return render(request, 'app/inspection_vals.html',
{
'formset': formset,
'dim_data': dims_data,
'title':title_head,
'dim_description': dims.description,
'dim_target': dims.target,
'work_order': sheet_data.work_order,
'customer_name': sheet_data.customer_name,
'serial_sample_number': serial_sample_number,
})
inspection_val.html
<h1>Inspeciton Values</h1>
<div class="well">
<form method="post">
{% csrf_token %}
<table>
{{ formset.management_form }}
{% for x in formset.forms %}
<tr>
<td>
Sample Number {{ forloop.counter0|add:serial_sample_number }}
</td>
<td>
{{ x }}
{{ x.errors }}
</td>
</tr>
{% endfor %}
</table>
<input type="submit" value="Submit Values" class="btn-primary" />
</form>
</div>
</div>
The Django docs on custom formset validation show that you should create a clean method.
You have named your method insp_clean, so Django will never call it. Rename the method to clean.

Multiple Forms and Formsets in CreateView

I have 2 models, Father and Son.
I have a page to register Father. On the same page I have a formset to register Son.
On page has a button "more" to add another Father and their respective Son on the same page.
Does anyone have any examples using CreateView?
Class based views are still new, so I'll write this out. The process is simple:
First, create the forms for your objects. One of the forms will be repeated. Nothing special to be done here.
class SonInline(ModelForm):
model = Son
class FatherForm(ModelForm):
model = Father
Then, create your formset:
FatherInlineFormSet = inlineformset_factory(Father,
Son,
form=SonInline,
extra=1,
can_delete=False,
can_order=False
)
Now, to integrate it with your CreateView:
class CreateFatherView(CreateView):
template_name = 'father_create.html'
model = Father
form_class = FatherForm # the parent object's form
# On successful form submission
def get_success_url(self):
return reverse('father-created')
# Validate forms
def form_valid(self, form):
ctx = self.get_context_data()
inlines = ctx['inlines']
if inlines.is_valid() and form.is_valid():
self.object = form.save() # saves Father and Children
return redirect(self.get_success_url())
else:
return self.render_to_response(self.get_context_data(form=form))
def form_invalid(self, form):
return self.render_to_response(self.get_context_data(form=form))
# We populate the context with the forms. Here I'm sending
# the inline forms in `inlines`
def get_context_data(self, **kwargs):
ctx = super(CreateFatherView, self).get_context_data(**kwargs)
if self.request.POST:
ctx['form'] = FatherForm(self.request.POST)
ctx['inlines'] = FatherInlineFormSet(self.request.POST)
else:
ctx['form'] = Father()
ctx['inlines'] = FatherInlineFormSet()
return ctx
Finally, here is the template:
The key part is the jquery django-dynamic-formset plugin that keeps adding new inline forms:
<form id="father-form" method="POST" enctype="multipart/form-data" action=".">
{% csrf_token %}
<div class="row">
{% for f in form %}
<div class="span3">{{ f.label }}<br />{{ f }}
{% if f.errors %}
{% for v in f.errors %}
<br /><span style="color:red;">{{ v }}</span>
{% endfor %}
{% endif %}
</div>
{% endfor %}
</div>
<hr />
<h2>Sons:</h2>
<table class="table-striped">
<table>
{% for f2 in inlines %}
<tr id="{{ f2.prefix }}-row">
{% for i in f2 %}
<td>
{{ i }}{% if i.errors %}<span style="color:red;">{{ i.errors }}</span>{% endif %}
</td>
{% endfor %}
</tr>
{% endfor %}
</table>
{{ inlines.management_form }}
<input type="submit" class="btn btn-primary" value="Go Go Gadget →">
</form>
<script type="text/javascript">
$(function() {
$('#father-form tr').formset({
prefix: '{{ inlines.prefix }}'
});
})
</script>

Can Dynamic number of formset be used in a single view and passed o a single Template

I have the following view,template and form through which i am implementing the formset. I intend to implement multiple formsets in a single view/template but my number of formsets is dynamic based on user input. How can i have multiple dynamic number of formsets in this code?
Can i do this with dictionary element i.e by creating a dictionary of formsets??
My view is as follows:
def show (request):
b = request.session["s1"] # count of no of period ids
c = request.session["s2"] # account number inserted by user
d = request.session["s3"] # year inserted by customer
a = account_period.objects.filter(year=d).values('id')
e = account_period.objects.filter(year=d).values('month')
f = account_period.objects.filter(id = a).values('year')
butt = formset_factory(bu, extra=b)
if request.method == 'POST'
formset = butt(request.POST)
if formset.is_valid():
z = account_tab.objects.get(account_number=c)
pr = date.today()
i=0
for form in formset.forms:
x = form.cleaned_data['value']
y = account_period.objects.get(id=a[i:(i+1)])
try:
uip = budget.objects.get(account_no = c,account_period = a[i:(i+1)])
if uip.budget_amount != x
uip.budget_amount = x
uip.save()
except budget.DoesNotExist:
w = budget(account_no = z, account_period = y, budget_amount = x, created_by_login = 'me')
w.save()
i=i+1
pass
return HttpResponse('thanks')
form is
class bu(forms.Form):
value = forms.CharField()
template is
<html>
<head>
<title>BUDGET</title>
</head>
<body>
<p>BUDGET MANAGEMENTS</p>
<p>Your Account Number is : {{ account_number }}.</p> <p>You Chose {{ period }} {{month}} as period<p>
{% if form.errors %}
<p style="color: red;">
Please correct the error{{ form.errors|pluralize }} below.
</p>
{% endif %}
<form action="." method="post">{% csrf_token %}
{{ formset.management_form }}
<table>
{% for form in formset.forms %}
{{ form }}
{% endfor %}
</table>
<input type="submit" value="Submit">
</form>
</body>
</html>
#
#rohan
my GET method return has many variables which has to be passed into template so i tried to pass the dictionary formsetlist (after appying the changes u suggested) in following 2ways
1)
formset = butt( return render_to_response('budgetfinalform.html', {'account_number': c,'period':d,'month':e,'year':f,'formset': formset},context_instance=RequestContext(request))
2)
ctx ={'formsetlist': formset}
formset = butt( return render_to_response('budgetfinalform.html', {'account_number': c,'period':d,'month':e,'year':f,ctx,context_instance=RequestContext(request))
but obtained "unboundlocalerror : local variable 'formset' referenced before assignment"
I would do something like:
def show (request):
#initial view processing
# fomset_count taken as parameter or user input
formsetlist = []
#create formset list
for i in range(0, formset_count):
formsetlist.append(formset_factory(bu, extra=b))
# other view related code
# for GET method
ctx = { 'formsetlist': formset }
return render_to_response('your_template_name', ctx,
context_instance = RequestContext(request)
)
In template:
<form action="." method="post">{% csrf_token %}
{% for formset in formsetlist %}
{{ formset.management_form }}
<table>
{% for form in formset.forms %}
{{ form }}
{% endfor %}
</table>
{%endfor%}
<input type="submit" value="Submit">

Categories