search box for all the pages after Django pagination of table - javascript

I have developed a web app using Django.
I have created a table pagination.
how could I create a search input for all the data in all the pages of table?
view.py
def Browse_and_adopt(request):
Title_list = Title.objects.all()
page = request.GET.get('page', 1)
paginator = Paginator(Title_list, 10)
try:
Titles = paginator.page(page)
except PageNotAnInteger:
Titles = paginator.page(1)
except EmptyPage:
Titles = paginator.page(paginator.num_pages)
page_obj = paginator.get_page(page)
return render(request, 'bms/inbox/Browse_and_adopt.html', {'Titles': Titles, 'page_obj': page_obj})
Browse_and_adopt.html
<table id="myTable">
<thead>
<tr>
<th>Title</th>
</tr>
</thead>
<tbody>
% for book in page_obj %}
<tr>
<td>{{ book.title }}</td>
</tr>
{% endfor %}
</tbody>
</table>
<div class="pagination">
<span class="step-links">
{% if page_obj.has_previous %}
« first
previous
{% endif %}
<span class="current">
Page {{ page_obj.number }} of {{ page_obj.paginator.num_pages }}.
</span>
{% if page_obj.has_next %}
next
last »
{% endif %}
</span>
</div>
Now only the first page shows, how to create a search bar for all the data in the table?

The view does not know whick object you are looking for.
There is two ways to do so.
In the frontend end where you write a JS callback event listener that filter all the supplied table data. " not optimal ''
Or you can create a custom view that recieve the object pk via post request and return the filtered result e.g url :
urlpatterns = [
path('update/<int:pk>/', updateViewSet.as_view()),
]

Related

Can I Reorder a LIst Based On User Provided Values Using Only HTMX?

I have HTMX working. The code below is fully functional. The one piece I'd like to incorporate, I can't figure out how to do it. The user is able to provide a number rank...but when they click save, the view returns with the item at the top. Only after they click reload does the list sort itself based on how I defined the attributes with the model.
Here's my HTML...
<h1 class="title62">Tasks</h1>
<button class="button36" hx-get="{% url 'MyTasks:create_task_form' %}" hx-target="#taskforms">Add Task</button>
<div id="taskforms"></div>
<div id="tblData">
{% if tasks %}
{% for task in tasks %}
{% include "partials/task_detail.html" %}
{% endfor %}
</div>
{% endif %}
<div hx-target="this" hx-swap="outerHTML" hx-headers='{"X-CSRFToken":"{{ csrf_token }}"}' class="" >
<form method="POST">
{% csrf_token %}
<div class="table22">
<table class="table23">
<thead>
<tr>
<th class="title67">Number</th>
<th class="title67">Task</th>
</tr>
</thead>
<tbody>
<button class="button35" hx-post=".">
Save
</button>
<button type="button" class="button33">
Delete
</button>
<tr>
<td class="title73">{{ form.number }}</td>
<td class="title73">{{ form.task }}</td>
</tr>
</tbody>
</table>
</div>
</form>
</div>
<script>
document.body.addEventListener('htmx:configRequest', (event) => {
event.detail.headers['X-CSRFToken'] = '{{ csrf_token }}';
})
</script>
<div hx-target="this" class="">
<div class="table22">
<table class="table23">
<thead>
<tr>
<th class="title67">Number</th>
<th class="title67">Task</th>
</tr>
</thead>
<tbody>
<button class="button35" hx-get="{% url 'MyTasks:update_task' task.id %}" hx-swap="outerHTML">
Update
</button>
<button class="button34" hx-confirm="Are you sure you want to delete?" hx-post="{% url 'MyTasks:delete_task' task.id %}" hx-swap="outerHTML">
Delete
</button>
<tr>
<td class="title70">{{ task.number }}</td>
<td class="title70">{{ task.task }}</td>
</tr>
</tbody>
</table>
</div>
</div>
My Model...
class Task(models.Model):
task = models.TextField(max_length=264,blank=True,null=True,unique=False)
number = models.PositiveIntegerField(default=1)
class Meta:
ordering = ["number"]
def __str__(self):
return self.task
I have begun to explore using Javascript to do HTML sorting to approach my issue that way instead. It just seems to me as capable as HTMX is there should be a way for me to do it leveraging HTMX. Thanks in advance for any thoughts.
I think the easiest way would be just to swap in the entire list on save instead of just the new item - that way you can take advantage of the ordering in the model.
EDIT:
In order to swap a list of the task in instead of the saved task, you will need to modify your view to return a list of the tasks instead of just the task being saved - like this for a CreateView:
class TaskCreateView(CreateView):
model = Task
form_class = TaskForm
template_name = 'task/_create_form.html'
def form_valid(self, form):
self.object = form.save()
tasks = Task.objects.all()
return render(self.request, 'task/_task_list.html', {'tasks': tasks})
You would also need to make partial template that would render all the tasks - something like this:
<div id="tblData">
{% if tasks %}
<ul>
{% for task in tasks %}
<li>{{ task.order }} - {{ task.task }}</li>
{% endfor %}
</ul>
{% endif %}
The HTMX technique you are looking for is the Out of Band Swapping which is basically 1 request with multiple targets. The targets can be anywhere on the page. In your case: when the user creates, changes or deletes a task, the response should also contain the updated list of tasks. It requires only a few modifications. For example a task updating view:
def update_view(request):
tasks_updated = False
tasks = None
if request.method == 'POST':
form = TaskForm(request.POST)
if form.is_valid():
# Update the task in the database
...
task.save()
tasks_updated = True
else:
# Return the form with errors
return render(request, 'task_form.html', {'form': form})
if tasks_updated:
# Fetch new list of tasks
tasks = Task.objects.order_by('number')
return render(request, 'task.html', {'tasks': tasks, 'task': task})
We have the tasks_updated tracking variable that we switch to True if we updated a task in the database, so the task list needs an update on the frontend. Just before we render the template, we check the value of this variable and fetch the tasks if needed.
And the partial template:
<div>
<!-- Render the task's table as usual. -->
</div>
{% if tasks %}
<div id="tblData" hx-swap-oob="true">
{% for task in tasks %}
{% include "partials/task_detail.html" %}
{% endfor %}
</div>
{% endif %}
Here we render the table only we have the tasks variable, so at least one of the task was updated therefore we loaded the tasks as well. The hx-swap-oob="true" tells HTMX to swap the element having tblData id.
Basically that's it. Just include an OOB-Swap task list in each response, where the task list needs an update. If you load the "new task form" you don't need it, but if you add/update/delete a task, you need a fresh OOB-Swap task list in the response (fetched from the database after the task operation has been finished).

Does TemplateView supports pagination?

How can I implement pagination with Templateview? The below view is class-based view where I am using Templateview for listing out networks ( which I am calling from api from another application). Here I am not using models so I cant use Listview because I don't have queryset.
class classView(TemplateView):
template_name = 'view_network.html'
# paginate_by = 5
context_object_name = 'networks'
paginator = Paginator('networks', 5)
def get_context_data(self, **kwargs):
...
...
return context
in html page i have added this:
<span class="step-links" style="margin-left: 30%;
margin-bottom: 0px;
margin-top: 0px;
width: 100%;">
<div style="text-align: justify"></div>
<table style="width: 50%">
<tr>
{% if page_obj.has_previous %}
<td>« First</td>
<td> Previous</td>
{% endif %}
<td> Page {{ page_obj.number }} of {{ page_obj.paginator.num_pages }}.</td>
{% if page_obj.has_next %}
<td>Next</td>
<td>Last »</td>
{% endif %}
</tr>
</table>
</div>
</span>
</div>
You can implement the pagination within the get_context_data() function. Assuming networks is a list of objects.
def get_context_data(self, **kwargs):
page_size = 5
paginator = Paginator(networks, page_size)
page = request.GET.get('page', 1)
page_obj = paginator.page(page)
context = {
"page_obj": page_obj
}
TemplateView does not support pagination, you have to use a ListView to use "paginate_by = 5" Here is a helpfull link to check all attributes/methods for each class based generic view.

create table with dynamic rows and columns with django html template

I'm trying to create a table with dynamic rows and columns based on the results list with django html template. The number of records and header number could change. I am using two for loops to get the number of rows and the column number. I'm having a hard time trying to output the actual values in the table. The idea was to "index" from the second for loop and applying it to "each" of first loop. I know that the syntax is definitely wrong, but is something that django can do? If not, is there any suggestions that I can research on how to implement this? Thanks!!
list = [
{'header_a': foo1, 'header_b': foo2, 'header_c': foo3},
{'header_a': foo1, 'header_b': foo2, 'header_c': foo3},
{'header_a': foo3, 'header_b': foo3, 'header_c': foo3},
{'header_a': foo4, 'header_b': foo4, 'header_c': foo4},
]
Sample Table
header_a | header_b | header_c
foo1 | foo1 | foo1
foo2 | foo2 | foo2
foo3 | foo3 | foo3
foo4 | foo4 | foo4
or
list_2 = [
{'header_c': c_foo1, 'header_d': d_foo1},
{'header_c': c_foo2, 'header_d': d_foo2},
]
Sample Table 2
header_c | header_d
c_foo1 | d_foo1
c_foo2 | d_foo2
<table>
<thead>
<tr>
{% for index in list.0 %}
<th>{{ index }}</th>
{% endfor %}
</tr>
</thead>
<tbody>
{% for each in list %}
<tr>
{% for index in a %}
<td>{{ each.{{index}} }}</td>
{% endfor %}
</tr>
{% endfor %}
</tbody>
</table>
Well, as you have a list of dicionaries in that schema, this is how you can iterate it inside the template:
<table>
<thead>
<tr>
{% for item in list %}
{% if forloop.first %}
{% for h in item %}
<th>{{ h }}</th>
{% endfor %}
{% endif%}
{% endfor %}
</tr>
</thead>
<tbody>
{% for item in list %}
<tr>
{% for key,value in item.items %}
<td>{{ value}}</td>
{% endfor %}
</tr>
{% endfor %}
</tbody>
</table>
Assuming you have the same keys in every dictionary (column headers or fields as you name them), you first iterate only the first dicionary to get its keys, then, you iterate again the values for rows...
Not the most efficient solution tho, it would be great if you can rewrite the way you create that list.
Hope it helps and please confirm if it works
maybe you should check out django tables? It's a pretty known tool to creating powerful tables with django. You can create them based on a model, but you can also simply pass the data directly to them. I also once used it to create a dynamic table. It takes all the job from the template and add it to the view where things are easier to manipulate.

Dynamically add or remove table rows with jQuery or Angular?

This is the code I have. I'm using Symfony/Twig to pass the variables and translation strings in (if anyone was unsure what the {{, }}, {% trans %} etc was for).
Please see the line where I have the glyphicon glyphicon-camera - what I want is for the user to be able to click this, and a new row appears directly below containing the contents of row.getPhoto() - the icon will only appear if row.getPhoto() is not null, so therefore clicking it will always mean there is content to show.
Likewise, clicking the photo icon again will make the row disappear.
How can I do this? I'm not sure if I should use jQuery or Angular (I am using both in other places in the project, so both are easily available for me). Any comments welcome, thank you.
<table class="table">
<tr>
<th width="10%">{% trans %} header.item {% endtrans %}</th>
<th width="60%">{% trans %} header.action {% endtrans %}</th>
<th width="10%">{% trans %} header.option1 {% endtrans %}</th>
<th width="10%">{% trans %} header.option2 {% endtrans %}</th>
<th width="10%">{% trans %} header.option3 {% endtrans %}</th>
</tr>
{% for row in showRows(allItems) %}
<tr>
<td>
{{ row.getItem() }}
</td>
<td>
{{ row.getAction() }} {% if row.getPhoto() is not null %} <span class="pull-right show-hide-photo glyphicon glyphicon-camera"></span>{% endif %}
</td>
<td>
{% if row.getOption1() %}<span class="glyphicon glyphicon-ok"></span>{% endif %}
</td>
<td>
{% if row.getOption2() %}<span class="glyphicon glyphicon-ok"></span>{% endif %}
</td>
<td>
{% if row.getOption3() %}<span class="glyphicon glyphicon-ok"></span>{% endif %}
</td>
</tr>
{% endfor %}
</table>
Only jQuery I have right now is this, to make the icon appear like a link when hovered over:
// Photo button
$('.show-hide-photo').css('cursor', 'pointer');
You can always pass symphony2 variables on javascript code, so you can have a scirpt with something along the lines of:
<scirpt>
$(.glyphicon).click(function(){
$(.Some-other-class).toggle()
});
</script>
You can have the .Some-other-class div element or td element starting as hidden and with variables in it (like you did in your static html code).
You don't need the css pointer in the js use it in a css class to have it when the page load not when the user click.
And for your click you can do something like this if you photo is a link then :
first use in your twig a <img src="{{row.photo}}" alt="" style="display:none;"/> whenever you want to put the images.
then inside your js in the click photo button
$('.show-hide-photo').on('click', function(){
$(this).closest('tr').find('img').toggle();
});
$(this) is your show-hide-photo button , closest('tr') will look for the tag which contain your button then find('img') will go find the tag inside that (row) in that case you wont need to bother with ids to select right row etc..

Django: Jquery click function not working in Ajax

I have been working through the Tango with Django exercises to cut my teeth into Django. Almost done but having a problem with the Ajax part.
Ajax function to auto_add a page is not being called. Idk what the problem is since the other functions are being called.
On the shell prompt, there is no call to the ajax function at all. Help needed.
Pertinent code attached. It is the same as on the website link above.
static/rango-ajax.js
$('.rango-add').click(function(){
var catid = $(this).attr("data-catid");
var title = $(this).atrr("data-title");
var url = $(this).attr("data-url");
$.get('/rango/auto_add_page/', {category_id: catid, url: url, title: title}, function(data){
$('#pages').html(data);
me.hide();
});
});
templates/rango/category.html
{% if user.is_authenticated %}
<button data-catid="{{category.id}}" data-title="{{ result.title }}" data-url="{{ result.link }}" class="rango-add btn btn-mini btn-info" type="button">Add</button>
{% endif %}
rango/views.py
#login_required
def auto_add_page(request):
context = RequestContext(request)
cat_id = None
url = None
title = None
context_dict = {}
if request.method == 'GET':
cat_id = request.GET['category_id']
url = request.GET['url']
title = request.GET['title']
if cat_id:
category = Category.objects.get(id=int(cat_id))
p = Page.objects.get_or_create(category=category, title=title, url=url)
pages = Page.objects.filter(category=category).order_by('-views')
#Adds our results list to the template context under name pages.
context_dict['pages'] = pages
return render_to_response('rango/page_list.html', context_dict, context)
rango/urls.py
urlpatterns = patterns('',
url(r'^$', views.index, name='index'),
url(r'^goto/$', views.track_url, name='track_url'),
url(r'^add_category/$', views.add_category, name='add_category'),
url(r'^auto_add_page/$', views.auto_add_page, name='auto_add_page'),
Complete code is at this link.
your code is good, the only thing what you have to do is to define your template in /tango/templates/rango/page_list.html. This template have the following code:
{% if pages %}
<ul>
{% for page in pages %}
<li>
{{ page.title}}
{% if page.views > 1 %}
({{page.views}} views)
{% elif page.views == 1 %}
({{page.views}} view)
{% endif %}
</li>
{% endfor %}
</ul>
{% else %}
<strong> No Pages currently in category. </strong>
{% endif %}
And inside of your category template you must define the following code:
% if category %}
{% if user.is_authenticated %}
Add a new Page <br>
{% endif %}
{% if pages %}
<div id="pages">
<ul>
{% for page in pages %}
<li>
{{ page.title}}
{% if page.views > 1 %}
({{page.views}} views)
{% elif page.views == 1 %}
({{page.views}} view)
{% endif %}
</li>
{% endfor %}
</ul>
</div>
{% else %}
<strong> No Pages currently in category. </strong>
{% endif %}
{% else %}
The specified category {{ category_name }} does not exist!
{% endif %}
I'm working through this section of the tutorial now and just want to add to Héctor's answer. To avoid duplicating the code to display the list of pages I did the following:
I added a get_page_list() method to tango/rango/templatetags/rango_extras.py, similar to the get_category_list() method used to display a list of categories in an earlier section of the tutorial.
from rango.models import Page
#register.inclusion_tag("rango/page_list.html")
def get_page_list(category):
pages = Page.objects.filter(category=category) if category else []
return {'pages': pages}
Then we just need to load rango_extras and call the get_page_list() method in tango/templates/rango/category.html.
{% extends 'rango/base.html' %}
{% load rango_extras %}
<!-- Existing code -->
{% if category %}
<!-- Existing code to show category likes and like button -->
<div id="page_list">
{% get_page_list category %}
</div>
<!-- Existing code to show search if user is authenticated -->
{% else %]
The specified category {{ category_name }} does not exist!
{% endif %}
This allows you to display the list of pages when a category page is first loaded and then refresh it if a category is added from the search area, without having to duplicate any code.

Categories

Resources