I am trying to produce a template with many addresses (forms), where you can add, edit and remove them.
Am I doing something wrong with formsets? Here are my views:
#login_required
def addresses(request):
AddressesFormset = modelformset_factory(Address,
can_delete = True,
extra = 0,
exclude = ['user'])
log.debug('Queryset: %s', request.user.addresses.all())
if request.method == 'POST':
log.debug('Formset from POST')
formset = AddressesFormset(request.POST)
if formset.is_valid():
log.debug('Saving form')
formset.save()
log.debug('Fromset from queryset')
formset = AddressesFormset(queryset = request.user.addresses.all())
else:
log.debug('Form is not valid')
else:
log.debug('Fromset from queryset')
formset = AddressesFormset(queryset = request.user.addresses.all())
return render_to_response('accounts/addresses.html', locals(), context_instance = RequestContext(request))
#login_required
def add_address(request):
address = Address.objects.create(user = request.user)
address.save()
return HttpResponseRedirect('/accounts/addresses/')
And template:
{{ formset.management_form }}
{% for form in formset.forms %}
<table class="accountT">
<tr class="accountTT">
<td><p>Ulica, nr domu, mieszkania:</p></td>
<td>{{ form.street.errors }}{{ form.street }}</td>
</tr>
<tr class="accountTT">
<td><p>Miejscowość:</p></td>
<td>{{ form.city.errors }}{{ form.city }}</td>
</tr>
<tr class="accountTT">
<td><p>Kod pocztowy:</p></td>
<td>{{ form.zipcode.errors }}{{ form.zipcode }}</td>
</tr>
<tr class="accountTT">
<td><p>Telefon kontaktowy:</p></td>
<td>{{ form.phone.errors }}{{ form.phone }}</td>
</tr>
<tr>
<td><p>Usuń:</p></td>
<td>{{ form.DELETE }}</td>
</tr>
{{ form.id }}
</table>
{% endfor %}
Edit:
The problem is that adding a form I have to save the formset (in add_address()). I would like to see how do you treat formsets properly. I don't understand it at all ;).
Thanks in advance,
Etam.
Well, you don't say what your problem is, but you are doing at least one thing wrong.
After confirming that the formset is valid, and then saving it, for some reason you then instantiate another formset and fall straight through to the render_to_response at the end of the function, so you end up displaying a set of blank forms again.
What you should do at that point is redirect somewhere else, eg to a confirmation page.
Related
I want the ability to update records in a table format so that I can quickly make updates. I am close to figuring this out, but form.valid() is still returning False.
My model:
class Actions(models.Model):
meeting = models.ForeignKey(Meeting, on_delete=models.CASCADE)
dateAdded = models.DateTimeField(default = timezone.now, editable = False)
dateComplete = models.DateTimeField(null=True, blank=True)
action = models.TextField(max_length=1000,)
responsibility = models.ForeignKey(staff, on_delete=models.CASCADE, blank=True,null = True,)
complete = models.BooleanField(default = False)
My view:
def actionItemsView(request):
ActionFormSet = modelformset_factory(Actions, fields=('action', 'responsibility','complete','meeting','dateComplete'),max_num=1)
if request.method == "POST":
action_formset = ActionFormSet(request.POST, request.FILES,queryset=Actions.objects.filter())
for action_form in action_formset:
print(action_form.errors)
if action_form.is_valid():
action = action_form.save()
return HttpResponseRedirect('/saved!/')
else:
formset = ActionFormSet(queryset=Actions.objects.filter(complete = False))
return render(request, 'action_items.html', {'formset': formset})
My template:
<table class="table table-hover table-sm">
<tr>
<th>decision</th>
<th>responsibility</th>
<th>complete?</th>
<th>meeting</th>
<th>date complete</th>
<th>submit</th>
</tr>
{%for form in formset%}
<form method="post" enctype= multipart/form-data>
<tr>
{{ formset.management_form }}
{{ form.management_form }}
{% csrf_token %}
<td>{{ form.action }}</td>
<td>{{ form.responsibility }}</td>
<td>{{ form.complete }}</td>
<td>{{ form.meeting }}</td>
<td>{{ form.dateComplete }}</td>
<td><button type="submit">Save</button></td>
</tr>
</form>
{% endfor %}
</table>
When I run this, the template is rendered exactly how I would expect, but when I make any changes to an item and hit submit, it throws The view meetings.views.actionItemsView didn't return an HttpResponse object. It returned None instead.
Because form.valid() is False
form.errors is returning:
<ul class="errorlist"><li>id<ul class="errorlist"><li>This field is required.</li></ul></li></ul>
<ul class="errorlist"><li>action<ul class="errorlist"><li>This field is required.</li></ul></li><li>meeting<ul class="errorlist"><li>This field is required.</li></ul></li><li>id<ul class="errorlist"><li>This field is required.</li></ul></li></ul>
<ul class="errorlist"><li>action<ul class="errorlist"><li>This field is required.</li></ul></li><li>meeting<ul class="errorlist"><li>This field is required.</li></ul></li><li>id<ul class="errorlist"><li>This field is required.</li></ul></li></ul>
But I can see in the template that each record has a meeting assigned to it in the dropdown...
The view meetings.views.actionItemsView didn't return an HttpResponse object. It returned None instead.
Given this is the error, it's saying that you are not returning any HTTPRESPONSE, which is true since you don't have any return statements if it's a POST request.
if request.method == "POST":
action_formset = ActionFormSet(request.POST, request.FILES,queryset=Actions.objects.filter())
for action_form in action_formset:
print(action_form.errors)
if action_form.is_valid():
action = action_form.save()
All methods in views.py are required to return an HTTPRESPONSE, so simply try to add any kind of HTTP response in there and it should solve your problem.
I am making a small web application that allow user to perform OCR on the selected image and provides the JSON output in a tabular Format like this.
JSON DATA :
{
"data": {
"test_1": {
"test_name": "FASTING SUGAR",
"results": "121.00",
"units": "mg%",
"low_range": 70.0,
"high_range": 110.0
}
}
}
What I'm facing now is when I'm selected new image to add values in the table, it overrides the values instead of appending.
And what I want is to append new value in the table by choosing another image, the previous row show me stay as it is and new will get append.
So that finally I can submit all the values to the database all together by clicking on the submit button.
Here is my template code :
<form method="post">{% csrf_token %}
<div class="table-responsive">
<table id="datatable2" class="table order-column hover">
<thead>
<tr>
<th>Investigation Name</th>
<th>Result</th>
<th>UOM</th>
<th>Low Range</th>
<th>High Range</th>
</tr>
</thead>
<tbody>
{% for key, value in data.items %}
{% for key2,value2 in value.items %}
<tr class="gradeX">
<td>{{ value2.test_name }}</td>
<td>{{ value2.results }}</td>
<td>{{ value2.units }}</td>
<td>{{ value2.low_range }}</td>
<td>{{ value2.high_range }}</td>
</tr>
{% endfor %}
{% endfor %}
</tbody>
</table>
</div>
<!--end .table-responsive -->
<button type="submit" class="btn btn-primary" name="data">Submit</button>
</form>
And my views.py
from django.shortcuts import render, redirect
import json
import urllib.request
from .models import Panel
from django.contrib import messages
from .forms import PanelForm, SingleDataForm
def photo_single(request):
if request.method=='POST':
form = PanelForm(request.POST, request.FILES)
form1 = SingleDataForm()
if form.is_valid():
print("valid")
temp,data = form.save()
return render(request, 'album/photo_single.html', {'data': data, 'form1':form1, 'form': form})
#return redirect('photo_list')
else:
form = PanelForm()
if request.method=='POST' and 'data' in request.POST:
form1 = SingleDataForm(request.POST)
if form1.is_valid():
print("INside this loop")
if form1.save():
print("INside this loop")
return redirect('album/photo_single.html', messages.success(request, 'Order was successfully created.', 'alert-success'))
else:
return redirect('album/photo_single.html', messages.error(request, 'Data is not saved', 'alert-danger'))
else:
return redirect('album/photo_single.html', messages.error(request, 'Form is not valid', 'alert-danger'))
else:
form1 = SingleDataForm()
return render(request, 'album/photo_single.html', {'form': form, 'form1':form1})
How can we use list in DTL to store the previous values and stay as it is and the new value just get append in the next row.. ?
I'm new in Django. Please Guide. Thanks.
I have a shipment_details form where have some information about shipment and all item in that order of the shipments. There is two model information one Shipment another is Items model. I want to update all Marco Item Shipped value using the checkbox( see the form view pics).
here is my form view
http://imgur.com/a/dcNZE
Here is my forms.py where I linked up checkbox to Items is_shipped field and this value show in the view using {{form_status.as_p}}.
forms.py
class ShipmentStatus(forms.CheckboxInput):
input_type = 'checkbox'
class ShipmentStatusForm((forms.ModelForm)):
class Meta:
model = Items
fields = ['is_shipped']
widgets = {
'is_shipped': ShipmentStatus(),
}
Here is my view model
shipment_detail.html
{% extends "_dashboardlayout.html" %}
{% block content %}
<div id="page-wrapper">
<div class="row">
<div class="col-lg-12">
<h2 class="page-header">Shipment Details</h2>
</div>
<div class="col-md-12">
<form method="POST" action="">
{% csrf_token %}
{{ form.as_p }}
<table class="table table-striped">
<tr>
<th>Item No</th>
<th>SKU</th>
<th>Quantity</th>
<th>Price</th>
<th>Marco Item</th>
<th>Marco Item Shipped</th>
</tr>
{% for item in items_queryset %}
<tr>
<td>{{ item.item_no }}</td>
<td>{{ item.sku }}</td>
<td>{{ item.requested_quantity }}</td>
<td>{{ item.price }}</td>
<td>{{ item.is_send }}</td>
<td>{{ form_status.as_p }}</td>
</tr>
{% endfor %}
</table>
<input type="submit" value="Save">
</form>
</div>
</div>
<!-- /.row -->
</div>
{% endblock %}
Here is my control py file
def shipment_detail(request, order_id=None):
order_queryset = Order.objects.get(order_id=order_id)
customer_queryset = Customer.objects.all()
address_queryset = Address.objects.all()
items_queryset = Items.objects.filter(order_id=order_id).order_by('item_no')
shipment_queryset = Shipment.objects.filter(order_id=order_id)
# if there is no shipment data then generate shipment details for the Order
if not shipment_queryset:
form = ShipmentForm(request.POST or None)
form_status = ShipmentStatusForm(request.POST or None)
if form.is_valid():
instance = form.save(commit=False)
instance.order_id = order_queryset
order_queryset.save()
instance.save()
# save item status
if form_status.is_valid():
instance = form_status.save(commit=False)
instance.save()
context = {
"form": form,
"form_status": form_status,
"order_queryset": order_queryset,
"customer_queryset": customer_queryset,
"address_queryset": address_queryset,
"items_queryset": items_queryset,
}
return render(request, "shipment_detail.html", context)
# if there is already data then updated the shipment details for the Order
else:
instance = get_object_or_404(Shipment, order_id=order_id)
form = ShipmentForm(request.POST or None, instance=instance)
if form.is_valid():
instance = form.save(commit=False)
instance.order_id = order_queryset
# updated order is_shipped field according to ship_status
if instance.status == True:
order_queryset.is_shipped = True
if instance.status == False:
order_queryset.is_shipped = False
# updated order is_completed field according to shipment is_complete field
if instance.is_complete == True:
order_queryset.is_completed = True
if instance.is_complete == False:
order_queryset.is_completed = False
order_queryset.save()
instance.save()
print "form status"
# updated item is_shipped field
instance_status = get_list_or_404(Items, order_id=order_id)
for instance in instance_status:
form_status = ShipmentStatusForm(request.POST, instance=instance)
if form_status.is_valid():
instance = form_status.save(commit=False)
instance.save()
context = {
"form": form,
"instance": instance,
"form_status": form_status,
"order_queryset": order_queryset,
"customer_queryset": customer_queryset,
"address_queryset": address_queryset,
"items_queryset": items_queryset,
}
return render(request, "shipment_detail.html", context)
Here problem is when click all the Marco Item Shipped true or false its save value properly but if I click one false another true then it doesn't save value.
One way to do this is use pk of an object as value of check box
<input type="checkbox" value='{{item.id}}'
name='for_action' id='for_action' >
, You can get list of these pk in your views using request.POST.getlist('for_action')
Here You Go!!
HTML:
<div class="col-lg-12">
<h2 class="page-header">Shipment Details</h2>
</div>
<div class="col-md-12">
<form method="POST" action="">
{% csrf_token %}
{{ form.as_p }}
<table class="table table-striped">
<tr>
<th>Item No</th>
<th>SKU</th>
<th>Quantity</th>
<th>Price</th>
<th>Marco Item</th>
<th>Marco Item Shipped</th>
</tr>
{% for item in items_queryset %}
<tr>
<td>{{ item.item_no }}</td>
<td>{{ item.sku }}</td>
<td>{{ item.requested_quantity }}</td>
<td>{{ item.price }}</td>
<td>{{ item.is_send }}</td>
<td><input type="checkbox" value='{{item.id}}'
name='for_action' id='for_action' ></td>
</tr>
{% endfor %}
</table>
<input type="submit" value="Save">
</form>
</div>
</div>
<!-- /.row -->
{% endblock %}
views.py
def shipment_detail(request, order_id=None):
#########
# save item status
list_of_id_for_action = request.POST.getlist('for_action')
list_of_obj = Items.objects.filter(pk__in=list_of_id_for_action)
list_of_obj.update(is_shipped=True)
######
context = {
"form": form,
"instance": instance,
"form_status": form_status,
"order_queryset": order_queryset,
"customer_queryset": customer_queryset,
"address_queryset": address_queryset,
"items_queryset": items_queryset,
}
Hope this helps
I have an Expense model and an ExpenseLineItem model. Just like a typical expense/invoice, one expense can have several line items to make up the total cost of an invoice. I'm trying to use class based views to create and update expenses. I've successfully coded the CreateView to make a new expense with multiple expense line items.
My problem is when I try and update an existing Expense which already has several expense line items. Here's my code below, and I can't figure out what the issue is. The mixins (TitleMixin, CancelSuccessMixin, SelectedApartment)are mine and work fine.
I'm getting an error that, I believe, means that it's trying to save a new copy of the ExpenseLineItems but fails since those already exist. Almost like I'm not providing an instance argument.
What am I doing wrong?
forms.py
class ExpenseForm(ModelForm):
class Meta:
model = Expense
fields = ['apart', 'inv_num', 'vendor', 'due_date']
ExpenseLineItemFormset = inlineformset_factory(Expense, ExpenseLineItem, fields=('description', 'account', 'amt'), can_delete=False)
Here's my ExpenseUpdate view:
class ExpenseUpdate(TitleMixin, CancelSuccessMixin, SelectedApartment, UpdateView):
model = Expense
form_class = ExpenseForm
template_name = 'accounting/expense.html'
def get(self, request, *args, **kwargs):
self.object = self.get_object()
form_class = self.get_form_class()
form = self.get_form(form_class)
expense_line_item_form = ExpenseLineItemFormset(instance = self.object)
return self.render_to_response(self.get_context_data(form = form, expense_line_item_form = expense_line_item_form))
def post(self, request, *args, **kwargs):
self.object = self.get_object()
form_class = self.get_form_class()
form = self.get_form(form_class)
expense_line_item_form = ExpenseLineItemFormset(self.request.POST, instance=self.object)
if (form.is_valid() and expense_line_item_form.is_valid()):
return self.form_valid(form, expense_line_item_form)
return self.form_invalid(form, expense_line_item_form)
def form_valid(self, form, expense_line_item_form):
self.object = form.save()
expense_line_item_form.instance = self.object
expense_line_item_form.save()
return HttpResponseRedirect(self.get_success_url())
def form_invalid(self, form, expense_line_item_form):
return self.render_to_response(self.get_context_data(form=form, expense_line_item_form=expense_line_item_form))
Error code I get:
MultiValueDictKeyError at /stuff/2/accounting/update-expense/25/
"u'expenselineitem_set-0-id'"
Request Method: POST
Request URL: http://localhost:8000/stuff/2/accounting/update-expense/25/
Django Version: 1.8.3
Exception Type: MultiValueDictKeyError
Exception Value:
"u'expenselineitem_set-0-id'"
Exception Location: /usr/local/lib/python2.7/dist-packages/django/utils/datastructures.py in __getitem__, line 322
Edit: Relevant part of my template:
<form class="form-horizontal" action="" method="post">
{% csrf_token %}
{% load widget_tweaks %}
<div class="row">
<div class="col-md-12">
<table class="table table-tight">
<thead>
<th>Description</th>
<th class="text-right">Account</th>
<th class="text-right">Amount</th>
</thead>
<tbody>
{{ expense_line_item_form.management_form }}
{% for eli in expense_line_item_form %}
<tr>
<td>{{ eli.description|attr:'cols:29' }}</td>
<td class="text-right">{{ eli.account }}</td>
<td class="text-right">{{ eli.amt }}</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
<div class="col-md-12 text-right">
Cancel
<input class="btn btn-success btn-lg" type="submit" value="Post" />
</div>
<br><br>
</form>
EDIT -- Working Form Template I thought I would add the working version of my template, should someone else need it:
<tbody>
{{ expense_line_item_form.management_form }}
{% for eli in expense_line_item_form %}
<tr>
<td>{{ eli.id }} {{ eli.description|attr:'cols:29' }}</td> <!-- <<==== Here's where I simply added {{ eli.id }}. That's all I changed :) -->
<td class="text-right">{{ eli.account }}</td>
<td class="text-right">{{ eli.amt }}</td>
</tr>
{% endfor %}
</tbody>
You need to include the form id for each form in the formset (it won't be shown to the user, as it is rendered as a hidden input). Without that form, the value is missing from the POST data, and you get a KeyError as you are seeing.
From the formset docs:
Notice how we need to explicitly render {{ form.id }}. This ensures that the model formset, in the POST case, will work correctly. (This example assumes a primary key named id. If you’ve explicitly defined your own primary key that isn’t called id, make sure it gets rendered.)
In your case, you are looping through the formset with {% for eli in expense_line_item_form %}, so you need to include {{ eli.id }}.
i'm trying to use model formsets with Django. When i load forms template, i see that it's filled-up with previous values. Is there a caching mechanism that i should stop, or what?
Thanks for your help, here is my code:
models.py
class FooModel( models.Model ):
a_field = models.FloatField()
b_field = models.FloatField()
def __unicode__( self ):
return self.a_field
forms.py
from django.forms.models import modelformset_factory
FooFormSet = modelformset_factory(FooModel)
views.py
def foo_func(request):
if request.method == 'POST':
formset = FooFormSet(request.POST, request.FILES, prefix='foo_prefix' )
if formset.is_valid():
formset.save()
return HttpResponseRedirect( '/true/' )
else:
return HttpResponseRedirect( '/false/' )
else:
formset = FooFormSet(prefix='foo_prefix')
variables = RequestContext( request , { 'formset':formset , } )
return render_to_response('footemplate.html' , variables )
template:
<form method="post" action=".">
{% csrf_token %}
<input type="submit" value="Submit" />
<table id="FormsetTable" border="0" cellpadding="0" cellspacing="0">
<tbody>
{% for form in formset.forms %}
<tr>
<td>{{ form.a_field }}</td>
<td>{{ form.b_field }}</td>
</tr>
{% endfor %}
</tbody>
</table>
{{ formset.management_form }}
</form>
The main problem here is in line:
formset = FooFormSet(prefix='foo_prefix')
When you instantiate FooFormSet() the queryset used to generate the forms is (by default):
FooModel.objects.all()
So, if you already have some FooModel() in your database they will be listed. In this case you can use:
formset = FooFormSet(prefix='foo_prefix', queryset=FooModel.objects.none())
You can see more information about this in Django's Documentation:
http://docs.djangoproject.com/en/dev/topics/forms/modelforms/#changing-the-queryset