How to pass arguments to included html in Flask web application - python

I am developing a blog application in python with flask. In the view function form is passed as argument to render_template which calls 'index.html'. form works in index.html as expected. But there is a {% include '' %} tag which places 'post.htm'. Now I want to use same form repeatedly in 'post.html'. How to do that? Will the passed form to index.html available to included 'post.html' also? And if so how to identify which button is pressed in the rendered page because both forms are same? My index.html file:
{% extends "base.html" %}
{% block content %}
<h1>Hi, {{ g.user.nickname }}!</h1>
<form action="" method="post" name="post">
{{ form.hidden_tag() }}
<table>
..........
..........
<tr>
<td><input type="submit" value="Post!"></td>
</tr>
</table>
</form>
{% for post in posts.items %}
<div class="{{ post.id }}">
<div>
{% include 'post.html' %}
</div>
</div>
{% endfor %}
{% endblock %}
And my post.html as:
<table>
..........
..........
<tr valign="top">
<td>{{ post.body }}</td>
</tr>
<tr>
<form action="" method="post" name="post">
{{ form.hidden_tag() }}
<table>
.........
.........
<td><input type="submit" value="Post!"></td>
</table>
</form>
</table>
Is it possible to use same form on both html files. As there will be several form fields in the rendered web page, how to identify which button is pressed?
index.html is rendered with code:
return render_template('index.html',
title='Home',
form=form,
posts=posts)

To distinguish the different forms, you need some unique key, e.g. a hidden input-tag, which contains an ID:
<input type="hidden" name="post_id" value="{{post.id}}">
For the index-Form you can use as generic ID the value "new".

Related

Search bar no content is returned

Hey i am new to Django and I am trying to make a search bar to my first site.
My problem here is when I search for any value that I/user entered and on the site, the site only refreshes and doesn't give me anything back but the empty option that i gave the site to display when there is no content to match the search.
(That's not all of the Topic model)
model.py
class Topic(models.Model):
content = models.CharField(max_length=200)
views.py
def search(request):
query = request.GET.get('q')
if query:
result = Topic.objects.filter(content__icontains=query)
context = { 'query': query, 'result': result}
return render(request, 'learning_logs/topics.html', context)
(that's all of the topics.html i am sorry of how it turned this not what it really looks like on the original topics.html but that's the full topics.html )
topics.html
% extends "leaning_logs\base.html" %}
{% block page_header %}
<h1>Topics </h1>
<br>Add a new topic</br>
{% endblock page_header %}
{% block content %}
<form method="GET" action="{% url 'learning_logs:search' %}">
{% csrf_token %}
<input name="q" value="{{ request.GET.q }}" placeholder="search..">
<button class="btn btn-success" type="submit">
Search</button>
</form>
{% for topic in topics %}
<div class="card-mb3">
<div class="card-header" style="background-color:lightgrey">
<table class="table">
<tr>
<th>Image</th>
<th>Title of the topic</th>
<th>Edit</th>
<th>Delete</th>
</tr>
<div class="card-body" style="background- color:white">
<tr>
<td>
{% if topic.image %}
<image src="{{topic.image.url}}" style="width:200px">
{% else %}
<span class="text-muted">No Image have been added</span>
{% endif %}
<td><h3>
{{topic}}
</td></h3>
<td><small><a href="{% url 'learning_logs:edit_topic' topic.id %}">
<button method="submit" class="btn btn-primary">
Edit topic</button></a></small></td>
<td><small><form method="post" action="{% url 'learning_logs:delete_topic' topic.id %}">
<button type="submit" class="btn btn-danger btn-primary" >
Delete topic</button></form></small></td>
</tr>
</div>
</div>
</div>
{% empty %}
<h3><li>No topics have been added yet.</li></h3>
{% endfor %}
{% endblock content %}
This:
{% for topic in topics %}
should be that:
{% for topic in result %}

Python Django Edit HTML rows and update database

I have a table and I wish to add an edit button that updates the certain record both visually and in the database.
The HTML I have.
{% for work_entry in work_entries %}
{% if work_entry.date == date.date %}
<form action="{% url 'work_entries:object_edit' work_entry.id %}" method="post">
{% csrf_token %}
<tr>
<td>
<button onclick="return confirm('Are you sure you want this edit?')">Edit
</button>
</td>
<td> <form action="{% url 'work_entries:object_delete' work_entry.id %}" method="post">
{% csrf_token %}
<button onclick="return confirm('Are you sure you want to delete this record?')">Delete
</button>
</form>
</td>
<td>{{ work_entry.id }}</td>
<td><input type="text" value="{{ work_entry.description }}" name="description"></td>
<td><input type="number" value="{{ work_entry.num_hours }}" name="hours"></td>
</tr>
</form>
{% endif %}
{% endfor %}
The views.py
def object_edit(request, object_id):
record = get_object_or_404(WorkEntry, pk=object_id)
if request.method == "POST":
record.description = request.POST["description"]
record.num_hours = request.POST["hours"]
record.save()
return redirect("/employeePage")
return render(request, "employeePage.html")
And urls.py
app_name = "work_entries"
urlpatterns = [
path("", views.employee_view, name="employeePage"),
url(r"^delete/(?P<object_id>[0-9]+)/$", views.object_delete, name="object_delete"),
url(r"^edit/(?P<object_id>[0-9]+)/$", views.object_edit, name="object_edit"),
]
I used an input tag in the as I thought that would allow me to change data and save it. However this is giving me MultiValueDictKeyError at /employeePage/edit/14/
'description' error. I am not too experienced with jquery which from research I saw that could work but I don't seem to get it right. Can someone help or even suggestions on how I should approach this would be useful.
Note: there is already a button to delete the record which works, I tried a similar approach for editing, but it doesn't work.
I fully encourage you to use the forms provided by Django, it will make your life easier.
And I fully encourage you as well to not use a form for your delete stuff, it should be a simple link, it would avoid to have a form in a form. I think your problem is here. Having a form in a form with the button in the middle make impossible for your browser to know which parts of the form you want to submit.
As well you have two buttons but none of them is submit type.
If you don't want to use the Django forms a way to do it would be
{% for work_entry in work_entries %}
{% if work_entry.date == date.date %}
<form action="{% url 'work_entries:object_edit' work_entry.id %}" method="post">
{% csrf_token %}
<tr>
<td>
<button>
Delete
</button>
</td>
<td> <button type="submit" onclick="return confirm('Are you sure you want to update this record?')">
Update
</button>
</td>
<td>{{ work_entry.id }}</td>
<td><input type="text" value="{{ work_entry.description }}" name="description"></td>
<td><input type="number" value="{{ work_entry.num_hours }}" name="hours"></td>
</tr>
</form>
{% endif %}
{% endfor %}
It's not the most beautiful way to do it I tried to keep your achitecture

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 }}

django CSRF token missing or incorrect error but it is included

I have the following django formset represented in the template:
<form method="post" action="">
{% csrf_token %}
{{ formset.management_form }}
{% csrf_token %}
<table width="100%" border="0" cellspacing="0" cellpadding="0">
{% for form in formset %}
{% csrf_token %}
<tr>
<th>My Activities</th>
<th>Duration</th>
<th>Log</th>
</tr>
<tr>
<td>{{ form.instance.activity.name }}</td>
<td><input type="text" class="minutesinput"> Minutes</td>
<td>
<div class="actvty_log_entry">
<input type="submit" value="Log Entry">
</div>
</td>
</tr>
{% endfor %}
</table>
</form>
When I submit the form, I get the error:
Forbidden (403)
CSRF verification failed. Request aborted.
Note: my normal forms work in all my other views and the middleware is activated
The problem was I was using render to response instead of:
return render(request, 'customers/password-change.html', context)
Changing to the above worked. Thanks for the hint #Daniel Roseman

django formsets can_delete header

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.

Categories