HTMX not working when using paginate with infinite-scroll - django

I have a product card in my Django Application, when clicked, adds to cart. I'm using infinite-scroll and django-pagination.
The issue is with the pagination, however. The first page of results works wonderfully with HTMX. However, the second page and all pages beyond does not work on click. Upon inspecting the page, the html does appear to be rendered properly and I can see the hx-get call with the proper url. But upon clicking, nothing happens.
Maybe I'm missing something obvious here, but any help would be appreciated!
HTML
<div class="container"
data-infinite-scroll='{ "path": ".pagination__next", "append": ".product-card", "history":"false"}'>
{% block content %}
{% include 'includes/cards.html' %}
{% include 'includes/sidebar.html' %}
{% endblock content %}
</div>
<ul class="pagination mt-50 mb-70">
{% if products.has_previous %}
<li class="page-item"><a class="page-link" href="?page={{ products.previous_page_number }}"><i class="fa fa-angle-left"></i></a></li>
{% endif %}
<li class="page-item"><a class="page-link" href="#">{{ products.number }}</a></li>
{% if products.has_next %}
<li class="page-item"><a class="pagination__next" href="?page={{ products.next_page_number }}"><i class="fa fa-angle-right"></i></a></li>
{% endif %}
</ul>
views.py
def shop(request):
anabanner = AnaBanner.objects.all()
gender = Gender.objects.all()
categories = Category.objects.all()
colors = Color.objects.all()
materials = Material.objects.all()
query = request.GET.get('query','')
products = Product.objects.all().order_by('-pk')
if query:
products = products.filter(
Q(name__icontains=query)|
Q(sub_name__icontains=query)
).distinct()
paginator = Paginator(products, 8)
page = request.GET.get('page')
products = paginator.get_page(page)
context = {'products':products,'categories':categories,'gender':gender,'anabanner':anabanner,'colors':colors,'materials':materials}
return render(request, 'shop.html', context)
Button
<div class="button">
<div class="button-layer"></div>
<button name="ekle"
href ="#"
hx-get="{% url 'add_to_cart' product.id %}"
hx-target="#menu-cart-button"
hx-swap="outerHTML"
class="btn btn-outline-secondary add-btn update-cart">Sepete Ekle</button>
</div>

Here i my Infinite scroll pattern django with HTMX
urls.py
highlights_urls = [
path('<slug:slug>/',
views.highlight_detail,
name='highlight_detail',
),
]
urlpatterns = [
path('highlights/', include(highlights_urls)),
]
views.py
def highlight_detail(request, slug: str):
object: Highlight = get_object_or_404(Highlight, slug=slug)
template_name = 'highlight/highlight-detail.html'
if request.htmx:
template_name = 'highlight/partials/highlight-detail-partial-elements.html'
page_number = request.GET.get('page', default=1)
paginator = Paginator(object.products.all(), settings.PAGINATION_PAGE_SIZE)
page_obj = paginator.get_page(page_number)
context = {
'object': object,
'page_obj': page_obj
}
return TemplateResponse(request, template=template_name, context=context)
highlight-detail.html
<section class="padding-top">
<div class="container">
<header class="section-heading">
<h3 class="section-title">{{ object.name }}</h3>
</header>
<div class="row" hx-indicator=".htmx-indicator">
{% include './partials/highlight-detail-partial-elements.html' %}
</div>
</div> <!-- container end.// -->
highlight-detail-partial-elements.html
{% for product in page_obj %}
<div
{% if forloop.last and page_obj.has_next %}
hx-get="{% url 'highlight_detail' object.slug %}?page={{ page_obj.number|add:1 }}"
hx-trigger="revealed"
hx-swap="afterend"
hx-target="this"
{% endif %}
class="col-6 col-sm-4 col-md-3 col-lg-3 col-xl-3">
{% include 'highlight/includes/product-card.html' with object=product %}
</div>
{% endfor %}

Related

Adding a tag to a pagination element django

When creating a pagination, everything works as it should. Added (?page= page number selection) pagination.
How can I add the pagination page number to its object?
When selecting an object and reloading the page, I need it to be spelled out in the URL (/?page=pagination number).
And the pagination remained on the selected page.
class MovieShow(DetailView):
model = Movie
template_name = 'movies/movie_play.html'
context_object_name = 'movie'
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['object_list'] = Movie.objects.filter(course__slug=self.kwargs['course_slug'])
context['title'] = context['movie']
paginator = Paginator(context['object_list'], 1)
page = self.request.GET.get('page')
try:
context['object_list'] = paginator.page(page)
except PageNotAnInteger:
context['object_list'] = paginator.page(1)
except EmptyPage:
context['object_list'] = paginator.page(paginator.num_pages)
return context
This is how I present pagination in the template
<div class="pagination" id="pagination">
<span class="step-links" >
{% if object_list.has_previous %}
<a class="page-link" href="?page=1"> << </a>
<a class="page-link" href="?page={{ object_list.previous_page_number }}"> < </a>
{% endif %}
<span class="current">
{{ object_list.number }} из {{ object_list.paginator.num_pages }}
</span>
{% if object_list.has_next %}
<a class="page-link" href="?page={{ object_list.next_page_number }}"> > </a>
<a class="page-link" href="?page={{ object_list.paginator.num_pages }}"> >> </a>
{% endif %}
</span>
And so I have a search of the elements inside the pagination, on which I want to hang the pagination page number.
I really hope I asked the question correctly.
I will be glad of any help!
<div class="video_courses" id="block-posts">
{% for c in object_list %}
<a class="a_hover" href="{{ c.get_absolute_url }}">
<div class="video_courses_block">
<div class="video_courses_block_img"><img src="{{ c.poster.url }}" alt=""></div>
<div class="video_courses_block_text">
<div class="video_courses_block_text_title"><h2>[ {{ c.author }} ] {{ c.title }}</h2></div>
<div class="video_courses_block_text_navigation">
<div class="video_courses_block_text_left">{{ c.category }}</div>
<div class="video_courses_block_text_rig">{{ course.movie_set.count }}</div>
</div>
</div>
</div>
</a>
{% endfor %}
{% include 'pagination.html' %}
You just need to add if to the link and specify the page number
{% for c in object_list %}
{% if object_list.number %}
<a class="a_hover" href="{{ c.get_absolute_url }}?page={{ object_list.number }}">
{% endif %}
<div class="video_courses_block">
<div class="video_courses_block_img"><img src="{{ c.poster.url }}" alt=""></div>
<div class="video_courses_block_text">
<div class="video_courses_block_text_title">
<h2>[ {{ c.author }} ] {{ c.title }}</h2>
</div>
<div class="video_courses_block_text_navigation">
<div class="video_courses_block_text_left">{{ c.category }}</div>
<div class="video_courses_block_text_rig">{{ course.movie_set.count }}</div>
</div>
</div>
</div>
</a>
{% endfor %}
</div>
{% include 'pagination.html' %}

How to create a search function on a class-based list view?

I am trying to create a search function based on the title of my posts. Right now I am trying to implement this search using a filter but the list view is not rendering. I am unsure if I should implement a URL for my search function.
This is my model:
class Post(models.Model):
title = models.CharField(max_length=100)
image = models.ImageField(default = 'default0.jpg', upload_to='course_image/')
description = models.TextField()
price = models.DecimalField(decimal_places=2, max_digits=6)
date_posted = models.DateTimeField(default=timezone.now)
author = models.ForeignKey(User, on_delete=models.CASCADE)
feedback = models.ManyToManyField(Feedback)
def __str__(self):
return self.title
def get_absolute_url(self):
return reverse('post-detail', kwargs={'pk' : self.pk})
This is my class-based list view:
class PostListView(ListView):
model = Post
template_name = 'store/sub_home.html' # <app>/<model>_<viewtype>.html
context_object_name = 'posts'
ordering = ['date_posted']
paginate_by = 12
def get_queryset(self):
object_list = super(PostListView, self).get_queryset()
search = self.request.GET.get('q', None)
if search:
object_list = object_list.filter(title__icontains = title)
return object_list
This is my search bar:
<div id="search">
<form method='GET' action=''>
<input type="text" name='q' placeholder="">
<button id='search_holder'>
<img src="/static/store/search_icon.gif" id="search_icon">
</button>
</form>
</div>
This is my html that is rendering the posts:
{% extends "store/base.html" %}
{% block content %}
{% include "store/home_ext.html" %}
<div style="padding-top: 20px;" id="main" >
<section class="text-center mb-4">
<div class="row" id="random">
{% for post in posts %}
{% include "store/card.html" %}
{% endfor %}
</div>
<div class="row" id="subscription" style="display: none;">
{% if not subs %}
<h2>You have not subscribed to any course :/</h2>
{% endif %}
{% for post in subs %}
{% include "store/card.html" %}
{% endfor %}
</div>
<div class="row" id="content" style="display: none;">
{% if not mine %}
<h2>You have not published anything :/</h2>
{% endif %}
{% for post in mine %}
{% include "store/card.html" %}
{% endfor %}
</div>
</section>
{% include "store/pagination.html" %}
</div>
{% endblock content %}
This is my card.html:
{% load extra_filter %}
<div class="col-lg-3 col-md-6 mb-4">
<div id="course_card">
<div class="view overlay">
<img style="margin-left: -10px;" src="{{ post.image.url }}" alt="">
</div>
<div>
<div>
<strong>
{% if user.is_authenticated %}
<a class="title" href="{% url 'post-detail' post.id %}" >
{% else %}
<a class="title" href="{% url 'login' %}" >
{% endif %}
{% if post.title|length < 30 %}
<span>{{ post.title }}</span>
{% else %}
<span>{{ post.title|cut:27 }}</span>
{% endif %}
<span style="background-color: rgb(253, 98, 98);" class="badge badge-pill danger-color">NEW
</span>
</a>
</strong>
</div>
<div class="star-ratings-css">
<div class="star-ratings-css-top" style="width: {{ post.feedback|calc_rating }}%"><span>★</span><span>★</span><span>★</span><span>★</span><span>★</span></div>
<div class="star-ratings-css-bottom"><span>★</span><span>★</span><span>★</span><span>★</span><span>★</span></div>
</div>
<a href="{% url 'user-posts' post.author.username %}" class="author">
by {{ post.author }}
</a>
<div>
<strong style="text-align: right;" class="price">S${{ post.price }}
</strong>
</div>
<small class="date">
{{ post.date_posted|date:'d F y'}}
</small>
</div>
</div>
</div>
As Nalin Dobhal mentioned in comments, context_object_name should be posts not post. Because in template, you are iterating through posts context variable. Also, when using search functionality, the implementation should be like this:
class PostListView(ListView):
model = Post
template_name = 'store/sub_home.html' # /_.html
context_object_name = 'posts'
ordering = ['date_posted']
paginate_by = 12
def get_queryset(self, *args, **kwargs):
object_list = super(PostListView, self).get_queryset(*args, **kwargs)
search = self.request.GET.get('q', None)
if search:
object_list = object_list.filter(title__icontains = search)
return object_list
Because you are sending the search query through URL querystring(ie: url will look like /posts/?q=title in browser). I am using request.GET.get('q') to fetch those query string values, and use it to filter the queryset.

Error pagination when filter to list by category ListView Django

I'm new with programming, my mentor only youtube, and when i got error, i search similar error in stackoverflow, but no luck now.
I have a problem with my code or maybe my logic. I don't have much experience or knowledge about call queryset for filtering correctly.
This my urls.py
urlpatterns = [
path('', IndexView.as_view(), name='index'),
path('product/<int:page>', ProductListView.as_view(), name='allproducts'),
path('<categories>/<int:page>', ProductCategoryListView.as_view(),
name='product_category'),
]
I have ProductListView with no error pagination.
class ProductListView(ListView):
context_object_name = 'product_list'
template_name = 'product.html'
model = Product
paginate_by = 16
def get_context_data(self, *args, **kwargs):
context = super(ProductListView, self).get_context_data(*args,**kwargs)
context ['catlist'] = Category.objects.all()
return context
when i filter by category, pagination doesn't work. filter by
category work fine, but when paginate_by more than my product, page
error
Reverse for 'product_category' with arguments '('', 2)' not found. 1 pattern(s) tried: ['(?P[^/]+)/(?P[0-9]+)$']\
class ProductCategoryListView(ListView):
context_object_name = 'product_list'
template_name = 'product_list.html'
model = Product
paginate_by = 20
def get_queryset(self):
self.queryset = self.model.objects.filter(category__name=self.kwargs['categories'])
return super().get_queryset()
def get_context_data(self, *args, **kwargs):
context = super(ProductCategoryListView, self).get_context_data(*args,**kwargs)
context ['catlist'] = Category.objects.all()
return context
This my models.py
class Category(models.Model):
name = models.CharField(max_length=125)
image = models.ImageField(upload_to=upload_location)
class Product(models.Model):
name = models.CharField(max_length=125)
category = models.ForeignKey(Category, null=True, on_delete=models.DO_NOTHING)
image = models.ImageField(upload_to=upload_lokasi)
slug = models.SlugField(blank=True, editable=False)
active = models.BooleanField(default=True)
This my template for ProductCategoryListView
<div class="...">
<div class="...">
<a href="{% url 'products:allproducts' 1%}"...>
All Products
</a>
{% for cat in catlist %}
<a href="{% url 'products:product_category' cat.name 1 %}"...>
{{ cat.name }}
</a>
{% endfor %}
<!-- Product List -->
<div class="row isotope-grid">
{% for prods in product_list %}
<div class="...">
<div class="...">
<div class="...">
<img src="{{ prods.image.url }}" alt="IMG-PRODUCT">
<a href="../{{ prods.slug }}" class="...">
Quick View
</a>
</div>
<div class="...">
<div class="...">
<a href="product-detail.html" class="...">
{{ prods.name }}
</a>
</div>
</div>
</div>
</div>
{% endfor %}
</div>
<!-- Pagination -->
<div class="row">
<div class="col-md-8">
{% if is_paginated %}
<nav aria-label="productPage">
<ul class="pagination">
{% if page_obj.has_previous %}
<li class="page-item">
<a class="page-link" href="{% url 'products:product_category' category page_obj.previous_page_number %}">Previous</a>
</li>
{% else %}
<li class="page-item disabled">
<a class="page-link" href="#" tabindex="-1" aria-disabled="true">Previous</a>
</li>
{% endif %}
{% for page in paginator.page_range %}
{% if page is page_obj.number %}
<li class="page-item active" aria-current="page">
<span class="page-link" href="#">{{page}}<span class="sr-only">(current)</span></span>
</li>
{% else %}
<li class="page-item">
<a class="page-link" href="{% url 'products:product_category' category page %}">{{page}}</a>
</li>
{% endif %}
{% endfor %}
{% if page_obj.has_next %}
<li class="page-item">
<a class="page-link" href="{% url 'products:product_category' category page_obj.next_page_number %}">Next</a>
</li>
{% else %}
<li class="page-item disabled">
<a class="page-link" href="#" tabindex="-1" aria-disabled="true">Next</a>
</li>
{% endif %}
</ul>
</nav>
{% endif %}
</div>
</div>
I guess error comes from here cause logic use different models.
def get_context_data(self, *args, **kwargs):
context = super(ProductCategoryListView, self).get_context_data(*args,**kwargs)
context ['catlist'] = Category.objects.all()
return context
my template
{% for cat in catlist %}
<a href="{% url 'products:product_category' cat.name 1 %}"...>
{{ cat.name }}
</a>
{% endfor %}
I use Category.objects.all() because i don't know how to List
Category from product, just for a name of category can be access.
I hope you guys understand what i asking about.
Sorry for my bad english.

Get Django search query right

Im currently facing a problem since a couple of days for now. I simply want to implement a search view into my Django app. But when i try to search something on my App i get the following error:
init() takes 1 positional argument but 2 were given__init__() takes
In the end i want that my Query is a combination of category and searchword. So that the user can filter specific categories (Just like Amazon.com searchfield) e.g.: http://127.0.0.1:8000/search/?category=1&q=hallo
base.html
...
<div class="globalsearch">
<form id="searchform" action="{% url 'search' %}" method="get" accept-charset="utf-8">
<label for="{{ categorysearch_form.category.id_for_label }}">In category: </label> {{ categorysearch_form.category }}
<input class="searchfield" id="searchbox" name="q" type="text" placeholder="Search for ...">
<button class="searchbutton" type="submit">
<i class="fa fa-search"></i>
</button>
</form>
</div>
</div>
...
categorysearch_form is a dropdown selector that gets his ID from the Database.
views.py
...
from django.contrib.postgres.search import SearchQuery, SearchRank, SearchVector
from django.views.generic import ListView
class globalsearch(ListView):
"""
Display a Post List page filtered by the search query.
"""
model = Post
paginate_by = 10
def get_queryset(self):
qs = Post.objects.published()
keywords = self.request.GET.get('q')
if keywords:
query = SearchQuery(keywords)
title_vector = SearchVector('title', weight='A')
content_vector = SearchVector('content', weight='B')
tag_vector = SearchVector('tag', weight='C')
vectors = title_vector + content_vector + tag_vector
qs = qs.annotate(search=vectors).filter(search=query)
qs = qs.annotate(rank=SearchRank(vectors, query)).order_by('-rank')
return qs
...
urls.py
...
url(r'^search/$', views.globalsearch.as_view(), name='search'),
...
Search.html results are getting displayd here:
{% extends 'quickblog/base.html' %}
{% block content %}
{% for post in object_list %}
<div class="post">
<h1><u>{{ post.title }}</u></h1>
<p>{{ post.content|linebreaksbr }}</p>
<div class="date">
<a>Published by: {{ post.author }}</a><br>
<a>Published at: {{ post.published_date }}</a><br>
<a>Category: {{ post.category }}</a><br>
<a>Tag(s): {{ post.tag }}</a>
</div>
</div>
{% endfor %}
{% if is_paginated %}
<ul class="pagination">
{% if page_obj.has_previous %}
<li>«</li>
{% else %}
<li class="disabled"><span>«</span></li>
{% endif %}
{% for i in paginator.page_range %}
{% if page_obj.number == i %}
<li class="active"><span>{{ i }} <span class="sr-only">(current)</span></span></li>
{% else %}
<li>{{ i }}</li>
{% endif %}
{% endfor %}
{% if page_obj.has_next %}
<li>»</li>
{% else %}
<li class="disabled"><span>»</span></li>
{% endif %}
</ul>
{% endif %}
{% endblock %}
Project: https://github.com/rsmvdl/quickblog
Since globalsearch is class based view it should be globalsearch.as_view() in your urls:
url(r'^search/$', views.globalsearch.as_view(), name='search'),

NoReverseMatch at / django python:Reverse for '*' not found. tried

Reverse for 'details' with arguments '('',)' not found. 1 pattern(s) tried: ['details/(?P[.\-\w]+)$']
I am getting this error when I open the home page. All other pages seem to work.
urls.py
app_name = 'main'
urlpatterns = [
url(r'^$', views.home, name='home'),
url(r'ask-question/$', views.question, name='ask-question'),
url(r'^details/(?P<slug>[.\-\w]+)$', views.details, name='details'),
]
views.py for the home page
def home(request):
questions = Question.objects.all().order_by("-date")
numbers = Question.objects.all().count()
numbers2 = Answer.objects.all().count()
total_users = User.objects.all().count()
# counting answers on specific questions
results = Question.objects.annotate(num_answers=Count('answer')).order_by("-date")
# PAGINATION ===============================
page = request.GET.get('page', 1)
paginator = Paginator(results,10)
try:
results = paginator.page(page)
except PageNotAnInteger:
results = paginator.page(1)
except EmptyPage:
results = paginator.page(paginator.num_pages)
# end of counting
empty = []
for a in Answer.objects.all():
idd = a.id
question_id = (a.question_id)
empty.append(str(question_id))
repeatition = Counter(empty)
# i = 0
# trend_list = []
# for x in range(len(repeatition)):
# new = repeatition.most_common()[i][0]
# trend_list.append(new)
# i += 1
# if len(trend_list) != 0:
# trend = Question.objects.get(id=trend_list[0])
# else:
# trend = 'No Trending Category'
# getting the answers to all questions in the front page
# search the questions ============
query= request.GET.get("q")
if query:
short_list = Question.objects.all()
questions = short_list.filter(title__icontains=query)
resulted = questions.annotate(num_answers=Count('answer'))
counted = questions.count()
context1 = {
'questions': questions,
'query': query,
'counted': counted,
'resulted': resulted,
}
return render(request, 'main/search.html',context1)
context = {
'questions': questions,
'numbers': numbers,
'numbers2': numbers2,
'total_users': total_users,
# 'trend': trend,
'results': results,
}
return render(request, 'main/index.html', context)
index.html
{% extends 'main/base.html' %} {% block content %}
<div class="container">
{% for message in messages %}
<div class="alert alert-{{ message.tags }} alert-dismissible" role="alert">
<button type="button" class="close" data-dismiss="alert" aria-label="Close">
<span aria-hidden="true">×</span>
</button> {{ message }}
</div>
{% endfor %}
</div>
<!-- end of the message container -->
<!-- start of the actual questions -->
<div class="container-fluid">
<h1 class="text-left" id="brand"> Recently Added Questions</h1>
<div class="row">
<div class="col-md-8">
<div id="qtns">
{% for q in results %}
<a href="{% url 'main:details' q.slug %}" id="questions">
<h4 id="titleq">{{ q.title }}</h4>
</a>
<a href="{% url 'main:filter' q.category %}">
<p class="badge badge-info">{{ q.category }}</p>
</a>
<p id="titleq">{{ q.date |timesince }} ago. {{ q.user }}</p>
<div class="text-right">
<p>Answers: {{q.num_answers}}</p>
</div>
<hr> {% endfor %}
</div>
</div>
<div class="col-md-3">
<div id="qtns1">
<br> {% if not user.is_authenticated %}
Ask Question<br><br> {% else %}
Ask Quesiton<br><br> {% endif %}
<div class="qtns2">
<h1 id="titleq">Statistics</h1>
<p>Questions asked: {{numbers}} </p>
<p>Answers: {{ numbers2 }}</p>
<p>Total Users: {{ total_users }}</p>
</div> <br>
<div class="qtns2">
Most answered:
<a href="{% url 'main:details' trend.slug %}" style="text-decoration:none;">
<p>{{ trend }}</a> - <i>{{ trend.user }}</i></p>
<p><i>Posted On: </i>{{ trend.date}}</p>
</div>
<br>
<div class="qtns2">
Most Questions By:
<a href="{% url 'accounts:profile' trend.user %}" style="text-decoration:none;">
<p>{{ trend.user }}</p>
</a>
</div>
</div>
</div>
</div>
<br>
<!-- pagination for the limited display of questions -->
<nav aria-label='pagination'>
{% if results.has_other_pages %}
<ul class="pagination">
{% if results.has_previous %}
<li class="page-item"><a class="page-link" href="?page={{ results.previous_page_number }}">«</a></li>
{% else %}
<li class="page-item disabled"><span class="page-link">«</span></li>
{% endif %} {% for i in results.paginator.page_range %} {% if results.number == i %}
<li class=" page-item active"><span class="page-link">{{ i }} <span class="sr-only">(current)</span></span>
</li>
{% else %}
<li class="page-item"><a class="page-link" href="?page={{ i }}">{{ i }}</a></li>
{% endif %} {% endfor %} {% if questions.has_next %}
<li class="page-item"><a class="page-link" href="?page={{ results.next_page_number }}">»</a></li>
{% else %}
<li class=" page-item disabled"><span class="page-link">»</span></li>
{% endif %}
</ul>
</nav>
</div>
{% endif %} {% endblock %}
All other pages are working, but the home page is returning reverse for 'details' ..... not found. What seems to be the problem, I can't figure it out. Can anyone please look at my code and tell me my mistake. Thanks in advance.
Every time you encounter an error you need to have a debugging strategy. In NoReverseMatch case the strategy would be:
Find all the cases where reverse for 'details' is called.
Check that cases validate by asking yourself three questions:
Is object in the context?
Is field (or key/value) you're trying to get part of this object?
Is value as expected?
All answers must be yes. If the answer is no, fix it.
Cases where reverse for 'details' is called are:
<a href="{% url 'main:details' q.slug %}" id="questions">
<a href="{% url 'main:details' trend.slug %}" style="text-decoration:none;">
Are q and trend in the context? q is as part of results object, that is a yes and trend isn't in the context, because you commented that part of the code in your views. trend.slug thus returns nothing and reverse for 'details' with nothing is not found, because slug is expected.
If you fix this, this error should go away.