I am having trouble understanding code of website in tutorial. what i understood is that urls.py take a argument as product_slug which is used to get object in my show_product view and another argument is used in as template_name
but what is argument 'catalog_product' doing it is defined in my model.when I remove 'catalog_product' I get error as:
no reverse match at /category/guitar
please explain how does this argument get_absolute_url work and how and where I can use it?
model.py is:
def get_absolute_url(self):
return reverse('catalog_product', (), { 'product_slug': self.slug })
I am having uurls.py as:
url(r'^product/(?P<product_slug>[-\w]+)/$',show_product, {'template_name':'catalog/product.html'}, 'catalog_product')
and views.py:
def show_product(request, product_slug, template_name="catalog/product.html"):
p = get_object_or_404(Product, slug=product_slug)
categories = p.categories.filter(is_active=True)
page_title = p.name
meta_keywords = p.meta_keywords
meta_description = p.meta_description
return render(request, template_name, locals())
template product.html :-
% extends "catalog.html" %}
{% block content %}
<div class="product_image" >
{% load static %}
<img src="{% static 'images/products/main/{{ p.image}}' %}" alt="{{ p.name }}" />
</div>
<h1>{{ p.name }}</h1>
Brand: <em>{{ p.brand }}</em>
<br /><br />
SKU: {{ p.sku }}
<br />
In categor{{ categories.count|pluralize:"y,ies" }}:
{% for c in categories %}
{{ c.name }}
{% if not forloop.last %}, {% endif %}
{% endfor %}
<br /><br />
{% if p.sale_price %}
Was: <del>$ {{ p.old_price }}</del>
<br />
Now: $ {{ p.price }}
{% else %}
Price: $ {{ p.price }}
{% endif %}
<br /><br />
[add to cart button]
<br /><br />
<div class="cb"><br /><br /></div>
<h3>Product Description</h3>
{{ p.description }}
{% endblock %}
Related
urls.py
urlpatterns = [
path('',CourseList.as_view(),name='course_list'),
path('create/',CourseCreate.as_view(),name='course_create'),
path('<int:cid>/',CourseView.as_view(),name='course_view'),
]
views.py
COURSE_PERM_GUEST = 0
COURSE_PERM_STUDENT = 1
COURSE_PERM_TEACHER = 2
COURSE_PERM_MEMBER = 3
class CourseAccessMixin(AccessMixin):
permission = None
extra_context = {}
def dispatch(self,request,*args,**kwargs):
if not request.user.is_authenticated:
return super().handle_no_permission()
self.course = get_object_or_404(Course,id=kwargs['cid'])
user_perm = COURSE_PERM_GUEST
if self.course.teacher == request.user:
user_perm = COURSE_PERM_TEACHER
elif self.course.enroll_set.filter(student=request.user).exists():
user_perm = COURSE_PERM_STUDENT
if not request.user.is_superuser and self.permission is not None:
is_accessible = False
if self.permission == COURSE_PERM_GUEST and \
user_perm == COURSE_PERM_GUEST:
is_accessible = True
elif (self.permission & user_perm) != 0:
is_accessible = True
if not is_accessible:
return super().handle_no_permission()
self.extra_context.update({'course':self.course})
return super().dispatch(request,*args,**kwargs)
class CourseView(CourseAccessMixin,DetailView):
extra_context = {'title':'檢視課程'}
model = Course
pk_url_kwarg = 'cid'
models.py
class Course(models.Model):
name = models.CharField('課程名稱',max_length=50)
enroll_password = models.CharField('選課密碼',max_length=50)
teacher = models.ForeignKey(User,models.CASCADE)
def __str__(self):
return '{}#{} ({})'.format(
self.id,
self.name,
self.teacher.first_name)
course_list.html
{% extends "base.html" %}
{% load user_tags %}
{% block content %}
{% if user|is_teacher %}
<div class="mb-2">
建立課程
</div>
{% endif %}
<div id="course_list">
{% for course in course_list %}
<div class="list-group">
<div class="list-group-item d-flex">
{% if user.is_authenticated %}
{{ course.name }}
{% else %}
{{ course.name }}
{% endif %}
<small class="ml-auto">{{ course.teacher.first_name }} 老師</small>
</div>
</div>
{% endfor %}
</div>
{% include 'pagination.html' %}
{% endblock %}
course_detail.html
{% extends 'base.html' %}
{% load user_tags %}
{% block content %}
<div id="course_view" class="card">
{% with b1 = "btn btn-sm btn-primary" b2 = "btn btn-sm btn-secondary" %}
<div class="card-header d-flex">
<div>
{{ course.name }}
<small>{{ course.teacher.first_name }} 老師</small>
</div>
{% if user.is_superuser or course.teacher == user %}
<div class="ml-auto">
<span class="badge badge-light">
選課密碼: {{ course.enroll_password }}
</span>
<a href="{% url 'course_edit' course.id %}" class="{{ b1 }}">
<i class="fas fa-edit"></i>編輯
</a>
</div>
{% endif %}
</div>
<div class="card-body">
{% block course_detail_body %}
<div id="student_op" class="btn-group">
{% if not course|has_member:user and not user.is_superuser %}
<a href="{% url 'course_enroll' course.id %}" class="{{ b1 }}">
<i class="fas fa-id-badge"></i>選修
</a>
{% else %}
<a href="{% url 'course_users' course.id %}" class="{{ b1 }}">
<i class="fas fa-users"></i>修課名單
</a>
{% if course|has_student:user %}
<a href="{% url 'course_seat' course.id %}" class="{{ b1 }}">
<i class="fas fa-chair"></i>更改座號
</a>
{% endif %}
{% endif %}
</div>
{% endblock %}
</div>
{% endwith %}
</div>
{% endblock %}
Error:
ValueError at /course/1/
The view course.views.CourseView didn't return an HttpResponse object. It returned None instead.
I had a view CourseView and when I try to access the detail of the corresponding course by clicking the hyperlink {{ course.name }} from the template course_list.html, I received the error message showing that it didn't return an HttpResponse object. I do not know what is missing in order to have the details accessible even though I had set the pk_url_kwarg?
You forget to add return super().dispatch(request,*args,**kwargs) and the end of dispatch function (you add it, only in if condition)
change this
self.extra_context.update({'course':self.course})
return super().dispatch(request,*args,**kwargs)
To this:
self.extra_context.update({'course':self.course})
return super().dispatch(request,*args,**kwargs)
return super().dispatch(request,*args,**kwargs)
I have a blog-type application where the homepage displays posts with some information and with an Add Comment form. The form is intended to write to my Comments() model in models.py for that specific post.
The Problem: is that because I am looping through the posts in home.html, the post.id is not available to the home function in routes.py. So, when the form is validated, the comment is applied to all the posts, not just the one in which the comment is added.
The question: how can I get the relevant post.id in the home function from the Jinja forloop and have the comment be applied to the specific post, not just all the posts on the homepage?? I'm not seeing my logic/syntax error - what am I missing here? Thanks
The resulting error: AttributeError: 'function' object has no attribute 'id'
which of course makes sense because the application has no clue what post we are referencing in the Jinja2 forloop in home.html.
here is the Comments db model in models.py:
class Comments(db.Model):
comment_id = db.Column(db.Integer, primary_key=True)
user_id = db.Column(db.Integer, nullable=True, primary_key=False)
post_id = db.Column(db.Integer, nullable=True, primary_key=False)
comment = db.Column(db.String(2000), unique=False, nullable=True)
comment_date = db.Column(db.DateTime, nullable=False, default=datetime.utcnow)
class Meta:
database = db
def fetch_post_comments(self, post_id):
comments = Comments.query.filter(Comments.post_id==post_id)
return comments
def fetch_user(self, user_id):
user = User.query.filter(User.id==user_id).first_or_404()
return user.username
def __repr__(self):
return f"Comments ('{self.user_id}', '{self.post_id}', '{self.comment}', '{self.comment_date}')"
And here is my home function in routes.py:
#app.route("/")
#app.route("/home", methods=['GET', 'POST'])
#login_required
def home():
page = request.args.get('page', 1, type=int)
posts = Post.query.order_by(Post.date_posted.desc()).paginate(page=page, per_page=5)
comment_form = CommentForm()
def add_comment(post_id):
if comment_form.validate_on_submit():
new_comment = Comments(user_id=current_user.id,
post_id=post_id,
comment=comment_form.comment_string.data)
db.session.add(new_comment)
db.session.commit()
flash('HOT TAKE! Posted your comment.', 'success')
# return redirect(url_for('post', post_id=post.id))
def get_upvote_count(post_id):
count = Vote.query.filter(Vote.post_id==post_id).count()
return count
def get_flag_count(post_id):
count = Flag.query.filter(Flag.post_id == post_id).count()
return count
def get_comment_count(post_id):
count = Comments.query.filter(Comments.post_id == post_id).count()
return count
def get_favorite_count(post_id):
count = Favorites.query.filter(Favorites.post_id == post_id).count()
return count
def get_youtube_id_from_url(url):
video_id = url.split('v=')[1]
if '&' in video_id:
video_id = video_id.split('&')[0]
base_url = "https://www.youtube.com/embed/"
return base_url + video_id
def get_spotify_embed_url(url):
track_or_playlist = url.split('https://open.spotify.com/')[1].split('/')[0]
base_url = f"https://open.spotify.com/embed/{track_or_playlist}/"
spotify_id = url.split('https://open.spotify.com/')[1].split('/')[1]
embed_url = base_url + spotify_id
return embed_url
return base_url + video_id
return render_template('home.html',
posts=posts,
get_upvote_count=get_upvote_count,
get_comment_count=get_comment_count,
get_flag_count=get_flag_count,
get_favorite_count=get_favorite_count,
comment_form=comment_form,
add_comment=add_comment,
get_youtube_id_from_url=get_youtube_id_from_url,
get_spotify_embed_url=get_spotify_embed_url)
And here is my home.html
{% extends "layout.html" %}
{% block content %}
{% for post in posts.items %}
<article class="media content-section">
<img class="rounded-circle article-img" src="{{ url_for('static', filename='profile_pics/' + post.author.image_file) }}">
<div class="media-body">
<div class="article-metadata">
<div align="left">
<a class="mr-2 text-secondary" href="{{ url_for('user_posts', username=post.author.username) }}">{{ post.author.username }}</a>
</div>
<div align="left">
<small class="text-muted">Posted on: {{ post.date_posted.strftime('%Y-%m-%d') }}</small>
</div>
<div align="right">
<a class="mr-2 text-secondary" href="{{ url_for('flag', post_id=post.id, user_id=current_user.id) }}">Flag Post</a>
</div>
<div align="right">
<a class="mr-2 text-secondary" href="{{ url_for('add_favorite', post_id=post.id, user_id=current_user.id) }}">Favorite Post ({{ get_favorite_count(post.id) }})</a>
</div>
<div align="right">
<a class="mr-2 text-secondary" href="{{ url_for('post', post_id=post.id) }}">Comments ({{ get_comment_count(post.id) }})</a>
</div>
</div>
<h3><a class="article-title" href="{{ url_for('post', post_id=post.id) }}">{{ post.title }}</a></h3>
<p class="article-content justify-content-center">{{ post.content }}</p>
<br>
{% for url in post.urls.split('||') %}
{% if 'youtube.com' in url %}
<div class="embed-responsive embed-responsive-16by9">
<iframe class="embed-responsive-item"
src="{{ get_youtube_id_from_url(url) }}" allowfullscreen="" frameborder="0">
</iframe>
</div>
Link
{% elif 'soundcloud.com' in url %}
<div class="embed-responsive embed-responsive-16by9">
<iframe class="embed-responsive-item" scrolling="no" frameborder="no"
src="{{ 'https://w.soundcloud.com/player/?url=' + url }}">
</iframe>
</div>
Link
{% elif 'spotify.com' in url %}
<div class="embed-responsive embed-responsive-16by9">
<iframe class="embed-responsive-item"
src="{{ get_spotify_embed_url(url) }}" allowfullscreen allow="encrypted-media">
</iframe>
</div>
Link
{% elif 'vimeo.com' in url %}
<div class="embed-responsive embed-responsive-16by9">
<iframe class="embed-responsive-item" scrolling="no" frameborder="no"
src="{{ 'https://player.vimeo.com/video/' + url.split('https://vimeo.com/')[1] }}">
</iframe>
</div>
Link
{% elif 'tumblr.com' in url %}
<div class="embed-responsive embed-responsive-16by9">
<iframe class="embed-responsive-item"
src="{{ url }}" frameborder="0">
</iframe>
</div>
Link
{% else %}
Link
<br>
{% endif %}
{% endfor %}
<br>
<br>
<p class="text-muted"><strong>Tags:</strong></p>
{% for tag in post.tags.replace(' ', ' ').strip(',').split(' ') %}
<a class="btn btn-light" href="{{url_for('tag_posts', tag=tag)}}">{{tag.strip('#').strip(' ').lower() }}</a>
{% endfor %}
<br>
<form method="POST" action="" enctype="multipart/form-data">
{{ comment_form.hidden_tag() }}
<fieldset class="form-group">
<br>
<br>
<p class="text-muted"><strong>Add a comment:</strong></p>
<div class="form-group">
{% if comment_form.comment_string.errors %}
{{ comment_form.comment_string(class="form-control form-control-lg is-invalid") }}
<div class="invalid-feedback">
{% for error in comment_form.comment_string.errors %}
<span>{{ error }}</span>
{% endfor %}
</div>
{% else %}
{{ comment_form.comment_string(class="form-control form-control-lg") }}
<!-- {{ add_comment(post_id=post.id) }}-->
{% endif %}
</div>
</fieldset>
<div class="form-group">
{{ comment_form.submit(class="btn btn-secondary") }}
</div>
</form>
<br>
<p class="text-muted mt-4"><strong>Street Cred: </strong>{{ get_upvote_count(post.id) }}</p>
<a class="btn btn-secondary mb-4" href="{{url_for('upvote', user_id=post.author.id, post_id=post.id)}}">Upvote</a>
</div>
</article>
{% endfor %}
{% for page_num in posts.iter_pages(left_edge=1, right_edge=1, left_current=1, right_current=2) %}
{% if page_num %}
{% if posts.page == page_num %}
<a class="btn btn-secondary mb-4" href="{{ url_for('home', page=page_num) }}">{{ page_num }}</a>
{% else %}
<a class="btn btn-outline-info mb-4" href="{{ url_for('home', page=page_num) }}">{{ page_num }}</a>
{% endif %}
{% else %}
...
{% endif %}
{% endfor %}
{% endblock content %}
A couple of options:
Add the post.id to the url as a parameter or arg, here's the arg method:
Add the url to the form and set the post.id as the arg:
<form method="POST" action="{{url_for('home', post_id=post.id)}}" enctype="multipart/form-data">
And in the route:
new_comment = Comments(user_id=current_user.id,
post_id=request.args.get('post_id', type=int),
comment=comment_form.comment_string.data)
OR
Add a hidden field to your form, and set the value of that to be the post.id:
Add a hidden field onto your form:
post_id = HiddenField()
You'll need to replace the CSRF render (hidden_tag()) to prevent auto rendering of the post_id field:
{{ comment_form.csrf_token }}
Next, set the value of your hidden field data (credit to this answer for this function):
{% set p = comment_form.post_id.process_data(post.id) %}
{{ comment_form.post_id() }}
and finally, in the route, (remove the add_comment declaration):
def home():
# Omitted ...
if comment_form.validate_on_submit():
new_comment = Comments(user_id=current_user.id,
post_id=comment_form.post_id.data,
comment=comment_form.comment_string.data)
db.session.add(new_comment)
# etc...
Hope this helps, note it's not tested
i want to display an image if nothing could be found trough my searchg function.
I setup 2 serach functions. one for elasticsearch and the other one for a local search query view, anyways the one for elastic does not seems to work or at least it does not display the "not found" image if the object_list is empty, any idea?
elastic_search_function:
def globalsearch_elastic(request):
qs = request.GET.get('qs')
page = request.GET.get('page')
if qs:
qs = PostDocument.search().query("multi_match", query=qs, fields=["title", "content", "tag"])
qs = qs.to_queryset()
else:
qs = ''
paginator = Paginator(qs, 10) # Show 10 results per page
try:
qs = paginator.page(page)
except PageNotAnInteger:
qs = paginator.page(1)
except EmptyPage:
qs = paginator.page(paginator.num_pages)
return render(request, 'myproject/search/search_results_elastic.html', {'object_list':qs})
template.html
<body>
<h1 class="center">Search results <a class="fa fa-search"></a></h1>
<hr class="hr-style">
{% if object_list.count == 0 %}
<div class="search_not_found">
<img src={% static "/gfx/sys/not_found.png" %}>
<h2>Nothing found here ...</h2>
</div>
{% else %}
{% for post in object_list %}
<div class="post">
<h3><u>{{ post.title }}</u></h3>
<p>{{ post.content|safe|slice:":800"|linebreaksbr}}
{% if post.content|length > 300 %}
... more
{% endif %}</p>
<div class="date">
<a>Published by: <a href="{% url 'profile' pk=user.pk %}" >{{ post.author }}</a></a><br>
<a>Published at: {{ post.published_date }}</a><br>
<a>Category: {{ post.category }}</a><br>
<a>Tag(s): {{ post.tag }}</a><br>
<a>Comment(s): {{ post.comment_set.count }}</a>
</div>
</div>
{% endfor %}
{% endif %}
How about like this using empty:
{% for post in object_list %}
<div class="post">
<h3><u>{{ post.title }}</u></h3>
<p>{{ post.content|safe|slice:":800"|linebreaksbr}}
{% if post.content|length > 300 %}
... more
{% endif %}</p>
<div class="date">
<a>Published by: <a href="{% url 'profile' pk=user.pk %}" >{{ post.author }}</a></a><br>
<a>Published at: {{ post.published_date }}</a><br>
<a>Category: {{ post.category }}</a><br>
<a>Tag(s): {{ post.tag }}</a><br>
<a>Comment(s): {{ post.comment_set.count }}</a>
</div>
</div>
{% empty %}
<div class="search_not_found">
<img src={% static "/gfx/sys/not_found.png" %}>
<h2>Nothing found here ...</h2>
</div>
{% endfor %}
I've an object containing an attribute defined by a series of choices - here's it's class definition:
class StashURLJobRequest(models.Model):
STATUS_CHOICES = ((0,"Requested"),(1,"Done"),(2,"Failed"))
url = models.URLField()
created = models.DateTimeField(auto_now_add = True, auto_now=False)
processed = models.DateTimeField(auto_now_add = False, auto_now = True)
status = models.IntegerField(choices=(STATUS_CHOICES))
requestBy = models.CharField(max_length=32)
def __unicode__(self):
return smart_unicode(self.url + str(self.created))
def status_display(self):
status_dict = dict(self.STATUS_CHOICES)
return status_dict[self.status]
I get a list of these and pass through into a template, intending to render each one as an individual row, again, here's the template code:
{% for job_instance in jobs %}
<div class="width100pc">
<div class="width10pc"> <img src="{% static 'img/empty.png' %}" /> </div>
<div class="width80pc">
<div class="width70pc textleft sans textsmall "> {{ job_instance.url }} </div>
<div class="width15pc textcentre sans texttiny "> {{ job_instance.processed }} </div>
<div class="width5pc textcentre sans texttiny {% ifequal job_instance.status_display 'Done' %} status_green {% endifequal %}
{% ifequal job_instance.status_display 'Requested' %} status_amber {% endifequal %}
{% ifequal job_instance.status_display 'Failed' %} status_red {% endifequal %}"> {{ job_instance.status_display }} </div>
<div class="width10pc textcentre sans texttiny"> {{ job_instance.requestBy }} </div>
</div>
<div class="width10pc"> <img src="{% static 'img/empty.png' %}" /> </div>
</div>
{% endfor %}
In particular, note the section:
{% ifequal job_instance.status_display 'Done' %} status_green {% endifequal %}
{% ifequal job_instance.status_display 'Requested' %} status_amber {% endifequal %}
{% ifequal job_instance.status_display 'Failed' %} status_red {% endifequal %}
Each of {status_green, status_amber and status_red} refer to a different css class, and allows me to render the status in an appropriate colour.
This seems a little unwieldy, and I don't want to code the css-class into the model, or the view (preferring to leave format and display to the template/html definitions) - so the question is, is there a way to do this that's more "pythonic" - ideally, I'd like to use something like:
{{ class_dict = {'Done' : 'status_green', 'Requested' : 'status_amber', 'Failed' : 'status_red' } }}
< ... some code ... >
{{ class_dict[job_instance.status_display] }}
(dodgy curly-braces aside!)
Add a helper function to the object, so that you don't need any logic in the template?
Add to StashURLJobRequest
def status_display_colour(self):
return {
"Done":"status_green",
"Requested":"status_amber",
"Failed":"status_red"
}[ self.status_display() ]
And the template becomes <div class="width5pc textcentre sans texttiny {{ job_instance.status_display_colour }} ...
Another way would be class="... my-class-{{job_instance.status_display}}" with my-class-Done, my-class-Requested, my-class-Failed appropriately defined in your css. It's inferior because it depends implicitly on status_display remaining a single word with no spaces or other special characters.
I'm trying to make a search form for Django.
Its a typical search form and then returns a table of matches. I wish to paginate the tables returned.
The problem lies in the Previous and Next buttons.
The links for the return query goes to /records/search/?query=a (search sample is a)
The page outputs the table and its previous and next links. However the links redirect to /records/search/?page=2 and the page displays a blank table.
Any help on which links I should pass for Prev/Next?
search.html:
{% extends 'blank.html' %}
{% block content %}
<div class="row">
<form id="search-form" method="get" action=".">
{{ form.as_p }}
<input type="submit" value="Search" />
</form>
</div>
<br><br>
//display table code//
{% if is_paginated %}
<div class="pagination">
<span class="step-links">
{% if agent_list.has_previous %}
forrige
{% endif %}
<span class="current">
Page {{ agent_list.number }} of {{ agent_list.paginator.num_pages }}.
</span>
{% if agent_list.has_next %}
Next
{% endif %}
</span>
</div>
{% endif %}
{% endblock %}
and the search view:
def search_page(request):
form = SearchForm()
agents = []
show_results=False
if request.GET.has_key('query'):
show_results=True
query=request.GET['query'].strip()
if query:
form=SearchForm({'query': query})
agents = \
Agent.objects.filter(Q(name__icontains=query))
paginator = Paginator(agents, 10)
page = request.GET.get('page')
try:
agents = paginator.page(page)
except PageNotAnInteger:
agents = paginator.page(1)
except EmptyPage:
agents = paginator.page(paginator.num_pages)
variables = RequestContext(request,
{ 'form': form,
'agent_list': agents,
'show_results': show_results,
'is_paginated': True,
}
)
return render_to_response('search.html', variables)
I've seen the similar questions but I can't understand/make them work. Any help?
Edit:
For a quickfix (haven't really looked at the cons)
I added a variable in my view:
variables = RequestContext(request,
{ 'form': form,
'agent_list': agents,
'show_results': show_results,
'is_paginated': True,
**'query': query,**
}
)
Where query without the quotes is the recieved query variable.
Then simply change the URL to:
Previous
If you have a better way of answering the question, please do or appending a URL to your currently opened URL.
I would recommend putting the solution in a template tag like so:
myapp/templatetags/mytemplatetags.py:
from django import template
register = template.Library()
#register.simple_tag
def url_replace(request, field, value):
d = request.GET.copy()
d[field] = value
return d.urlencode()
#register.simple_tag
def url_delete(request, field):
d = request.GET.copy()
del d[field]
return d.urlencode()
Then from templates do:
{% load mytemplatetags %}
...
previous
you can use {{ request.get_full_path }} this tag to get current url.
Next
this worked for me
The below works before and after a search form has been submitted:
Views.py
class PostListView(ListView):
model = Post #.objects.select_related().all()
template_name = 'erf24/home.html' # <app>/<model>_<viewtype>.html
context_object_name = 'posts' # default >> erf24/post_list.html
ordering = ['date_posted']
paginate_by = 3
def is_valid_queryparam(param):
return param != '' and param is not None
def invalid_queryparam(param):
return param == '' and param is None
class SearchView(ListView):
model = Post #.objects.select_related().all()
template_name = 'erf24/home.html' # <app>/<model>_<viewtype>.html
context_object_name = 'posts' # default >> erf24/post_list.html
ordering = ['date_posted']
paginate_by = 3
def get_queryset(self): # new
key = self.request.GET.get('key')
minp = self.request.GET.get('min')
maxp = self.request.GET.get('max')
if is_valid_queryparam(key):
obj = Post.objects.filter(Q(content__icontains=key) | Q(location__icontains=key)).distinct().order_by('date_posted')
if is_valid_queryparam(minp):
obj = Post.objects.filter(Q(price__gte=minp)).distinct().order_by('date_posted')
if is_valid_queryparam(maxp):
obj = Post.objects.filter(Q(price__lte=maxp)).distinct().order_by('date_posted')
if is_valid_queryparam(minp) & is_valid_queryparam(maxp):
obj = Post.objects.filter(Q(price__gte=minp) & Q(price__lte=maxp)).distinct().order_by('date_posted')
if is_valid_queryparam(key) & is_valid_queryparam(minp) & is_valid_queryparam(maxp):
obj = Post.objects.filter(Q(content__icontains=key) | Q(location__icontains=key)).distinct()
obj = obj.filter(Q(price__gte=minp) & Q(price__lte=maxp)).order_by('date_posted')
if invalid_queryparam(key) & invalid_queryparam(minp) & invalid_queryparam(maxp):
obj = Post.objects.all()
return obj
url.py
urlpatterns = [
path('', PostListView.as_view(), name='erf24-home'),
path('search/', SearchView.as_view(), name='erf24-search'),
]
Home.html
<form action="{% url 'erf24-search' %}" method="GET">
<div class="form-group">
<label for="inputAddress">Search keyword</label>
<input type="text" class="form-control" id="key" name="key" placeholder="keyword">
</div>
<label for="">Price</label>
<div class="form-row">
<div class="form-group col-md-6">
<input type="number" class="form-control" id="min" name="min" placeholder="min price">
</div>
<div class="form-group col-md-6">
<input type="number" class="form-control" id="max" name="max" placeholder="max price">
</div>
</div>
<button type="submit" class="btn btn-primary btn-sm mt-1 mb-1">Search</button>
<button type="reset" class="btn btn-secondary btn-sm mt-1 mb-1">Clear</button>
</form>
{% for post in posts %}
<article class="media content-section">
<div class="media-body">
<div class="article-metadata">
<img class="rounded-circle article-img" src="{{ post.author.profile.image.url }}" alt="">
{{ post.author }}
<small class="text-muted">{{ post.date_posted }}</small>
<!-- use |date: "specs" to filter date display -->
</div>
<h2>
{{ post.price }}
</h2>
<p class="article-content">{{ post.content }}</p>
<p class="article-content">{{ post.location }}</p>
<p><a class="like-btn" data-href="{{ post.get_api_like_url }}" href="">{{ post.likes.count }}
{% if user in post.likes.all %} Unlike
{% else %} Like
{% endif %}
</a></p>
</div>
{% for image in post.image_set.all %}
<img class="account-img" src="{{ image.image.url }}" alt="">
{% endfor %}
</article>
{% endfor %}
{% if is_paginated %}
{% if page_obj.has_previous %}
First
Previous
{% endif %}
{% for num in page_obj.paginator.page_range %}
{% if page_obj.number == num %}
{{ num }}
{% elif num > page_obj.number|add:'-3' and num < page_obj.number|add:'3' %}
{{ num }}
{% endif %}
{% endfor %}
{% if page_obj.has_next %}
Next
Last
{% endif %}
{% endif %}
Worked like a charm :) Enjoy!
You can use {{ request.get_full_path }} template tag
Next
you can use this, I use it because I use filters in the url itself, so all the url params are used to build the next or previous url
import re
from django import template
register = template.Library()
PAGE_NUMBER_REGEX = re.compile(r'(page=[0-9]*[\&]*)')
#register.simple_tag
def append_page_param(value,pageNumber=None):
'''
remove the param "page" using regex and add the one in the pageNumber if there is one
'''
value = re.sub(PAGE_NUMBER_REGEX,'',value)
if pageNumber:
if not '?' in value:
value += f'?page={pageNumber}'
elif value[-1] != '&':
value += f'&page={pageNumber}'
else:
value += f'page={pageNumber}'
return value
then, in your pagination nav you can call it like this:
{% append_page_param request.get_full_path page_obj.previous_page_number %}