Смотря что используешь. Если django, то там достаточно просто, но топорно сделано. Делаешь CBV наследуемый от ListView, задаешь paginate_by=ЧИСЛО объектов на странице, и делаешь простую обработку в шаблоне.
{% if is_paginated %}
<ul class="pagination">
{% if page_obj.has_previous %}
<li><a href="?page={{ page_obj.previous_page_number }}">«</a></li>
{% else %}
<li class="disabled"><a href="">«</a></li>
{% endif %}
{% for page in page_obj.paginator.page_range %}
{% if page == page_obj.number %}
<li class="active"><a href="?page={{ page }}">{{ page }}</a></li>
{% else %}
<li><a href="?page={{ page }}">{{ page }}</a></li>
{% endif %}
{% endfor %}
{% if page_obj.has_next %}
<li><a href="?page={{ page_obj.next_page_number }}">»</a></li>
{% else %}
<li class="disabled"><a href="">»</a></li>
{% endif %}
</ul>
{% endif %}