Skip to content

Instantly share code, notes, and snippets.

@nicholaskajoh
Last active November 27, 2023 10:01
Show Gist options
  • Save nicholaskajoh/ae85bb836f2a6254244c847b962095d4 to your computer and use it in GitHub Desktop.
Save nicholaskajoh/ae85bb836f2a6254244c847b962095d4 to your computer and use it in GitHub Desktop.
Lazy load your content with Django and jQuery
<html>
<head>
<script type="text/javascript">
// A CSRF token is required when making post requests in Django
// To be used for making AJAX requests in script.js
window.CSRF_TOKEN = "{{ csrf_token }}";
</script>
</head>
<body>
<h2>My Blog Posts</h2>
<div id="posts">
{% include 'myapp/posts.html' %}
</div>
<div><a id="lazyLoadLink" href="javascript:void(0);" data-page="2">Load More Posts</a></div>
</body>
</html>
from __future__ import unicode_literals
from django.db import models
class Post(models.Model):
title = models.CharField()
content = models.TextField()
{% for post in posts %}
<div>
<h4>{{ post.title }}</h4>
<p>{{ post.content }}</p>
</div>
{% endfor %}
(function($) {
$('#lazyLoadLink').on('click', function() {
var link = $(this);
var page = link.data('page');
$.ajax({
type: 'post',
url: '/lazy_load_posts/',
data: {
'page': page,
'csrfmiddlewaretoken': window.CSRF_TOKEN // from index.html
},
success: function(data) {
// if there are still more pages to load,
// add 1 to the "Load More Posts" link's page data attribute
// else hide the link
if (data.has_next) {
link.data('page', page+1);
} else {
link.hide();
}
// append html to the posts div
$('#posts').append(data.posts_html);
},
error: function(xhr, status, error) {
// shit happens friends!
}
});
});
}(jQuery));
from myapp import views
urlpatterns = [
url(r'^$', views.index, name='index'),
url(r'^lazy_load_posts/$', views.lazy_load_posts, name='lazy_load_posts'),
]
from django.shortcuts import render
from myapp.models import Post
from django.template import loader
from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger
from django.http import JsonResponse
def index(request):
posts = Post.objects.all()[:5]
return render(request, 'myapp/index.html', {'posts': posts})
def lazy_load_posts(request):
page = request.POST.get('page')
posts = Post.objects.all()
# use Django's pagination
# https://docs.djangoproject.com/en/dev/topics/pagination/
results_per_page = 5
paginator = Paginator(posts, results_per_page)
try:
posts = paginator.page(page)
except PageNotAnInteger:
posts = paginator.page(2)
except EmptyPage:
posts = paginator.page(paginator.num_pages)
# build a html posts list with the paginated posts
posts_html = loader.render_to_string('myapp/posts.html', {'posts': posts})
# package output data and return it as a JSON object
output_data = {'posts_html': posts_html, 'has_next': posts.has_next()}
return JsonResponse(output_data)
@nicholaskajoh
Copy link
Author

Thanks @nenadzero. Updated!

@nenadzero
Copy link

I also added:

if request.user.is_authenticated:
        user = request.user
    else:
        user = None

before line 27 views.py
and change line 27 to:
posts_html = loader.render_to_string('myapp/posts.html', {'user': user, 'posts': posts})
because we must have user info in template
example:

{% for post in posts %}
{% if user in post.likes.all %} 
<button> Unlike </button>
{ % else %} 
<button> Like </button>
{% endif %}
{% endfor %}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment