Django search bar problems - django

I'm trying to implement a search bar to my website, it's not working and I can't seem to figure out why. The search form looks like this:
<form class="navbar-form navbar-left" role="search" method="GET" action="{% url 'search' %}">
<div class="form-group">
<input type="text" class="form-control" name="q" value="{{request.GET.q}}">
</div>
<button type="submit" class="btn">Search</button>
</form>
url.py:
url(r'^search/$', views.SearchView, name='search'),
views.py:
def SearchView(request):
products = Photos.objects.all()
query = request.GET.get("q")
if query:
products = products.filter( Q(category__contains=query) ).distinct()
return render(request, 'urcle/search.html', {'products': products})
else:
return render(request, 'urcle/search.html', {'products': products})
search.html:
{% extends 'urcle/base.html'%}
{%block content%}
{% if products %}
<div id="inner" >
{% for item in products %}
<div id = 'content' align="center" ></div>
<div class="col-sm-4 col-lg-2" style="width:30%" >
<div class="thumbnail" align="left" >
<a href="{{item.name}}">
<img src="http://ec2-54-194-123-114.eu-west-1.compute.amazonaws.com/images/{{ item.name }}.jpg" class="img-responsive">
</a>
<div class="caption" >
{{item.title}} </li>
<br/>
</div>
</div>
</div>
{% cycle '' '' '' '' '' '<div class="clearfix visible-lg"> </div>' %}
{% endfor %}
</div>
{% else %}
<h1>nothing to see here!!!</h1>
{% endif %}
{%endblock%}
What's really bugging me is that all that gets displayed is the part that gets extended from base.html not even the tag on the else statement gets displayed, anyone know whats up?

The problem was a conflicting URL, which was taking me to the wrong view function

Related

Django search pagination error, page not found error each time I try to move to page 2

I'm popping up with an error on my comic book ecommerce application. It's a Django app. Basically, the search function isn't paginating properly, giving me a page not found error each time I try to move to page 2 and onwards. It works fine in my general products listing area though, where there is no q-based search.
It works fine when I paginate just the products section, adding in...
paginate_by = 6
...into the class ListView section...
...and adding this section into the view.html section...
<div class="pagination">
<span class="step-links">
{% if page_obj.has_previous %}
« first
previous
{% endif %}
<span class="current">
Page {{ page_obj.number }} of {{ page_obj.paginator.num_pages }}.
</span>
{% if page_obj.has_next %}
next
last »
{% endif %}
</span>
</div>
...But, once I try to paginate the search function in the same way, it appears to paginate, but page 2 and onwards just gives me a page not found error...
http://127.0.0.1:8000/search/?page=2
Request Method: GET
Request URL: http://127.0.0.1:8000/search/?page=2
Raised by: search.views.SearchProductView
....I think it has something to do with q, and the view.html section, but I'm not sure.
Any help would be much-appreciated.
Also, here's my view.html:
{% extends "base.html" %}
{% block content %}
<!-- <div class="pagination">
<span class="step-links">
{% if page_obj.has_previous %}
« first
previous
{% endif %}
<span class="current">
Page {{ page_obj.number }} of {{ page_obj.paginator.num_pages }}.
</span>
{% if page_obj.has_next %}
next
last »
{% endif %}
</span>
</div> -->
<!--the heading with the result of the name-->
<div class="row mb-3">
{% if query %}
<div class="col-12">
Results for <b>{{ query }}</b>
<hr/>
</div>
{% else %}
<div class="col-12 col-md-8 mx-auto py-5">
{% include 'search/snippets/search-form.html' %}
</div>
<div class="col-12">
<hr>
</div>
{% endif %}
</div>
<!--create a card/item for each comic-->
<div class="row">
{% for obj in object_list %}
<div class="col">
{% include 'products/snippets/card.html' with instance=obj %}
{% if forloop.counter|divisibleby:3 %}
</div>
</div>
<!--or else if no item just create a blank row and column-->
<div class='row'><div class='col-12'><hr/></div>
{% else %}
</div>
{% endif %}
{% endfor %}
{% endblock %}
And here's a snippet that works within the view.html (search-form.html)
<form method="GET" action='{% url "search:query" %}' class="form my-2 my-lg-0 search-form">
<div class="input-group">
<input class="form-control" type="search" placeholder="Search" name='q' aria-label="Search" value='{{ request.GET.q }}'>
<span class='input-group-btn'>
<button class="btn btn-outline-success" type="submit">Search</button>
</span>
</div>
</form>
As well, here's my view.py backend:
from django.shortcuts import render
from django.views.generic import ListView
from products.models import Product
from django.core.paginator import Paginator
class SearchProductView(ListView):
#PROBLEM WITH PAGINATION IN THE SEarch function and view
#https://stackoverflow.com/questions/48436649/django-pagination-page-not-found?rq=1
#https://www.youtube.com/watch?v=acOktTcTVEQ
#https://www.youtube.com/watch?v=q-Pw7Le30qQ
#https://docs.djangoproject.com/en/3.1/topics/pagination/
#paginate_by = 6
template_name = "search/view.html"
def get_context_data(self, *args, **kwargs):
context = super(SearchProductView, self).get_context_data(*args, **kwargs)
context['query'] = self.request.GET.get('q')
return context
def get_queryset(self, *args, **kwargs):
request = self.request
method_dict = request.GET
query = method_dict.get('q', None) #method_dict['q']
if query is not None:
return Product.objects.search(query).order_by('title')
return Product.objects.filter(featured=True).order_by('title')
'''
__icontains = field contains this
__iexact = field is exactly this
'''
Finally, here are my urls:
from django.conf.urls import url
from .views import (
SearchProductView
)
urlpatterns = [
url(r'^$', SearchProductView.as_view(), name='query'),
]

How to apply if else, if the keyword entered in search bar does not exists in Django

I have created a search button in my blogging application that returns the posts with the similar title.
views.py has
def search(request):
query = request.GET.get('query')
posts = Post.objects.filter(title__icontains=query).order_by('-date_posted')
params = {'posts' : posts}
return render(request, 'blog/search.html' , params)
base.html
<form method="get" class="form-inline my-2my-lg-0 " action="{% url 'search' %}">
<input class="form-control nav-item nav-link text-secondary" type="search" name="query" id="query" placeholder="Search" aria-label="Search">
<button class="btn btn-outline-success nav-item nav-link ml-1">Search</button>
</form>
and search.html
{% for post in posts %}
<!-- starting loop (posts is keyword from view) -->
<article class="media content-section">
<img class="rounded-circle article-img" src="{{post.author.profile.image.url}}">
<div class="media-body">
<div class="article-metadata">
<a class="mr-2" href="{% url 'user-posts' post.author.username %}">{{ post.author }}</a>
<small class="text-muted">{{ post.date_posted | date:"F d, Y" }}</small>
</div>
<h2><a class="article-title" href="{% url 'post-detail' post.id%}">{{ post.title }}</a></h2>
<p class="article-content">{{ post.content|slice:":200" }}</p>
{% if post.content|length > 200 %}
<div class="btn-group-sm">
<a class="btn btn-outline-secondary" href="{% url 'post-detail' post.id%}">Read More →</a>
</div>
{% endif %}
</div>
</article>
{% endfor %}
Now if the the user enters a keyword that is similar to the title of any post then those posts are returned. If no post title matches that keyword a black page is returned. Instead of a blank page I want a paragraph saying that "no post matches the title "
EDIT
How to get something like "no post matches the title {{query}} " instead of "no post matches the title " I get
Wrap your template like this:
{% if posts %}
{% for post in posts %}
...
{% endfor %}
{% else %}
<h2> No post matches the title. </h2>
{% endif %}
Since your posts queryset will be empty it will display the statement in the else block.

How can i render objects in html through django templating via primary key?

i have a problem in searching articles on my home page. the problem is that when i enter a query in a search bar , the error "Reverse for 'blog_detail/' not found. 'blog_detail/' is not a valid view function or pattern name." appears.
code
homepage from where i search a query
<form method="get" action={% url 'search' %} class="">
<!-- <form method="get" action="{% url 'search' %} class="">-->
<input type="text" name="search" class="form-control bg-dark text-white" placeholder="Search Articles" aria-label="Recipient's username" aria-describedby="basic-addon2">
<div class="input-group-append bg-dark">
<button class="btn btn-outline-primary bg-danger text-white" type="submit" >Search </button>
</div>
</form>
search.html
The action of the form sends query to this page
<div class="row">
{% for item in post %}
<div class="card my-3 text-white bg-dark mb-3" style="width: 18rem;">
<img src="/media/{{item.thumbnail}}" class="card-img-top" alt="...">
<div class="card-body">
<h5 class="card-title">{{item.title}}</h5>
<p class="card-text">{{item.intro}}</p>
read more...
</div>
</div>
{% if forloop.counter|divisibleby:5 %}
</div>
{% endif %}
{% endfor %}
</div>
this (href="{% url 'blog_detail/' id=item.post_id %}") is giving an error saying (NoReverseMatch at /search/)
in the urls.py the route for blog_detail is : path("blog_detail/<int:id>", views.blog_detail, name = "blog"),
and for search route is : path("search/", views.search, name="search"),
in the models the primary key is set as post_id : post_id = models.AutoField(primary_key=True)
i hope this information is enough....!
The first parameter of the {% url … %} template tag [Django-doc] is the name of the path. So you should write this as:
href="{% url 'blog' id=item.post_id %}"
since in your urlpatterns, you wrote:
urlpatterns = [
# …
path("blog_detail/<int:id>", views.blog_detail, name="blog"),
# …
]

How load to Django Paginator Page (next/ previous)?

Hy,
i followed a tutorial for a multiple model search and it worked. now i want to paginate the output. But how can i load my paginator page (next/ previous) data into my template? So far if i push next i get an error.
views.py
from django.views.generic import TemplateView, ListView
from django.views.generic import View
from django.shortcuts import render
from django.db.models import Q
from django.core.paginator import Paginator
from itertools import chain
# --- Import Models
from datainput.models import Animal
from datainput.models import Farmer
<....>
class SearchView(ListView):
template_name = 'farmapi/searchview.html'
paginate_by = 2
count = 0
def get_context_data(self, *args, **kwargs):
context = super().get_context_data(*args, **kwargs)
context['count'] = self.count or 0
context['query'] = self.request.GET.get('q')
return context
def get_queryset(self):
request = self.request
query = request.GET.get('q', None)
if query is not None:
farmer_results = Farmer.objects.search(query)
animal_results = Animal.objects.search(query)
# combine querysets
queryset_chain = chain(
farmer_results,
animal_results
)
qs = sorted(queryset_chain,
key=lambda instance: instance.pk,
reverse=True)
self.count = len(qs) # since qs is actually a list
return qs
return Farmer.objects.none() # just an empty queryset as default
template.html
{% extends 'base.html' %}
{% load class_name %}
{% load static %}
{% block custom_css %}
<link rel="stylesheet" type="text/css" href="{% static 'css/home_styles.css' %}">
{% endblock %}
{% block content %}
<div style="height: 10px;">
</div>
<div class="container-fluid">
<div class='row'>
<div class="col-4 offset-md-8">
<form method='GET' class='' action='.'>
<div class="input-group form-group-no-border mx-auto" style="margin-bottom: 0px; font-size: 32px;">
<span class="input-group-addon cfe-nav" style='color:#000'>
<i class="fa fa-search" aria-hidden="true"></i>
</span>
<input type="text" name="q" data-toggle="popover" data-placement="bottom" data-content="Press enter to search" class="form-control cfe-nav mt-0 py-3" placeholder="Search..." value="" style="" data-original-title="" title="" autofocus="autofocus">
</div>
</form>
</div>
</div>
</div>
<div style="height: 10px;">
</div>
<div class="container-fluid">
<div class="row">
<div class="col-6 offset-md-4">
{% for object in object_list %}
{% with object|class_name as klass %}
{% if klass == 'Farmer' %}
<div class='row'>
Farmer: <a href='{{ object.get_absolute_url }}'> {{ object.first_name }} {{ object.last_name }}</a>
</div>
{% elif klass == 'Animal' %}
<div class='row'>
Animal: <a href='{{ object.get_absolute_url }}'> {{ object.name }} {{ object.species }}</a>
</div>
{% else %}
<div class='row'>
<a href='{{ object.get_absolute_url }}'>{{ object }} | {{ object|class_name }}</a>
</div>
{% endif %}
{% endwith %}
{% empty %}
{% endfor %}
<div style="height: 10px;">
</div>
<div class='row'>
<results>{{ count }} results for <b>{{ query }}</b></results>
</div>
</div>
</div>
</div>
<div class="container-fluid">
<!-- Pagniator Data -->
<div class="paginator">
<span class="step-links">
<span class="current">
Page {{ page_obj.number }} of {{ page_obj.paginator.num_pages }}.
</span>
{% if page_obj.has_previous %}
« first
previous
{% endif %}
{% if page_obj.has_next %}
next
last »
{% endif %}
</span>
</div>
</div>
{% endblock %}
if i my template shows me for instance "4 Results for xyz" and "Page 1 of 2" and i push next or last Page, then i get this Error Message:
Page not found (404) Request Method: GET Request URL:
http://127.0.0.1:8000/data/searchview/?page=2 Raised by:
farmapi.views.SearchView
Invalid page (2): That page contains no results
So as far as i understand i have to explicit paginate the return of my queryset so that the paginator will put it into? Or did i miss to set a request for the paginator?
I also use a paginator where the number of items per page can be defined by the user. I added following method:
def get_paginate_by(self, queryset):
limit = int(self.request.POST.get('limit', 25))
return limit
In the template it looks like:
{% if is_paginated %}
{{ page_obj|render_paginator }}
{% endif %}
where render_paginator a template tag is.
In your template call a url like: your_url?page=2

Reverse for 'edit' with no arguments not found. 1 pattern(s) tried: ['articles/edit/(?P<pk>[0-9]+)/$']

I am a beginner in Django and now i am developing a blogging application. At the article editing section i got stucked and I dont know why its showing this error. Searched a lot and cant find an answer
NoReverseMatch at /articles/edit/2/
Reverse for 'edit' with no arguments not found. 1 pattern(s) tried: ['articles/edit/(?P<pk>[0-9]+)/$']
edit_articles section in
views.py
#login_required(login_url="/accounts/login/")
def edit_articles(request, pk):
article = get_object_or_404(Article, id=pk)
if request.method == 'POST':
form = forms.CreateArticle(request.POST, instance=article)
if form.is_valid():
post = form.save(commit=False)
post.author = request.user
post.save()
return redirect('articles:myarticles')
else:
form = forms.CreateArticle(instance=article)
return render(request, 'articles/article_edit.html', {'form': form})
article_edit.html
{% extends 'base_layout.html' %}
{% block content %}
<div class="create-article">
<form class="site-form" action="{% url 'articles:edit' %}" method="post" enctype="multipart/form-data">
{% csrf_token %}
<div class="jumbotron">
<div class="heading col-md-12 text-center">
<h1 class="b-heading">Edit Article</h1>
</div>
<div class="row">
<div class="col-md-6">
<div class="form-group">
{{ form.title }}
</div>
</div>
<div class="col-md-6">
<div class="form-group">
{{ form.slug }}
</div>
</div>
<div class="col-md-6">
<div class="form-group">
{{ form.thumb }}
</div>
</div>
<div class="col-md-12">
<div class="form-group">
{{ form.body }}
</div>
</div>
</div>
<button type="submit" class="btn btn-primary btn-lg btn-block">Update</button>
</div>
</form>
</div>
{% endblock %}
urls.py
from django.urls import path
from . import views
app_name = 'articles'
urlpatterns = [
path('', views.article_list, name='list'),
path('create/', views.article_create, name='create'),
path('edit/<int:pk>/', views.edit_articles, name='edit'),
path('myarticles/',views.my_articles, name='myarticles'),
path('<slug>/', views.article_detail, name='details'),
]
my_articles.html
That button in 4th is triggering the edit function with primary key and redirects to edit page
<tbody>
{% if articles %}
{% for article in articles %}
<tr class="table-active">
<th scope="row">1</th>
<td>{{ article.title }}</td>
<td>{{ article.date }}</td>
<td><button type="button" class="btn btn-info">Edit</button></td>
{% endfor %}
</tr>
{% else %}
<tr>
<td colspan=4 class="text-center text-danger">Oops!! You dont have any articles.</td>
</tr>
{% endif %}
In your template article_edit.html - post url is expecting a pk, you need to pass a pk just like you are doing it for template my_articles.html
<div class="create-article"><form class="site-form" action="{% url 'articles:edit' pk=form.instance.pk %}" method="post" enctype="multipart/form-data">{% csrf_token %}...
This way django knows which article you are editing