Second page of Pagination not working in django after searching - django

Searching result is not appearing in second page what should I change to solve my problem ? and I'm using elasticsearch as search engine
index.html
<ul>
{% for i in paginator.page_range %}
{% if i <= page_number|add:5 and i >= page_number|add:-5 %}
<li class=" {% if i == page_number %} active {% endif %} " >
{{forloop.counter}}
</li>
{% endif %}
{% endfor %}
</ul>
and this is in my views.py
def index(request):
q = request.GET.get('q')
if q:
articles = PostDocument.search().query("match", title=q, )
paginator = Paginator(articles, 5)
page_number = request.GET.get('page', 1)
page_obj = paginator.get_page(page_number)
return render(request, 'index.html', {
'articles': page_obj.object_list,
'paginator': paginator,
'page_number': int(page_number),
})
else:
articles = ''
return render(request, 'index.html', {'articles': articles})

If you write ?page=…, then the ?q=… parameter is "dropped". The trick is to add it to the querystring when you go to the next object:
def index(request):
q = request.GET.get('q')
if q:
articles = PostDocument.search().query("match", title=q, )
paginator = Paginator(articles, 5)
page_number = request.GET.get('page', 1)
page_obj = paginator.get_page(page_number)
return render(request, 'index.html', {
'articles': page_obj.object_list,
'paginator': paginator,
'page_number': int(page_number),
'q' : q
})
else:
articles = ''
return render(request, 'index.html', {'articles': articles})
and then render this with:
{{forloop.counter}}
The |urlencode template filter [Django-doc] is necessary to percentage encode the query, for example if it contains a question mark (?), ampersand (&), etc.

Related

How can I Render Data To Main Template In Other Extended View From Main Template?

First of all, hello everyone. I apologize to everyone for my bad English, I will try my best. I am making a video site, in this site there are three main views, they are single-video-view, index-view and main-view. All other views extends from main-view (%extends 'base/main.html' %). There is a sidebar that should appear on all pages. In this sidebar, the categories of pre-loaded videos should be listed.
My urls.py:
urlpatterns = [
path('',views.index,name="index"),
path('main/',views.main,name="main"),
path('video/<slug:slug>/',views.video,name="video"),
#path('test/',views.category,name="setcategory"),
path('apivideo/',views.apivideo,name="apivideo"),
]
If I visit main.html directly working fine
Single video view, categories not listing
Index view, categories not listing
View.py:
def index(request):
# q = request.GET.get('q')
# if request.GET.get('q') != None:
if 'q' in request.GET and request.GET['q']:
page = request.GET.get('page', 1)
q = request.GET['q']
videos = Video.objects.filter(
Q(video_title__icontains=q) | Q(video_tags__icontains=q))
paginator = Paginator(videos, 24)
videos = paginator.page(page)
return render(request, 'base/index.html', {'videos': videos, 'q': q})
else:
main(request)
videos = Video.objects.all().order_by("-id")
paginator = Paginator(videos, 24)
page_number = request.GET.get('page')
videos = paginator.get_page(page_number)
return render(request, 'base/index.html', {'videos': videos})
def main(request):
setcategory = []
category = Video.objects.values_list('video_tags', flat=True)
for i in range(0, len(category)):
for x in range(0, len(category[i])):
categorycount = Video.objects.filter(Q(video_title__icontains=str(
category[i][x]).lower()) | Q(video_tags__icontains=str(category[i][x]).lower())).count()
if (categorycount >= 10):
print("if: " + str(categorycount))
setcategory.append(str(category[i][x]).lower())
else:
print("else: " + str(categorycount))
break
setcategory = sorted([*set(setcategory)])
return render(request, 'base/main.html', {'setcategory': setcategory})
def video(request, slug):
eachvideo = Video.objects.get(video_slug=slug)
randomVideo = list(Video.objects.all())
randomVideo = random.sample(randomVideo, 20)
return render(request, 'base/video.html', {'eachvideo': eachvideo, 'randomVideo': randomVideo})
Main.html:
Some HTML..
<ul class="sidebar navbar-nav toggled">
{% if setcategory %}
{% for category in setcategory %}
<li class="nav-item active">
<a class="nav-link" href="{% url 'index' %}?q={{category}}">
<i class="fas fa-fw fa-home"></i>
<span>{{category|title}}</span>
</a>
</li>
{% endfor %}
{% endif %}
</ul>
Some HTML..
The code I wrote for this works fine, but it only works when I add a redirect to the main-view specifically in the url .py file and go to the main view page. What I want is for these categories to appear in the sidebar when the user browses the index or other pages.

How to hide html button if queryset doesn't have next blog post in Django?

I would like to hide the Next button in my blog if there is no next blog post available.
Is there some kind of built-in method to check has_next has_previous or do I need to create some logic in my view and extend the template with let's say {% if Foo %} show button {% endif %} ?
views.py
def render_post(request, id):
category_count = get_category_count()
most_recent = Post.objects.order_by('-timestamp')[:3]
post = get_object_or_404(Post, id=id)
next_post_id = int(id) + 1
previous_post_id = int(id) - 1
PostView.objects.get(post=post)
context = {
'post': post,
'id': id,
'next_post_id': next_post_id,
'previous_post_id': previous_post_id,
'most_recent': most_recent,
'category_count': category_count,
}
return render(request, 'post.html', context)
html
<div id="button-wrapper">
<button class="buttons" type="submit">Previous</button>
<button class="buttons" type="submit">Next</button>
</div>
You could do it by checking that the previous/next posts exist and returning the results in the context:
views.py
def render_post(request, id):
category_count = get_category_count()
most_recent = Post.objects.order_by('-timestamp')[:3]
post = get_object_or_404(Post, id=id)
next_post_id = int(id) + 1
previous_post_id = int(id) - 1
try:
previous_post_exists = Post.objects.filter(id=previous_post_id).exists()
except Post.DoesNotExist:
previous_post_exists = False
try:
next_post_exists = Post.objects.filter(id=next_post_id).exists()
except Post.DoesNotExist:
next_post_exists = False
context = {
'post': post,
'id': id,
'next_post_id': next_post_id,
'previous_post_id': previous_post_id,
'previous_post_exists': previous_post_exists,
'next_post_exists': next_post_exists,
'most_recent': most_recent,
'category_count': category_count,
}
return render(request, 'post.html', context)
You would then need to check those values in your template:
html
<div id="button-wrapper">
{% if previous_post_exists %}
<button class="buttons" type="submit">Previous</button>
{% endif %}
{% if next_post_exists %}
<button class="buttons" type="submit">Next</button>
{% endif %}
</div>

How to apply django lazy loading to load my comments?

I am tried but i am not getting the desired output for lazy loading
views.py
def post_detail(request, pk):
post = get_object_or_404(Post, pk=pk)
content_type = ContentType.objects.get_for_model(Post)
obj_id = post.id
comments = Comment.objects.filter(
content_type=content_type, object_id=obj_id)
parent_id = request.POST.get("parent_id")
csubmit = False
if parent_id:
content_type = ContentType.objects.get_for_model(Comment)
Comment.objects.create(content_type=content_type,
object_id=parent_id,
parent_id=parent_id,
user=request.user,
text=request.POST.get("text"))
if request.method == 'POST':
form = CommentForm(data=request.POST)
if form.is_valid():
new_comment = form.save(commit=False)
new_comment.content_type = content_type
new_comment.user = request.user
new_comment.save()
csubmit = True
else:
form = CommentForm()
paginator = Paginator(comments, 10)
try:
comments = paginator.page(page)
except PageNotAnInteger:
comments = paginator.page(1)
except EmptyPage:
comments = paginator.page(paginator.num_pages)
return render(request, 'post_detail.html', {'post': post,
'comments': comments, 'csubmit': csubmit, 'form': form})
I want to apply lazy loading in the above view and want to apply on template.Above i added pagination and rendered in template
post_details.html
{%for comment in comments %}
<br>
{{comment.text}}<br/>
by {{comment.user}}<br>
<a href='#' class="rep_cmt" data-parentid="
{{comment.id}}">Reply</a><br>
{% for comment in comment.children.all %}
{{comment}}
{% endfor %}
{%endfor%}
{% if comments.has_next %}
<a class="infinite-more-link" href="?page={{ comments.next_page_number
}}">More</a>
{% endif %}
<div class="loading" style="display: none;">
Loading...
</div>
<script>
var infinite = new Waypoint.Infinite({
element: $('.rep_cmt')[0],
onBeforePageLoad: function () {
$('.loading').show();
},
onAfterPageLoad: function ($items) {
$('.loading').hide();
}
});
</script>
In above i added script to render data in lazy loading process but it is not rendering

Django template variable does not show up

for some reason im unable to display the comments of a category_request and i have now idea why, is smb. maybe able to have an eye on that, praticaly i should work but i dont see the mistake here.
as far as i see I'm using category_request_comment from the view to get a releated comment objects from a category_request... any idea?
Template Snippet:
{% for category_request_comment in category_request_comments %}
<div class="comment">
<p>{{ category_request_comment.content|readmore:15 }}</p>
{% if category_request_comment.content.published_date %}
<div class="date">
<a>Comment by: {{ category_request_comment.author }}</a><br>
<a>Commented at: {{ category_request_comment.published_date }}</a>
</div>
{% endif %}
{% if request.user == category_request_comment.author %}
<a class="commentoption" href="{% url 'comment_edit' pk=category_request_comment.pk %}">Edit</a><a> | </a>
<a class="commentoption" href="{% url 'comment_delete' pk=category_request_comment.pk %}">Delete</a>
{% endif %}
</div>
{% endfor %}
views.py
def category_request_detail(request, pk):
category_request = get_object_or_404(CategoryRequests, pk=pk)
list_category_request = CategoryRequests.objects.get_queryset().filter(id=pk).order_by('-pk')
paginator = Paginator(list_category_request, 20)
page = request.GET.get('page')
category_request_comment = paginator.get_page(page)
return render(request, 'myproject/category_request_detail.html', {'category_request': category_request, 'category_request_comment': category_request_comment})
views.py (only for Reference)
def category_request_comment_new(request, pk):
if request.method == "POST":
form = CategoryRequestsCommentForm(request.POST)
if form.is_valid():
category_request = get_object_or_404(CategoryRequests, pk=pk)
requests_comment = form.save(commit=False)
requests_comment.author = request.user
requests_comment.published_date = timezone.now()
requests_comment.category_request = category_request
requests_comment.save()
return redirect('category_request_detail', pk=requests_comment.category_request.pk)
else:
form = CategoryRequestsCommentForm()
return render(request, 'myproject/comment_new.html', {'form': form})
urls.py
url(r'^categories/requests/$', myproject_views.category_request_list, name='category_request_list'),
Thanks in advance
Your template is looking for an object called category_request_comments, but you have not sent anything with that name to the template.
def category_request_detail(request, pk):
category_request = get_object_or_404(CategoryRequests, pk=pk)
list_comments = CategoryRequests_Comment.objects.get_queryset().filter(category_request_id=pk).order_by('-pk')
paginator = Paginator(list_comments, 10)
page = request.GET.get('page')
comments = paginator.get_page(page)
return render(request, 'myproject/category_request_detail.html', {'category_request': category_request, 'comments': comments})

How to implement Post/Redirect/Get in django pagination?

I have a view that filters out results for a posted search form:
def profile_advanced_search(request):
args = {}
if request.method == "POST":
form = AdvancedSearchForm(request.POST)
qs=[]
if form.is_valid():
cd = form.cleaned_data
s_country=cd['country']
s_province=cd['province']
s_city = cd['city']
if s_country: qs.append(Q(country__icontains = s_country))
if s_province: qs.append( Q(province__icontains=s_province))
if s_city: qs.append( Q(city__icontains=s_city))
f = None
for q in qs:
if f is None:
f=q
else: f &=q
list = UserProfile.objects.filter(f).order_by('-created_at')
else:
form = AdvancedSearchForm()
list = UserProfile.objects.all().order_by('-created_at')
paginator = Paginator(list,10)
page= request.GET.get('page')
try:
results = paginator.page(page)
except PageNotAnInteger:
results = paginator.page(1)
except EmptyPage:
results = paginator.page(paginator.num_pages)
args.update(csrf(request))
args['form'] = form
args['results'] = results
return render_to_response('userprofile/advanced_search.html', args,
context_instance=RequestContext(request))
the urls.py part is:
url(r'^search/$', 'userprofile.views.profile_advanced_search'),
The template is:
<form action="/search/" method="post">{% csrf_token %}
<ul class="list-unstyled">
<li><h3>Country</h3></li>
<li>{{form.country}}</li><br>
<h4>Province</h4>
<li>{{form.province}}</li>
<h4>City</h4>
<li>{{form.city}}</li>
</ul>
<input type="submit" name="submit" value="search" />
</form>
Search Results:
{% for p in results %}
<div">
<div>
<br>
<strong><a href="/profile/{{p.username}}" >{{p.username}}</a></strong>
{{p.country}} <br>
{{p.province}} <br>
{{p.city}} <br>
</div>
</div>
{% endfor %}
<div>
<div class="pagination">
{% if results.has_previous %}
<< Prev &nbsp
{% endif %}
{% if results.has_next %}
Next >>
{% endif %}
</div>
</div>
</div>
These work fine for the first page, but to deal with the later pages, it is suggested that I need to implement Post/Redirect/Get .
However I have had difficulty to make such views/template/urls to deal with GET pages regarding that all of the search parameters are arbitrary. So I appreciate a complete solution.
Do you need 2 views. First one for form search and second one to show results. You have not implemented redirect in any way in your sample code!
urls
...
url(r'^search/$',
'userprofile.views.profile_advanced_search'),
url(r'^show/(?P<country>\w+)/(?P<province>\w+)/(?P<site>\w+)/(?P<page>\d+)',
'userprofile.views.profile_advanced_show'),
...
profile_advanced_search
def profile_advanced_search(request):
args = {}
if request.method == "POST":
form = AdvancedSearchForm(request.POST)
qs=[]
if form.is_valid():
cd = form.cleaned_data
s_country=cd['country']
s_province=cd['province']
s_city = cd['city']
return HttpResponseRedirect(
reverse('userprofile.views.profile_advanced_show',
args=(s_country, s_province, s_city, 0, )))
return HttpResponseRedirect(
reverse('userprofile.views.profile_advanced_show',
args=('+', '+', '+', 0, )))
profile_advanced_show
def profile_advanced_show(request, s_country='',
s_province='', s_city='', page=0):
f = some filters with s_country, s_province and s_city
list = UserProfile.objects.filter(f).order_by('-created_at')
paginator = Paginator(list,10)
try:
results = paginator.page(page)
except PageNotAnInteger:
results = paginator.page(1)
except EmptyPage:
results = paginator.page(paginator.num_pages)
args.update(csrf(request))
form = AdvancedSearchForm(initial={ 's_country': s_country, ... } )
args['form'] = form
args['results'] = results
return render_to_response('userprofile/advanced_search.html', args,
context_instance=RequestContext(request))
Notice: improve it for not valid form submissions. Remember you can send parameters to second view via GET as key value instead route values.