Django Infinite scrolling with javascript fetch api and function based view.
Tags: django, ajax, fetch, pagination
Published: 2021-08-12 23:35:43

Hello, I will take you straight through the process of adding inifinte pagination in your django application like it's abc complete code is down below

**Note: this is for absolute beginner**

[django-infinite-scroll](https://github.com/tochimclaren/django-infinite-scroll.git
)

First thing first, we create our django project.

```
mkdir django-infinite-scroll
```
```
cd django-infinite-scroll
```
```
pipenv shell #this initializes with Pipfile and creates the environment
```
We install our django application
```
pipenv install django
```
We create a new django project
```
django-admin startproject core .
```
We create our app blog and add it to `INSTALLED_APPS`.
```
python manage.py startapp blog
```

```
INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    
    # our blog app
    'blog.apps.BlogConfig',
]
```
Run the development server and make sure everything is working properly.
```
python manage.py runserver
```
Migrate the database and createsuperuser in my case the credentials were username: `admin` password: `admin` run the server and let the fun begin!
```
python manage.py migrate
```

```
python manage.py createsuperuser
```


```
python manage.py runserver
```
Creating a simple model for a blog to hold
```
# models.py
from django.db import models

class Post(models.Model):
    title = models.CharField(max_length=255)
    content = models.TextField()
    created = models.DateTimeField(auto_now_add=True)
    updated = models.DateTimeField(auto_now=True)
    published = models.BooleanField(default=False)

    def __str__(self):
        return self.title
```

```
# views.py
from django.core.paginator import Paginator
from django.http import JsonResponse
from django.shortcuts import render
from .models import Post


def posts(request):
    # it's not a bug if it's intentional ;)
    post_list = Post.objects.filter(published=False)
    # we get page 1 returns 10 post objects
    paginator = Paginator(post_list, 10)
    
    # page_number is initialized to `1` see main.js
    page_number = request.GET.get('page')
    
    # we are applying page number which defaults to `1`
    page_obj = paginator.get_page(page_number)

    if page_number:
        # We are checking if `page_number` < or == 
        paginator.num_pages total amount of pages returned by the `Paginator` this only runs if the above conditions are met
        if int(page_number) <= paginator.num_pages:

            obj_list = paginator.get_page(page_number)

            obj_list = obj_list.object_list.values()

            return JsonResponse(list(obj_list), status=200, safe=False)

    ctx = {'page_obj': page_obj}
    return render(request, 'post/posts.html', ctx)

```
Add your app url to project url config
```
#core/urls.py

from django.contrib import admin
from django.urls import include, path

urlpatterns = [
    path('admin/', admin.site.urls),
    path('', include('blog.urls'))
]

```
Define your app urls.py
```
# blog/urls.py
from django.urls import path
from . import views

urlpatterns = [
    path('', views.posts, name="posts")
]

```

We create a simple example template
```
# template
# 'blog/templates/post/posts.html'
{% load static %}
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        #content{
			margin: 0 auto;
			width: 40vw;
		}
	</style>
</head>

<body>
    <div id="content">
        {% for post in page_obj %}
	        <div>
	            <h1>{{post.title}}</h1>
	            <p>{{post.content}}</p>
	        </div>
        {% endfor %}
    </div>
</body>
<script type="text/javascript" src="{% static 'blog/js/main.js' %}"></script>

</html>

```
On the js side of things, we are listening to scroll event, when we scroll to the bottom of the page, we trigger a function that calls our view which in turn returns a Json objects that we can inject to our template.

```
# main.js
# 'blog/static/blog/js/main.js'

content = document.querySelector("#content");
let page = 1

window.onscroll = function() {
    url = `/?page=${page}`
    if (window.innerHeight + window.pageYOffset >= document.body.offsetHeight) {
        fetch(url).then(res => {
            if (res.ok) {
                return res.json();
            }
        }).then(data => {
            console.dir(data)
            page += 1
            content.innerHTML += data.map(
            	obj=>`<div>
            	<h1>${obj.title}</h1> 
            	<p>${obj.content}</p> 
            	</div>`
            	).join("\n")
        }).catch(err => {

        })
    }
}
```

I hope this helps shed some weight on your web application, because things like these are not worth intsalling an external library (waypointjs i'm looking at you), please help your app shed some weight! Happy coding!