Skip to content
GitLab
Menu
Projects
Groups
Snippets
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
Menu
Open sidebar
Websites UFRPE
django-dsgov
Commits
b356bf09
Commit
b356bf09
authored
Nov 12, 2025
by
Eduardo Silva
Browse files
finalizacao do componente de tabela com pagination funcionando
parent
2c654ac2
Changes
2
Hide whitespace changes
Inline
Side-by-side
dsgov/templatetags/br_table_tags.py
View file @
b356bf09
...
@@ -347,52 +347,234 @@ class BRTableFooterNode(template.Node):
...
@@ -347,52 +347,234 @@ class BRTableFooterNode(template.Node):
# O conteúdo interno é HTML de template, marcado como seguro.
# O conteúdo interno é HTML de template, marcado como seguro.
return
format_html
(
'<div class="table-footer">{}</div>'
,
mark_safe
(
self
.
nodelist
.
render
(
context
)))
return
format_html
(
'<div class="table-footer">{}</div>'
,
mark_safe
(
self
.
nodelist
.
render
(
context
)))
# -----------------------------------------------------------------------------
# Funções utilitárias necessárias para a paginação DSGov (versão tabela)
# -----------------------------------------------------------------------------
def
build_page_url
(
request
,
page
,
extra_params
=
""
):
"""Monta a URL com o número da página e preserva outros parâmetros GET."""
params
=
request
.
GET
.
copy
()
# Atualiza ou adiciona o parâmetro 'page'
params
[
"page"
]
=
page
querystring
=
params
.
urlencode
()
# 🔹 Remove 'page' e 'per_page' duplicados de extra_params
if
extra_params
:
cleaned_extra
=
"&"
.
join
(
[
p
for
p
in
extra_params
.
split
(
"&"
)
if
not
(
p
.
startswith
(
"page="
)
or
p
.
startswith
(
"per_page="
))
]
)
if
cleaned_extra
:
querystring
+=
f
"&
{
cleaned_extra
}
"
return
f
"?
{
querystring
}
"
def
build_per_page_url
(
request
,
per_page
,
extra_params
=
""
):
"""Monta a URL com o número de itens por página e reseta para a primeira página."""
params
=
request
.
GET
.
copy
()
# Remove o per_page anterior para não duplicar
if
"per_page"
in
params
:
del
params
[
"per_page"
]
params
[
"per_page"
]
=
per_page
querystring
=
params
.
urlencode
()
# Remove 'page' e 'per_page' duplicados de extra_params
if
extra_params
:
cleaned_extra
=
"&"
.
join
(
[
p
for
p
in
extra_params
.
split
(
"&"
)
if
not
(
p
.
startswith
(
"page="
)
or
p
.
startswith
(
"per_page="
))
]
)
if
cleaned_extra
:
querystring
+=
f
"&
{
cleaned_extra
}
"
return
f
"?
{
querystring
}
"
@
register
.
simple_tag
(
takes_context
=
True
)
@
register
.
simple_tag
(
takes_context
=
True
)
def
br_table_pagination
(
context
):
def
br_table_pagination
(
context
,
page_obj
=
None
,
extra_params
=
""
,
per_page_options
=
None
):
"""Renderiza o componente de paginação da tabela."""
"""
meta
=
context
.
get
(
'br_table_meta'
,
{})
Renderiza paginação DSGov (versão tabela).
total
=
meta
.
get
(
'data_total'
,
0
)
current
=
meta
.
get
(
'data_current'
,
1
)
Exemplo de uso no template:
per_page
=
meta
.
get
(
'data_per_page'
,
10
)
{% br_table_pagination page_obj=page_obj extra_params=extra_params %}
- page_obj: objeto do Django Paginator (ex: `page_obj` vindo da view)
- extra_params: string adicional de parâmetros (opcional)
- per_page_options: lista de opções de "itens por página" (ex: 10,20,30,50,100 etc)
"""
request
=
context
[
"request"
]
if
not
page_obj
:
# Renderiza a versão genérica/placeholder
return
format_html
(
"""
<nav class="br-pagination" aria-label="paginação" data-total="50" data-current="1" data-per-page="20">
<div class="pagination-per-page">
<div class="br-select">
<div class="br-input">
<label for="per-page-selection">Exibir</label>
<input id="per-page-selection" type="text" placeholder=" " value="20"/>
<button class="br-button" type="button" aria-label="Exibir lista" tabindex="-1" data-trigger="data-trigger"><i class="fas fa-angle-down" aria-hidden="true"></i>
</button>
</div>
<div class="br-list" tabindex="0">
<div class="br-item" tabindex="-1">
<div class="br-radio">
<input id="per-page-10" type="radio" name="per-page" value="10"/>
<label for="per-page-10">10</label>
</div>
</div>
<div class="br-item" tabindex="-1">
<div class="br-radio">
<input id="per-page-20" type="radio" name="per-page" value="20" checked="checked"/>
<label for="per-page-20">20</label>
</div>
</div>
<div class="br-item" tabindex="-1">
<div class="br-radio">
<input id="per-page-30" type="radio" name="per-page" value="30"/>
<label for="per-page-30">30</label>
</div>
</div>
</div>
</div>
</div><span class="br-divider d-none d-sm-block mx-3"></span>
<div class="pagination-information d-none d-sm-flex"><span class="current">1</span>–<span class="per-page">20</span> de <span class="total">50</span> itens</div>
<div class="pagination-go-to-page d-none d-sm-flex ml-auto">
<div class="br-select">
<div class="br-input">
<label for="go-to-selection">Página</label>
<input id="go-to-selection" type="text" placeholder=" " value="1"/>
<button class="br-button" type="button" aria-label="Exibir lista" tabindex="-1" data-trigger="data-trigger"><i class="fas fa-angle-down" aria-hidden="true"></i>
</button>
</div>
<div class="br-list" tabindex="0">
<div class="br-item" tabindex="-1">
<div class="br-radio">
<input id="go-to-1" type="radio" name="go-to" value="1" checked="checked"/>
<label for="go-to-1">1</label>
</div>
</div>
<div class="br-item" tabindex="-1">
<div class="br-radio">
<input id="go-to-2" type="radio" name="go-to" value="2"/>
<label for="go-to-2">2</label>
</div>
</div>
<div class="br-item" tabindex="-1">
<div class="br-radio">
<input id="go-to-3" type="radio" name="go-to" value="3"/>
<label for="go-to-3">3</label>
</div>
</div>
</div>
</div>
</div><span class="br-divider d-none d-sm-block mx-3"></span>
<div class="pagination-arrows ml-auto ml-sm-0">
<button class="br-button circle disabled" type="button" aria-label="Voltar página"><i class="fas fa-angle-left" aria-hidden="true"></i>
</button>
<button class="br-button circle" type="button" aria-label="Página seguinte"><i class="fas fa-angle-right" aria-hidden="true"></i>
</button>
</div>
</nav>
"""
)
# Dados base
current_page
=
page_obj
.
number
total_items
=
page_obj
.
paginator
.
count
per_page
=
page_obj
.
paginator
.
per_page
total_pages
=
page_obj
.
paginator
.
num_pages
per_page_options
=
per_page_options
or
[
10
,
20
,
30
]
per_page_id
=
meta
.
get
(
'per_page_select_id'
,
_uniq_id
(
'per-page-selection'
))
# Cálculo da exibição “X–Y de Z itens”
go_to_id
=
meta
.
get
(
'go_to_select_id'
,
_uniq_id
(
'go-to-selection'
))
start_item
=
(
current_page
-
1
)
*
per_page
+
1
end_item
=
min
(
start_item
+
per_page
-
1
,
total_items
)
per_page_options
=
[
10
,
20
,
30
]
# Botões prev/next
prev_disabled
=
"disabled"
if
not
page_obj
.
has_previous
()
else
""
next_disabled
=
"disabled"
if
not
page_obj
.
has_next
()
else
""
prev_link
=
(
build_page_url
(
request
,
page_obj
.
previous_page_number
(),
extra_params
)
if
page_obj
.
has_previous
()
else
"javascript:void(0)"
)
next_link
=
(
build_page_url
(
request
,
page_obj
.
next_page_number
(),
extra_params
)
if
page_obj
.
has_next
()
else
"javascript:void(0)"
)
# Select de “itens por página”
per_page_html
=
[]
per_page_html
=
[]
for
opt
in
per_page_options
:
for
opt
in
per_page_options
:
checked
=
'checked'
if
opt
==
per_page
else
''
checked
=
"checked"
if
opt
==
per_page
else
""
radio_id
=
f
'
{
per_page_id
}
-
{
opt
}
'
# Adicionar a URL de navegação ao clicar no rádio
per_page_html
.
append
(
format_html
(
url
=
build_per_page_url
(
request
,
opt
,
extra_params
)
'<div class="br-item" tabindex="-1"><div class="br-radio">'
per_page_html
.
append
(
'<input id="{id}" type="radio" name="{name}" value="{val}" {checked}/>'
format_html
(
'<label for="{id}">{label}</label>'
"""
'</div></div>'
,
<div class="br-item" tabindex="-1">
id
=
radio_id
,
name
=
format_html
(
'per-page-{}'
,
per_page_id
),
val
=
str
(
opt
),
checked
=
mark_safe
(
checked
),
label
=
str
(
opt
)
<div class="br-radio">
))
<input id="per-page-{0}" type="radio" name="per-page" value="{0}" {1}
onclick="window.location.href='{2}'"/>
# number of pages
<label for="per-page-{0}">{0}</label>
pages
=
max
(
1
,
(
total
+
per_page
-
1
)
//
per_page
)
</div>
</div>
"""
,
opt
,
mark_safe
(
checked
),
mark_safe
(
url
),
)
)
# Select de “ir para página”
go_to_html
=
[]
go_to_html
=
[]
for
p
in
range
(
1
,
pages
+
1
):
for
p
in
range
(
1
,
total_pages
+
1
):
checked
=
'checked'
if
p
==
current
else
''
checked
=
"checked"
if
p
==
current_page
else
""
radio_id
=
f
'
{
go_to_id
}
-
{
p
}
'
# Adicionar a URL de navegação ao clicar no rádio
go_to_html
.
append
(
format_html
(
url
=
build_page_url
(
request
,
p
,
extra_params
)
'<div class="br-item" tabindex="-1"><div class="br-radio">'
go_to_html
.
append
(
'<input id="{id}" type="radio" name="{name}" value="{val}" {checked}/>'
format_html
(
'<label for="{id}">{label}</label>'
"""
'</div></div>'
,
<div class="br-item" tabindex="-1">
id
=
radio_id
,
name
=
format_html
(
'go-to-{}'
,
go_to_id
),
val
=
str
(
p
),
checked
=
mark_safe
(
checked
),
label
=
str
(
p
)
<div class="br-radio">
))
<input id="go-to-{0}" type="radio" name="go-to" value="{0}" {1}
onclick="window.location.href='{2}'"/>
# pagination html assembled
<label for="go-to-{0}">{0}</label>
return
format_html
(
'''
</div>
<nav class="br-pagination" aria-label="paginação" data-total="{total}" data-current="{current}" data-per-page="{per_page}">
</div>
"""
,
p
,
mark_safe
(
checked
),
mark_safe
(
url
),
)
)
# HTML final
return
format_html
(
"""
<nav class="br-pagination" aria-label="paginação"
data-total="{total}" data-current="{current}" data-per-page="{per_page}">
<div class="pagination-per-page">
<div class="pagination-per-page">
<div class="br-select">
<div class="br-select">
<div class="br-input">
<div class="br-input">
<label for="
{
per
_
page
_id}
">Exibir</label>
<label for="per
-
page
-selection
">Exibir</label>
<input id="
{
per
_
page
_id}
" type="text" placeholder=" "
/
>
<input id="per
-
page
-selection
" type="text" placeholder=" "
value="{per_page}"
>
<button class="br-button" type="button" aria-label="Exibir lista" tabindex="-1" data-trigger="data-trigger">
<button class="br-button" type="button" aria-label="Exibir lista" tabindex="-1" data-trigger="data-trigger">
<i class="fas fa-angle-down" aria-hidden="true"></i>
<i class="fas fa-angle-down" aria-hidden="true"></i>
</button>
</button>
...
@@ -404,15 +586,15 @@ def br_table_pagination(context):
...
@@ -404,15 +586,15 @@ def br_table_pagination(context):
</div>
</div>
<span class="br-divider d-none d-sm-block mx-3"></span>
<span class="br-divider d-none d-sm-block mx-3"></span>
<div class="pagination-information d-none d-sm-flex">
<div class="pagination-information d-none d-sm-flex">
<span class="current">{
curren
t}</span>–
<span class="current">{
star
t}</span>–
<span class="per-page">{
per_page
}</span> de
<span class="per-page">{
end
}</span> de
<span class="total">{total}</span> itens
<span class="total">{total}</span> itens
</div>
</div>
<div class="pagination-go-to-page d-none d-sm-flex ml-auto">
<div class="pagination-go-to-page d-none d-sm-flex ml-auto">
<div class="br-select">
<div class="br-select">
<div class="br-input">
<div class="br-input">
<label for="
{
go
_
to
_id}
">Página</label>
<label for="go
-
to
-selection
">Página</label>
<input id="
{
go
_
to
_id}
" type="text" placeholder=" "
/
>
<input id="go
-
to
-selection
" type="text" placeholder=" "
value="{current}"
>
<button class="br-button" type="button" aria-label="Exibir lista" tabindex="-1" data-trigger="data-trigger">
<button class="br-button" type="button" aria-label="Exibir lista" tabindex="-1" data-trigger="data-trigger">
<i class="fas fa-angle-down" aria-hidden="true"></i>
<i class="fas fa-angle-down" aria-hidden="true"></i>
</button>
</button>
...
@@ -424,20 +606,24 @@ def br_table_pagination(context):
...
@@ -424,20 +606,24 @@ def br_table_pagination(context):
</div>
</div>
<span class="br-divider d-none d-sm-block mx-3"></span>
<span class="br-divider d-none d-sm-block mx-3"></span>
<div class="pagination-arrows ml-auto ml-sm-0">
<div class="pagination-arrows ml-auto ml-sm-0">
<
button
class="br-button circle" type="button" aria-label="Voltar página">
<
a href="{prev_link}"
class="br-button circle
{prev_disabled}
" type="button" aria-label="Voltar página">
<i class="fas fa-angle-left" aria-hidden="true"></i>
<i class="fas fa-angle-left" aria-hidden="true"></i>
</
button
>
</
a
>
<
button
class="br-button circle" type="button" aria-label="Página seguinte">
<
a href="{next_link}"
class="br-button circle
{next_disabled}
" type="button" aria-label="Página seguinte">
<i class="fas fa-angle-right" aria-hidden="true"></i>
<i class="fas fa-angle-right" aria-hidden="true"></i>
</
button
>
</
a
>
</div>
</div>
</nav>
</nav>
'''
,
"""
,
total
=
total
,
total
=
total_items
,
current
=
current
,
current
=
current_page
,
per_page
=
per_page
,
per_page
=
per_page
,
per_page_id
=
per_page_id
,
start
=
start_item
,
go_to_id
=
go_to_id
,
end
=
end_item
,
per_page_html
=
mark_safe
(
''
.
join
(
per_page_html
)),
per_page_html
=
mark_safe
(
""
.
join
(
per_page_html
)),
go_to_html
=
mark_safe
(
''
.
join
(
go_to_html
))
go_to_html
=
mark_safe
(
""
.
join
(
go_to_html
)),
prev_link
=
prev_link
,
next_link
=
next_link
,
prev_disabled
=
prev_disabled
,
next_disabled
=
next_disabled
,
)
)
tests/django_dsgov_test1/templates/examples_table.html
View file @
b356bf09
...
@@ -8,7 +8,7 @@
...
@@ -8,7 +8,7 @@
{% block content %}
{% block content %}
{% br_table data-search="data-search"
data-total="50" data-current="1" data-per-page="20"
%}
{% br_table data-search="data-search" %}
{% br_table_header %}
{% br_table_header %}
{% br_table_title %}Tabela irregular 2{% end_br_table_title %}
{% br_table_title %}Tabela irregular 2{% end_br_table_title %}
{% br_table_actions_trigger %}
{% br_table_actions_trigger %}
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment