添加对象时的 Django 分页
Django pagination while objects are being added
我有一个网站显示的照片总是被添加,人们看到主页上的页面之间存在重复(最后添加的照片)
我不完全确定如何解决这个问题,但这基本上是正在发生的事情:
- 首页显示最新的20张照片[0:20]
- 用户滚动(同时正在将照片添加到数据库
- 用户加载下一页(通过 ajax)
- 页面显示照片[20:40]
- 用户看到重复的照片,因为添加到列表顶部的照片将它们推到下一页
解决这个问题的最佳方法是什么?我想我可能需要以某种方式在用户会话中缓存查询集?我真的不太了解缓存,所以一步一步的解释将是无价的
这是获取新页面图像的函数:
def get_images_paginated(query, origins, page_num):
args = None
queryset = Image.objects.all().exclude(hidden=True).exclude(tags__isnull=True)
per_page = 20
page_num = int(page_num)
if origins:
origins = [Q(origin=origin) for origin in origins]
args = reduce(operator.or_, origins)
queryset = queryset.filter(args)
if query:
images = watson.filter(queryset, query)
else:
images = watson.filter(queryset, query).order_by('-id')
amount = images.count()
images = images.prefetch_related('tags')[(per_page*page_num)-per_page:per_page*page_num]
return images, amount
使用函数的视图:
def get_images_ajax(request):
if not request.is_ajax():
return render(request, 'home.html')
query = request.POST.get('query')
origins = request.POST.getlist('origin')
page_num = request.POST.get('page')
images, amount = get_images_paginated(query, origins, page_num)
pages = int(math.ceil(amount / 20))
if int(page_num) >= pages:
last_page = True;
else:
last_page = False;
context = {
'images':images,
'last_page':last_page,
}
return render(request, '_images.html', context)
您可以采取的一种方法是在 AJAX 请求中发送客户端当前拥有的最旧 ID(即当前列表中最后一项的 ID),然后确保您只查询旧 ID。
所以get_images_paginated
修改如下:
def get_images_paginated(query, origins, page_num, last_id=None):
args = None
queryset = Image.objects.all().exclude(hidden=True).exclude(tags__isnull=True)
if last_id is not None:
queryset = queryset.filter(id__lt=last_id)
...
您需要在 AJAX 请求中发送最后一个 ID,并将其从您的视图函数传递给 get_images_paginated
:
def get_images_ajax(request):
if not request.is_ajax():
return render(request, 'home.html')
query = request.POST.get('query')
origins = request.POST.getlist('origin')
page_num = request.POST.get('page')
# Get last ID. Note you probably need to do some type casting here.
last_id = request.POST.get('last_id', None)
images, amount = get_images_paginated(query, origins, page_num, last_id)
...
正如@doniyor 所说,您应该结合此逻辑使用 Django 的内置分页。
我有一个网站显示的照片总是被添加,人们看到主页上的页面之间存在重复(最后添加的照片)
我不完全确定如何解决这个问题,但这基本上是正在发生的事情:
- 首页显示最新的20张照片[0:20]
- 用户滚动(同时正在将照片添加到数据库
- 用户加载下一页(通过 ajax)
- 页面显示照片[20:40]
- 用户看到重复的照片,因为添加到列表顶部的照片将它们推到下一页
解决这个问题的最佳方法是什么?我想我可能需要以某种方式在用户会话中缓存查询集?我真的不太了解缓存,所以一步一步的解释将是无价的
这是获取新页面图像的函数:
def get_images_paginated(query, origins, page_num):
args = None
queryset = Image.objects.all().exclude(hidden=True).exclude(tags__isnull=True)
per_page = 20
page_num = int(page_num)
if origins:
origins = [Q(origin=origin) for origin in origins]
args = reduce(operator.or_, origins)
queryset = queryset.filter(args)
if query:
images = watson.filter(queryset, query)
else:
images = watson.filter(queryset, query).order_by('-id')
amount = images.count()
images = images.prefetch_related('tags')[(per_page*page_num)-per_page:per_page*page_num]
return images, amount
使用函数的视图:
def get_images_ajax(request):
if not request.is_ajax():
return render(request, 'home.html')
query = request.POST.get('query')
origins = request.POST.getlist('origin')
page_num = request.POST.get('page')
images, amount = get_images_paginated(query, origins, page_num)
pages = int(math.ceil(amount / 20))
if int(page_num) >= pages:
last_page = True;
else:
last_page = False;
context = {
'images':images,
'last_page':last_page,
}
return render(request, '_images.html', context)
您可以采取的一种方法是在 AJAX 请求中发送客户端当前拥有的最旧 ID(即当前列表中最后一项的 ID),然后确保您只查询旧 ID。
所以get_images_paginated
修改如下:
def get_images_paginated(query, origins, page_num, last_id=None):
args = None
queryset = Image.objects.all().exclude(hidden=True).exclude(tags__isnull=True)
if last_id is not None:
queryset = queryset.filter(id__lt=last_id)
...
您需要在 AJAX 请求中发送最后一个 ID,并将其从您的视图函数传递给 get_images_paginated
:
def get_images_ajax(request):
if not request.is_ajax():
return render(request, 'home.html')
query = request.POST.get('query')
origins = request.POST.getlist('origin')
page_num = request.POST.get('page')
# Get last ID. Note you probably need to do some type casting here.
last_id = request.POST.get('last_id', None)
images, amount = get_images_paginated(query, origins, page_num, last_id)
...
正如@doniyor 所说,您应该结合此逻辑使用 Django 的内置分页。