The problem is that duplicated posts appear during automatic pagination.
If the loop {% for post in post_lists %} in the home.html template specifies the output of 5 published posts, then during automatic pagination, duplicates of these 5 published posts are added from the home_list.html template, which is incorrect.
Automatic pagination works correctly and displays all published posts properly. The issue only lies with the duplication of the first five published posts; the rest of the posts are not duplicated and are displayed correctly.
How to fix this?
home.html:
{% for post in post_lists %}
<div class="post_content" id="post_content">
<!----code for displaying posts goes here---->
</div>
{% endfor %}
<div id="pagination-loader" class="pagination_pages" data-page="1"></div>
</div>
<script>
$(document).ready(function(){
var loadedPage = 1; // Variable to store the loaded page number
// Function to load the next batch of posts
function loadNextPage() {
// Perform an AJAX request to the server
var nextPageUrl = '/load-posts/?page=' + loadedPage;
console.log("Next page URL:", nextPageUrl);
$.ajax({
url: nextPageUrl,
type: 'GET',
dataType: 'json',
success: function(response) {
console.log("Response from server:", response);
// Check for post data in the JSON response
if (response.posts) {
// Add HTML with posts to the end of the container
$('#post_contenter').append(response.html_posts);
// Check if there are more posts on the next page
if (response.next_page_url) {
// Increment the value of the loadedPage variable
loadedPage++;
} else {
// If there is no next page, hide the loading indicator
$('#pagination-loader').hide();
}
} else {
// If there is no post data, display an error message
console.error('Error loading posts: Post data is missing in the JSON response');
}
},
error: function(jqXHR, textStatus, errorThrown) {
// Handle the request error if it occurs
console.error('Error loading posts:', textStatus, errorThrown);
}
});
}
// Event handler for page scrolling
$(window).on('scroll', function() {
// Get the current scroll position
var scrollPosition = $(window).scrollTop();
// Get the height of the browser window
var windowHeight = $(window).height();
// Get the height of the entire document
var documentHeight = $(document).height();
// If the user has scrolled to the end of the page
if (scrollPosition + windowHeight >= documentHeight) {
// Check if the loading indicator is visible
if ($('#pagination-loader').is(':visible')) {
// Load the next batch of posts
loadNextPage();
}
}
});
// Check if the first page of posts needs to be loaded when the page is loaded
if($(window).scrollTop() + $(window).height() == $(document).height()) {
loadNextPage();
}
});
</script>
home_list.html:
{% if posts %}
<div class="post-list">
{% for post in posts %}
<div class="post_content" id="post_content">
<!----code for displaying posts goes here---->
</div>
</div>
{% endfor %}
{% endif %}
views.py:
@login_required
def create_post(request):
form = PostForm(request.POST or None)
if request.method == 'POST':
if form.is_valid():
post = form.save(commit=False)
post.author = request.user
post.save()
return redirect('home')
# Get the IDs of users whom the current user is subscribed to
subscribed_user_ids = Subscription.objects.filter(subscriber=request.user).values_list('target_user', flat=True)
# Get all posts from authors whom the current user is subscribed to
subscribed_posts = Userpublication.objects.filter(author__in=subscribed_user_ids)
# Get all posts by the current user
own_posts = Userpublication.objects.filter(author=request.user)
# Combine the lists of posts
all_posts = (subscribed_posts | own_posts).order_by('-time_create').distinct()
# Get the page object for displaying posts
page_number = request.GET.get('page', 1)
paginator = Paginator(all_posts, 5) # 5 posts per page
try:
page_posts = paginator.page(page_number)
except PageNotAnInteger:
page_posts = paginator.page(1)
except EmptyPage:
page_posts = paginator.page(paginator.num_pages)
context = {'form': form, 'post_lists': page_posts, 'title': 'Twippie | News', 'page_number': page_number}
return render(request, 'twippie/home.html', context)
@login_required
def load_posts(request):
# Get the page number from the request
page_number = request.GET.get('page', 1) # Default to page 1 if not provided
# Get the IDs of users whom the current user is subscribed to
subscribed_user_ids = Subscription.objects.filter(subscriber=request.user).values_list('target_user', flat=True)
# Get all posts from users whom the current user is subscribed to or posts authored by the current user
all_posts = Userpublication.objects.filter(Q(author__in=subscribed_user_ids) | Q(author=request.user)).order_by('-time_create').distinct()
# Create a Paginator object
paginator = Paginator(all_posts, 5) # 5 posts per page
try:
# Get the objects for the current page
current_page_posts = paginator.page(page_number)
except PageNotAnInteger:
# If the page number is not an integer, show the first page
current_page_posts = paginator.page(1)
except EmptyPage:
# If the page is out of range, return an empty response
return JsonResponse({'posts': [], 'next_page_url': None})
# Render HTML markup for the posts
html_posts = render_to_string('twippie/home_list.html', {'posts': current_page_posts})
# Form a list of posts to pass to JSON
posts_list = [{'id': post.id, 'content': post.content} for post in current_page_posts]
# Get the URL for the next page if it exists
next_page_url = None
if current_page_posts.has_next():
next_page_url = reverse('load_posts') + f'?page={current_page_posts.next_page_number()}'
# Return a JSON response with data about the posts, HTML markup, and URL of the next page
return JsonResponse({'posts': posts_list, 'html_posts': html_posts, 'next_page_url': next_page_url})
2
Answers
Two key notes
You need to order with id with the time_create, I assume you’re testing and created the posts in a loop, sometimes this can result in a post with the same time_create
This is a limitation of the normal Paginator (Limit/Offset), use a Cursor paginator instead
Its supported in DRF as
rest_framework.pagination.CursorPagination
, use it indjango_paginator_class
Problem :-
Look comments in the code. Frist page already loaded. But you load frist page again with js. That’s the problem.
Answer :-