Django tabular input form (user can key in data into table) - django

I attempt to create a tabular input form. User can key in data into the table cells. The table should have 100 rows. The following is an illustration of the end goal.
However, if such table is not possible, a suggestion to create the following table is also welcomed!
This is what I have tried:
forms.py
class SampleInputForm(forms.Form):
x = forms.FloatField()
y = forms.FloatField()
views.py
class ToolView(View):
def get(self, request):
table_rows = 10
sample_form_set_factory = formset_factory(SampleInputForm, extra = table_rows)
sample_form_set = sample_form_set_factory()
context = {
'sample_form' : sample_form_set,
}
return render(request, 'tools/tools.html', context)
html file
{% csrf_token %}
<form method="post">
<table>
<tr>
<th>Input</th>
<th>Output</th>
</tr>
{{sample_form}}
</table>
</form>
However, this attempt does not form a table. The Y input field is displayed below the X, hence not forming a table.

formset_factory is iterable , so in template you can do this
<form method="post">
<table>
<thead>
<tr>
<th>Input</th>
<th>Output</th>
</tr>
</thead>
<tbody>
{% for form in sample_form %}
<tr>
<th>
{{ form.x }}
</th>
<th>
{{ form.y }}
</th>
</tr>
{% endfor %}
</tbody>
</table>
</form>

Related

Bootstrap Table not sending selected checkbox values in POST request in Django app

I am using Bootstrap Table (https://bootstrap-table.com/) to display a product list in a Django app. I would like the user to select some products and click the button to submit. Using Bootstrap Table seems to prevent the checked checkboxes being sent in the POST request.
views.py
class ProductProcessView(View):
def post(self, request):
products = request.POST.getlist('product_checkboxes')
# process the chosen products
return redirect('product-list')
html template
<form method="post">
{% csrf_token %}
<table class="table-striped"
data-toggle="table"
>
<thead>
<tr>
<th data-field="product_id" data-checkbox="true"></th>
<th data-field="product">Product</th>
</tr>
</thead>
{% for product in product_list %}
<tr>
<td><input type="checkbox" name="product_checkboxes" value="{{ product.id }}"></td>
<td>{{ product.short_name }}</td>
</tr>
{% endfor %}
</table>
<button onclick="location.href='{% url 'process-products' %}'">Select Products</button>
</form>
If I remove the line data-toggle="table" this correctly sends the selected product IDs in the POST request, but with that line included it does not send any IDs at all. Bootstrap Table requires the data-toggle="table" attribute to initialise the table so without it there is no formatting.
This is the request.body with data-toggle="table" included:
<QueryDict: {'csrfmiddlewaretoken': ['fOma6gtvG2ETw1hrVYMdIuSUWuE1RA2jpX2Tae7ntipMPGX4yKNYEGgkHD0Jcuco'], 'btSelectItem': ['on', 'on']}>
This is without it:
<QueryDict: {'csrfmiddlewaretoken': ['Si6UyiTZ4yAJNYKKQ9FtA8dk0gNPGTPp2rMDCgxRROlC6DqntVGewkBKLp9x1NZu'], 'product_checkboxes': ['43004', '43006']}>
I would be very grateful for any ideas about how I can use the Bootstrap Table framework with it's formatting and widgets, but still be able to use checkboxes to collect the product data.
You can't rely on your HTML because it is dynamically replaced by BootstrapTable.
So you need to use its API to retrieve the values. The simplest way is to add script to the page which will get values from table and assign on some (hidden) element in the form.
Then - on Python side you will read this field and process the data.
See example (uses JQuery but can be converted to plain JS):
<script>
$(document).ready(function () {
$('#product-form').on('submit', function () {
const table = $('#products').bootstrapTable('getSelections')
$('#checkboxes').val(JSON.stringify(table))
})
})
</script>
Some corrections to the template:
Add ID to form
Include product ID as hidden column
Add hidden element which will pass content via form
html template:
<form method="post" id="product-form">
{% csrf_token %}
<table id="products" class="table-striped" data-toggle="table">
<thead>
<tr>
<th data-field="product_check" data-checkbox="true"></th>
<th data-field="product_id" data-visible="false">ID</th>
<th data-field="product">Product</th>
</tr>
</thead>
<input id="checkboxes" name="product_checkboxes" style="display: none">
{% for product in product_list %}
<tr>
<td><input type="checkbox" data-id="{{ product.id }}" value="{{ product.id }}"></td>
<td>{{ product.id }}</td>
<td>{{ product.short_name }}</td>
</tr>
{% endfor %}
</table>
<button id="select-products" onclick="location.href='{% url 'process-products' %}'">Select Products</button>
</form>
And finally - getting the data in views.py:
def post(self, request):
products = json.loads(request.POST.get('product_checkboxes'))
# process the chosen products
return redirect('product-list')
Note that in this case products will be a list of objects. Each object has values that are correspondent to columns

Django Form Not Validating my Date fields

I have a Search form that includes the query box, some checkbox items, and a start and end date. I am getting my information when I enter a query, so I know it is performing the search_results action, but the start and end date is not getting validated at all. I have yet to add the code to handle the start and end date in my results, but the issue is there is no client side validation happening on the form.
My form looks like this:
class SearchForm(forms.Form):
q = forms.CharField(max_length=64,required=False)
service_choices = forms.MultipleChoiceField(
required=True,
widget=forms.CheckboxSelectMultiple,
choices=CustomUser.SERVICE_CHOICES,
)
start_date = forms.DateField(required=False)
end_date = forms.DateField(required=False)
I tried using Class Based View, but did not get any fields at all, so I
tried using a function based view to get my search criteria.
The view looks like:
def get_search(request):
form = SearchForm()
return render(request, 'get_search.html', {'form':form})
My template is:
<!-- templates/get_search.html -->
{% extends "base.html" %}
{% block title %}Search{% endblock title %}
{% block content %}
{% if user.is_authenticated %}
<br><br>
<TABLE BORDER="0" WIDTH="100%">
<TR>
<TD ALIGN="Left"><B>Track X - search</B></TD>
<TD ALIGN="Center"><B>User: {{ user }}</B></TD>
<TD ALIGN="Right"><B>Service: {{ user.service }}</B></TD>
</TR>
</TABLE>
<form action="{% url 'search_results' %}" method="get"">
{% csrf_token %}
<TABLE BGCOLOR="#66CCCC" Border="2" WIDTH="100%">
<TR>
<TD ALIGN="Left" WIDTH="100"> Services:</TD>
<TD ALIGN="Right">Search expression:</TD>
<TD ALIGN="Left">
{{ form.q }}
<button type="submit" name="submit">Search TrackX</button>
</TD>
</TR>
<TR>
<TD WIDTH="100"> {{ form.service_choices }} </TD>
<TD COLSPAN="2" ALIGN="Center"> Start Date: {{ form.start_date }}
End Date: {{ form.end_date }}</TD>
</TR>
</TABLE>
</form>
{% else %}
<p>You are not logged in</p>
Log In |
Sign Up
{% endif %}
{% endblock content %}
The Search_results view just uses the query to build some Q Filter
queries, and it seems to be working correctly.
It originally used a GET Method, and was passing the parameters into the search results view just fine. It just doesn't validate the dates (or anything else I assume) before passing the parameters into the view.
Can anyone tell me what am I missing here?
As I see on the view that your posted, you are not actually checking if the form is valid, you can do that by using:
if request.method == 'POST':
form = SearchForm(request.POST)
form.is_valid()
This method will validate all your fields, and return the boolean value representing if its valid or not.

Django - ModelForm - UpdateView -pk

I would like to implement UpdateView in order to update selected objects of my Model.
Currently I have:
views.py
def fd_detail(request, fdslug):
fddetail = Fd.objects.get(slug=fdslug)
cffilter = CashFlowFilter(request.GET, queryset=CashFlow.objects.filter(feeder__slug=fdslug))
return render(request, 'fd/fd_detail.html',
{'fddetail': fddetail,
'cffilter': cffilter,
})
class CashFlowUpdate(UpdateView):
model = CashFlow
fields = ['amount', 'description']
url.py
path('<slug:fdslug>/updatecashflow/', views.CashFlowUpdate.as_view(),name = "update_cashflow"),
path('<slug:fdslug>/', views.fd_detail, name="fd_detail")
update_cashflow.html
<form method="post">
{% csrf_token %}
{{ form.as_p }}
<input type="submit" value="Update">
</form>
I get the following error : " Generic detail view CashFlowUpdate must be called with either an object pk or a slug in the URLconf." , which means i need to pass-through the primary key of the object I want to Update... What is the best way to do it? Currently all my objects are displayed via a table (see below)? i could add a column with a url link "Edit", but how to put the pk in it?
<table class="table table-bordered">
<thead>
<tr>
<th>Amount</th>
<th>Description</th>
<th>Edit</th>
</tr>
</thead>
<tbody>
{% for cashflow in cffilter.qs %}
<tr>
<td> {{cashflow.amount}} </td>
<td> {{cashflow.description}} </td>
<td> ?????? </td>
</tr>
{% empty %}
<tr>
<td colspan="5"> No cashflow matches your search criteria</td>
</tr>
{% endfor %}
</tbody>
</table>
many thanks
Like the error says:
Generic detail view CashFlowUpdate must be called with either an object pk or a slug in the URLconf.
An update view usually needs some kind of URL parameter to determine which object to update. It implicitly aims to check for two fields: the slug and the primary key. But here in your urls.py, you used fdslug as a URL parameter.
This can easily be resolved by specifying a slug_url_kwarg [Django-doc] yourself, like:
class CashFlowUpdate(UpdateView):
model = CashFlow
fields = ['amount', 'description']
slug_url_kwarg = 'fdslug'
As for an edit link, you can add a {% url ... %} template tag, like:
<td>edit</td>

how to get flat value from muitiple values_list? Django database

I am getting postgresql data from my server and fill out the table down below.
I was able to join 3 different tables and get columns I want from them.
However, it gives me none-formatted object. Is there any way I can fill out the table using joined query one by one..?
enter image description here
enter image description here
views.py
vlan_query_results = Vlans.objects.select_related('vlan_id').values_list('name', 'gateways__vip', 'gateways__backup', 'gateways__master', 'gateways__nat', 'gateways__vhid', 'subnets__dhcp', 'subnets__dns').order_by('vlan_id')
template
{% for object in vlan_query_results %}
<tr #id='items-table'>
<th scope="row" class="checkbox-row"><input type="checkbox" name="item" /></th>
<th scope="row">{{ forloop.counter }}</th>
<td class="item"> {{object }}</td>
<td class="item"> </td>
</tr>
{% endfor %}
Maybe instead using values_list, you should use DRF Serializers to get the response in a dictionary like structure with only the fields you want.
from rest_framework import serializers
class VlansSerializer(serializers.ModelSerializer):
gateways_vip = serializers.ReadOnlyField(source='gateways__vip')
gateways_backup = serializers.ReadOnlyField(source='gateways__backup')
gateways_master = serializers.ReadOnlyField(source='gateways__master')
gateways_nat = serializers.ReadOnlyField(source='gateways__nat')
gateways_vhid = serializers.ReadOnlyField(source='gateways__vhid')
subnets_dhcp = serializers.ReadOnlyField(source='subnets__dhcp')
subnets_dns = serializers.ReadOnlyField(source='subnets__dns')
class Meta:
model = Vlans
fields = ('name', 'gateways_vip', 'gateways_backup', 'gateways_master', 'gateways_nat', 'gateways_vhid', 'subnets_dhcp', 'subnets_dns')
In your views.py:
vlan_query_results = VlansSerializer(Vlans.objects.all(), many=True).data
In your html:
{% for object in vlan_query_results %}
<tr>
<th scope="row" class="checkbox-row">
<input type="checkbox" name="item" />
</th>
<th scope="row">{{ forloop.counter }}</th>
<td class="item">{{object.name}}</td>
<td class="item">{{object.gateways_vip}}</td>
</tr>
{% endfor %}
You have to add the rest of the <td></td> tags in a similar manner.
Also, you cant add the #id='items-table' to the <tr> since it is in a loop and ids are supposed to be unique in a html page.
Hope this helps. :)

model object not iterable

template.html
{% extends "base.html" %}
<body>
{% block content %}
<form action="." method="post">
{% csrf_token %}
<table align="center" style="margin-left:60px";>
<p>{{KEBReading_form.as_table}}</p>
<tr><td colspan="2" align="right"><input name="KEBsubmit" type="submit" value="Submit Reading" id="_KEBsubmit1"/> </td></tr>
<tr><td colspan="2" >{{KEBMessage}} </td></tr>
</table>
</form>
<table border="1">
<p> KEB Reading as on Month jan and year 2012</p>
<tr>
<th>Date </th>
<th>Time</th>
<th>True Power Reading</th>
<th>Apparent Power Reading</th>
<th>True Power consumed</th>
<th>Voltage Reading</th>
<th>Power Factor</th>
</tr>
{% for item in q2 %}
<tr>
<td>{{item.date}}</td>
<td>{{item.time}}</td>
<td>{{item.truepower_reading}}</td>
<td>{{item.apparentpower_reading}}</td>
<td>{{item.truepower_consumed}}</td>
<td>{{item.voltage_reading}}</td>
<td> {{item.powerfactor}}</td>
</tr>
{% endfor %}
</table>
{% endblock content %}
views.py
def KEBReading1(request):
#form2 = KEBReading.objects.all()
if request.method == "POST":
form = KEBReading_form(request.POST)
if form.is_valid():
prevdate=KEBReading.objects.latest("date")
# Model.objects.latest('field')
print prevdate.date
print prevdate.time
# q1 = KEBReading.objects.get(datetime.date.today()-datetime.timedelta(0))
kr_truepower_reading = form.cleaned_data["truepower_reading"]
kr_apparentpower_reading = form.cleaned_data["apparentpower_reading"]
truepower_consumed1=kr_truepower_reading-prevdate.truepower_reading
powerfactor1=((kr_truepower_reading-prevdate.truepower_reading)/(kr_apparentpower_reading-prevdate.apparentpower_reading))
#instance=truepower_consumed,powerfactor
## replace form.save() with following lines
form1=form.save(commit=False)
#form1.calculate(truepower_consumed1,powerfactor1)
form1.truepower_consumed=truepower_consumed1
form1.powerfactor=powerfactor1
print form1.powerfactor
form1.save()
q2=KEBReading.objects.latest("date")
context={'KEBReading_form':form,'q2':q2}
return render_to_response('keb.html',context,context_instance=RequestContext(request))
else:
form = KEBReading_form()
return render_to_response('keb.html',{'KEBReading_form':form},context_instance=RequestContext(request))
i want to display all readings in a table whic i calculated through the views in the template. i get model object not iterable while using for loop to iterate..
A few issues:
First, as Aidan correctly noted KEBReading.objects.latest("date") this will return an object, not a collection or iterable.
Secondly, you aren't assigning any of the fields that you are calculating in view. truepower_consumed1=kr_truepower_reading-prevdate.truepower_reading doesn't assign it to your object that you retrieved (your q2). I'm not sure if this is intentional. However, I suspect you want to return to your template the instance of the form, not another record from the table. You need to update your question.
To fix these problems immediately:
<tr>
<td>{{q2.date}}</td>
<td>{{q2.time}}</td>
<td>{{q2.truepower_reading}}</td>
<td>{{q2.apparentpower_reading}}</td>
<td>{{q2.truepower_consumed}}</td>
<td>{{q2.voltage_reading}}</td>
<td> {{q2.powerfactor}}</td>
</tr>
latest() returns the latest object in the table, not a set of objects. Instead of that, you should use KEBReading.objects.all().order_by('date')
Your q2 variable is just an object not a set.
The following line returns a single object -
KEBReading.objects.latest("date")
But your template is expecting a set that it can iterate over -
{% for item in q2 %}
<tr>
<td>{{item.date}}</td>
<td>{{item.time}}</td>
<td>{{item.truepower_reading}}</td>
<td>{{item.apparentpower_reading}}</td>
<td>{{item.truepower_consumed}}</td>
<td>{{item.voltage_reading}}</td>
<td> {{item.powerfactor}}</td>
</tr>
{% endfor %}
Check the docs for the latest() function.