django formsets can_delete header - python

I am new to django , please bear with me ..
created a template using django formsets and it works all good except i am not able to give header to the can_delete column .
My Django views.py looks like :
def add_expenditure(request):
context = RequestContext(request)
ExpFormSet = modelformset_factory(Expenditure,extra=1,max_num=10,fields=('exp_date', 'description','amount'),can_delete=True)
if request.method == 'POST':
formset = ExpFormSet(request.POST)
if formset.is_valid():
formset.save(commit=True)
formset = ExpFormSet()
else:
print "errors in formset are ",formset.errors
else:
formset = ExpFormSet(queryset=Expenditure.objects.none())
return render_to_response('moni/add_expenditure.html', {'formset':formset}, context)
templete form code is as below :
<form id="expenditure_form" method="post" action="/moni/add_expenditure/">
{% csrf_token %}
<table border=10>
<tr>
<th>Serial No.</th>
<th><label >Date:</label></th>
<th><label for="id_description">Description:</label></th>
<th><label for="id_amount">Amount</label></th>
</tr>
{{ formset.management_form }}
{% for form in formset %}
<tr>
<td>{{forloop.counter}}</td>
{% for field in form %}
<td> {{ field.class }} {{ field }}
{% if field.name == "exp_date" %}
<a href="javascript:void(0)" class="todaylink" id= {{forloop.parentloop.counter0}} >Today</a>
{% endif %}
</td>
{% endfor %}
</tr>
<br>
{% endfor %}
</table>
<input type="submit" name="submit" value="Create Expenditure" />
</form>
and template looks like :
What i want is to have a header for delete check box as well .. just next to amount . I tried adding one more header but seems its not working as intended . Can someone provide any advices .. Below is how it looks after adding one more header
<form id="expenditure_form" method="post" action="/moni/add_expenditure/">
{% csrf_token %}
<table border=10>
<tr>
<th>Serial No.</th>
<th><label >Date:</label></th>
<th><label for="id_description">Description:</label></th>
<th><label for="id_amount">Amount</label></th>
<th><label for="id_delete">Delete</label></th>
</tr>
{{ formset.management_form }}
{% for form in formset %}
<tr>
<td>{{forloop.counter}}</td>
{% for field in form %}
<td> {{ field.class }} {{ field }}
{% if field.name == "exp_date" %}
<a href="javascript:void(0)" class="todaylink" id= {{forloop.parentloop.counter0}} >Today</a>
{% endif %}
</td>
{% endfor %}
</tr>
<br>
{% endfor %}
</table>
<input type="submit" name="submit" value="Create Expenditure" />
</form>
Any Advice as to how to create this header above delete check box ?

The problem is
{% for field in form %}
<td> {{ field.class }} {{ field }}
{% if field.name == "exp_date" %}
<a href="javascript:void(0)" class="todaylink" id= {{forloop.parentloop.counter0}} >Today</a>
{% endif %}
</td>
{% endfor %}
This create 5 TD and you have 4 TD in header.
Please try this
<tr>
<th>Serial No.</th>
<th><label >Date:</label></th>
<th><label for="id_description">Description:</label></th>
<th><label for="id_amount">Amount</label></th>
<th></th>
<th><label for="id_delete">Delete</label></th>
</tr>
Also you can remove element before delete checkbox.

Related

Search result does not show up

I am trying to create a database search engine using sqlite3, Python Flask and HTML in Visual Studio Code. I want to fetch title and attribution where title contains user's search input.
app.py :
#app.route("/explore", methods=["GET", "POST"])
#login_required
def explore():
if request.method == "GET":
return render_template("explore.html")
else:
search = request.form.get("search")
conn = sqlite3.connect("project.db")
cur = conn.cursor()
query = cur.execute("SELECT title, attribution FROM objects WHERE title LIKE ?", [search])
cols = ["object_title", "attribution"]
conn.commit()
results= pd.DataFrame(query.fetchall(), columns=cols)
conn.close()
return render_template('searchresult.html', results=results)
explore.html (search engine):
{% extends "layout.html" %}
{% block title %}
Explore Artworks
{% endblock %}
{% block main %}
<form action="/explore" method="POST">
<div class="mb-3">
<input autocomplete="on" autofocus class="form-control mx-auto w-auto" name="search" placeholder="Artist or Artwork" type="text">
</div>
<button class="btn btn-outline-primary" type="submit">Search</button>
</form>
{% endblock %}
searchresult.html :
{% extends "layout.html" %}
{% block title %}
Search Result
{% endblock %}
{% block main %}
<table>
<thead>
<td> Title </td>
<td> Attribution </td>
</thead>
{% for result in results %}
<tr>
<td> {{ result["object_title"] }}</td>
<td> {{ result["attribution"] }}</td>
</tr>
{% endfor %}
</table>
{% endblock %}
However, search result page only shows an empty table:
searchresult.html with empty table

dynamically change SubmitField's label/value in html Flask WTForm

I have created a Flask WTForm. I used the form for Add/Edit/Delete purpose. I want dynamically change label/value of the SubmitField according to the purpose
Form Class
class UserForm(Form):
username = StringField('User Name',validators=[validators.required(), validators.Length(max=32)])
password = PasswordField('Password',validators=[validators.required(), validators.Length(min=8, max=16)])
confirm_password = PasswordField('Confirm Password',validators=[validators.required(), validators.EqualTo('password', message='Both password fields must be equal !')])
name = StringField('Name',validators=[validators.required(), validators.Length(max=32)])
submit = SubmitField('Submit')
HTML Template
<title>User Form</title>
{% with messages = get_flashed_messages(with_categories=true) %}
{% if messages %}
<ul>
{% for message in messages %}
<li>{{ message[1] }}</li>
{% endfor %}</ul>
{% endif %}
{% endwith %}
<table height="100%" width="100%" >
<tr><td align="center" valign="middle">
<form method="post" action="/process/{{ option }}">
<table>
{{form.csrf }}
<tr><td>{{ form.username.label }}</td></tr>
<tr><td>
{% if option == "new" %}
{{ form.username() }}
{% else %}
{{ form.username(readonly=true) }}
{% endif %}
</td></tr>
<tr><td>{{ form.password.label }}</td></tr>
<tr><td>{{ form.password }}</td></tr>
<tr><td>{{ form.confirm_password.label }}</td></tr>
<tr><td>{{ form.confirm_password }}</td></tr>
<tr><td>{{ form.name.label }}</td></tr>
<tr><td>{{ form.name }}</td></tr>
{% if option == "new" %}
{{ form.submit() }} **submit label with 'New'
{% else %}
{{ form.submit() }} **submit label with 'Edit'
{% endif %}
</table>
</form>
</td>
</tr>
</table>
Update the label at runtime in your view:
For example:
from wtforms import Label
def some_view():
_form = UserForm()
_form.submit.label = Label(_form.submit.id, 'New' if option == 'new' else 'Edit')
return render_template('index.html', form=_form)
Edit November 2022
It's even easier to simply modify the label's instance text property.
def some_view():
_form = UserForm()
_form.submit.label.text = 'New' if option == 'new' else 'Edit'
return render_template('index.html', form=_form)

How To Populate Table With Filtered Data in Django

I am attempting to populate a table with a filtered set of data from my Manifests model using a url parameter.
I believe that the problem I am having is in the Views.py line
manifests = Manifests.objects.all().filter(reference=reference_id)
Models.py
class Manifests(models.Model):
reference = models.ForeignKey(Orders)
cases = models.IntegerField()
description = models.CharField(max_length=1000)
count = models.IntegerField()
def __str__(self):
return self.description
Urls.py
url(r'^add_manifest/(?P<reference_id>\d+)/$', add_manifest, name='add_manifest'),
Views.py
def add_manifest(request, reference_id):
if request.method == "POST":
form = CreateManifestForm(request.POST)
if form.is_valid():
instance = form.save(commit=False)
try:
order = Orders.objects.get(id=reference_id)
except Orders.DoesNotExist:
pass
instance.reference = order
instance.save()
return redirect('add_manifest', reference_id=reference_id)
form = CreateManifestForm()
#manifests = Manifests.objects.all()
manifests = Manifests.objects.all().filter(reference=reference_id)
context = {
'form': form,
'reference_id': reference_id,
'manifests' : manifests,
}
return render(request, 'add_manifest.html', context)
template (add_manifest.html)
{% extends 'base.html' %}
{% block body %}
<div class="container">
<form method="POST">
<br>
<br>
<br>
{% csrf_token %}
<div class="column">
<label for="form.reference">Reference ID: </label><br>
<input type="text" value="{{ reference_id }}">
<br>
</div>
<div class="description">
<div class="column">
<label for="form.description">Description: </label>
<br>
{{ form.description}}
</div>
</div>
<div class="column">
<label for="form.cases">Cases: </label>
<br>
{{ form.cases }}
<br>
</div>
<div class="column">
<label for="form.count">Count: </label>
<br>
{{ form.count }}
<br>
<br>
</div>
<br>
<br>
<button type="submit" name="add_mani" style="border-color: #7395AE;">Add Line</button>
</form>
<br>
<h4>Manifest</h4>
<div class="table-responsive">
<table class="table table-striped table-bordered manifest_table" cellspacing="0" style="width="100%">
<thead>
<tr>
<th></th>
<th style="width:10%;">Ref ID</th>
<th style="width:10%;">Cases</th>
<th style="width:60%;">Description</th>
<th style="width:10%;">Count</th>
</tr>
</thead>
<tbody>
{% for manifests in manifests %}
<tr>
<td>
Edit
</td>
<td>{{ manifests.reference }}</td>
<td>{{ manifests.cases }}</td>
<td>{{ manifests.description}}</td>
<td>{{ manifests.count}}</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
<div class="text-center">
<button type="submit" class="btn btn-primary" name="button" align="right">Subit Manifest</button>
</div>
</div>
I want the table to display only lines where the reference in the Manifests model = the reference_id in the URL. Currently it does not work as such, the table is just empty.
Change the for-loop variable name like this:
{% for manifest in manifests %}
<tr>
<td>
Edit
</td>
<td>{{ manifest.reference }}</td>
<td>{{ manifest.cases }}</td>
<td>{{ manifest.description}}</td>
<td>{{ manifest.count}}</td>
</tr>
{% endfor %}
If there is any Manifest object for reference_id, then it will render them in template.
Update
Its possible that your form is not validating. So its a good idea to render form errors:
# view
def add_manifest(request, reference_id):
form = CreateManifestForm(request.POST or None)
if request.method == "POST":
if form.is_valid():
instance = form.save(commit=False)
try:
order = Orders.objects.get(id=reference_id)
instance.reference = order
except Orders.DoesNotExist:
pass
instance.save()
manifests = Manifests.objects.all().filter(reference=reference_id)
context = {
'form': form,
'reference_id': reference_id,
'manifests' : manifests,
}
return render(request, 'add_manifest.html', context)
And update template to show the errors in template as well:
{% if form.errors %}
{% for field in form %}
{% for error in field.errors %}
<div>
<strong>{{ error|escape }}</strong>
</div>
{% endfor %}
{% endfor %}
{% for error in form.non_field_errors %}
<div>
<strong>{{ error|escape }}</strong>
</div>
{% endfor %}
{% endif %}

non_form_errors doesn't show

I am working with inlineformset_factory and created a forms.BaseInlineFormSet to override the clean function to make some validations. the validation works and the form isn't accepted but the ValidationError message doesn't appear when the page is reloaded.
here is my form class:
class BaseDetailFormSet(forms.BaseInlineFormSet):
def clean(self):
super(BaseDetailFormSet, self).clean()
if any(self.errors):
return self.errors
for form in self.forms:
product = form.cleaned_data['product']
if form.cleaned_data['quantity_sold'] > product.quantity_in_stock:
raise forms.ValidationError(_('not enough products'))
DetailFormset = inlineformset_factory(Invoices,
InvoiceDetail,
fields=('product', 'quantity_sold'),
widgets= {'product': forms.Select(
attrs={
'class': 'search',
'data-live-search': 'true'
})},
formset=BaseDetailFormSet,
extra=1)
and my html code:
<form class="form-inline" method="post" action="">
{% csrf_token%}
{% include '_layouts/form_snippet.html' %}
<table class="table">
{{inlines.management_form}}
{%for form in inlines.forms%}
{% if forloop.first%}
<thead>
<tr>
{%for field in form.visible_fields%}
<th>{{field.label|capfirst}}</th>
{%endfor%}
{%endif%}
</tr>
</thead>
<tr class="formset_row">
{{ form.non_form_errors }}
{% for field in form.visible_fields %}
<td>
{# Include the hidden fields in the form #}
{% if forloop.first %}
{% for hidden in form.hidden_fields %}
{{ hidden }}
{% endfor %}
{% endif %}
{{ field }}
</td>
{% endfor %}
</tr>
{% endfor %}
</table>
<button type="submit" value="Add" class="btn btn-inverse">{% trans 'Submit Invoice' %}</button>
</form>
any ideas how to show the validation error message or why it isn't shown.
non_form_errors belongs to the formset not the form.
So you can display it with:
{{ formset.non_form_errors }}
Or in your case, since you use the variable inlines:
{{ inlines.non_form_errors }}
Since it belongs to the formset, you should do this outside of the forloop through the forms.
If you have errors on the form that don't belong to any field, then you access these with
{{ form.non_field_errors }}

MultiValueDictKeyError while updating inline formsets

I'm having an issue with Django while updating inline formsets. I want to update a form and an inline formset, but it raises this error:
"MultiValueDictKeyError"
Exception Value: "u'clientphone_set-0-id'"
This is my view:
def edit_client(request, client_id):
client_to_edit = Client.objects.get(id=client_id)
form = ClientForm(instance=client_to_edit)
phone_formset = ClientPhoneFormSet(instance=client_to_edit)
if request.method == 'POST':
form = ClientForm(request.POST, instance=client_to_edit)
if form.is_valid():
form_saved = form.save(commit=False)
phone_formset = ClientPhoneFormSet(request.POST, request.FILES, instance=form_saved)
if phone_formset.is_valid():
form_saved.save()
phone_formset.save()
return client(request)
return render(request, 'WorkOrders/add_client.html', {'form' : form, 'phone_formset' : phone_formset})
And these are my forms
class ClientForm(forms.ModelForm):
name = forms.CharField(max_length=128)
rif = forms.CharField(max_length=10)
address = forms.CharField(max_length=250)
class Meta:
model = Client
fields = ('name','rif','address',)
ClientPhoneFormSet = inlineformset_factory(Client, ClientPhone, extra=1, fields=('phone_number',), can_delete=True)
And this is my template
<form class="form-horizontal" id="add_client" method="post" action=".">
{% csrf_token %}
{% for field in form.visible_fields %}
<div class="form-group">
<label for="{{ field.id }}" class="col-sm-2 control-label">{{ field.help_text }}</label>
<div class="col-sm-10">
{{ field.errors }}
{{ field }}
</div>
</div>
{% endfor %}
<div class="form-group">
<label for="{{ field.id }}" class="col-sm-2 control-label">Teléfono</label>
<div class="col-sm-10">
<table border="0" cellpadding="0" cellspacing="0" width="100%">
<tbody>
{% for form in phone_formset.forms %}
<tr>
<td>
{% if form.instance.pk %}
{{ form.DELETE }}
{% endif %}
{{ form.errors }}
{{ form.phone_number }}
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
{{ phone_formset.management_form }}
<div class="form-group">
<div class="col-sm-offset-2 col-sm-10">
<button type="submit" class="btn btn-primary">Guardar</button>
Volver
</div>
</div>
</div>
</form>
It opens the form with no problem, the error happens when I submit.
Thanks.
I fixed it by using phone_formset instead of phone_formset.forms, and added the {{ phone_field.id }}.
Here is the result:
<table border="0" cellpadding="0" cellspacing="0" width="100%">
<tbody>
{% for phone_field in phone_formset %}
<tr>
<td>
{% if phone_field.instance.pk %}
{{ phone_field.DELETE }}
{% endif %}
{{ phone_field.errors }}
{{ phone_field.id }}
{{ phone_field.phone_number }}
</td>
</tr>
{% endfor %}
</tbody>
</table>

Categories