How to GET data by search word Django - django

I have problem getting the data to the home page.
I would like to filter out all the books based on Genre. I'm following the
MDN site for this.
index.html
{% extends "base_generic.html" %}
{% block content %}
<h1>Local Library Home</h1>
<p>Welcome to <em>Local Library</em>, a very basic Django website.</p>
<h2>Dynamic content</h2>
<form action="" method="get">
<input type="text" name="genre" placeholder="Search">
<input type="submit" value="Search">
</form>
{% endblock %}
urls.py
urlpatterns = [
url(r'^$', views.index, name='index'),
url(r'^books/$', views.BookListView.as_view(), name='books'),
url(r'^(?P<string>[-\w]+)$', views.GenreListView.as_view(), name='index'),
]
GenreListView class
class GenreListView(generic.ListView):
model = Book
def get(request, string):
try:
book = Book.objects.all().filter(genre=string)
except Book.DoesNotExist:
raise Http404("Book does not exist")
return render(
request,
'index.html',
context={'book': book,}
)
I can't figure out what I'm missing or what else I have to do to get all the date based on genre?
EDIT:
whole index.html
{% extends "base_generic.html" %}
{% block content %}
<h1> Book List </h1>
<form action="" method="get">
<input type="text" name="genre" placeholder="Search">
<input type="submit" value="Search">
</form>
{% if book_list %}
<ul>
{% for book in book_list %}
<li>
{{ book.title }} ({{ book.author }})
</li>
{% endfor %}
</ul>
{% else %}
<p>There are no books in the library</p>
{% endif %}
{% endblock %}

You should override get_queryset, No need to rewrite get
class GenreListView(generic.ListView):
model = Book
template_name = 'index.html'
def get_queryset(self):
books = Book.objects.all()
query = self.request.GET.get('genre', None)
if query:
return books.filter(genre=query)
return books
The exception Book.DoesNotExist will never
occur if you filter() queryset. it will always return a empty queryset in case of no object found

Related

How to display search term on search results page in django?

I made a form and then i made little search form and it works but, i didnt display the search term on the search results page...
I just wanna show Search Results for (Search Term)
Here are my codes.
Views.py
class SearchResultsView(ListView):
model = Post
template_name = 'search.html'
def get_queryset(self):
query = self.request.GET.get('q')
object_list = Post.objects.filter(Q(soru1__icontains=query) | Q(soru2__icontains=query) |
Q(soru3__icontains=query) |
Q(soru4__icontains=query) |
)
return object_list
Base.html ( search bar in it)
<form class="d-flex" action="{% url 'search' %}" method="get">
<input class="form-control me-2" name="q" type="text" placeholder="Arama...">
<button class="btn btn-outline-success" type="submit">Ara</button></form>
And search.html
{% extends 'base.html' %}
{% block content %}
<h1>Search Results for </h1>
<ul>
{% for Post in object_list %}
<li>
{{ Post.soru1 }}
</li>
{% endfor %}
</ul>
{% endblock %}
You need to add query to context:
Views.py
class SearchResultsView(ListView):
model = Post
template_name = 'search.html'
def get_queryset(self):
query = self.request.GET.get('q')
object_list = Post.objects.filter(Q(soru1__icontains=query) | Q(soru2__icontains=query) |
Q(soru3__icontains=query) |
Q(soru4__icontains=query) )
return object_list
def get_context_data(self, **kwargs):
context = super(SearchResultsView, self).get_context_data(**kwargs)
context['query'] = self.request.GET.get('q')
return context
and in template:
{% extends 'base.html' %}
{% block content %}
<h1>Search Results for {{ query }} </h1>
<ul>
{% for Post in object_list %}
<li>
{{ Post.soru1 }}
</li>
{% endfor %}
</ul>
{% endblock %}

Django simple search with Class based views and forms.py

I have been trying to do a variation of what Williams Vincent did on this page: https://learndjango.com/tutorials/django-search-tutorial .
I am using Django 3.2 so if there are modifications, I need to make I have not identified them. I am having some troubles.
This what I made which worked just fine.
my_search.html:
{% extends "base.html" %}
{% block body %}
{% for city in object_list %}
<li>
{{city.name}}   {{city.city_no}}
</li>
{% endfor %}
{% endblock %}
views.py:
from django.views.generic import ListView
from .models import City
class SearchResutlsView(ListView): # test version
model = City
template_name = "search_results.html"
def get_queryset(self):
return City.objects.filter(name__icontains='Boston')
Now it is time to add forms.py, but when I made the below changes to the code it does not work. What am I missing? There are no errors displayed. I get a blank html.
{% extends "base.html" %}
{% block body %}
<form class="d-flex" method='get' action="{% url 'city:search_results' %}">
{{ form }}
<button class="btn btn-outline-success" type="submit" value="qu">Search Name</button>
</form>
{% for city in city_list %}
<li>
{{city.name}}   {{city.city_no}}
</li>
{% endfor %}
{% endblock %}
forms.py
from django import forms
class SearchForm(forms.Form):
q = forms.CharField(label='Search label', max_length=50, strip=True)
views.py
from django.views.generic import FormView, ListView
from .models import City
class SearchResutlsView(FormView):
model = City
form_class = SearchForm
template_name = "city/search_results.html"
def get_queryset(self):
query = self.request.Get.get("q")
if query:
city_list = City.objects.filter(name__icontains=query)
else:
city_list = City.objects.none()
return city_list
First, Your method should be POST not get.
Second, you need to add CSRF token.
something like that:
{% extends "base.html" %}
{% block body %}
<form class="d-flex" method='post' action="{% url 'city:search_results' %}">
{% csrf_token %}
{{ form }}
<button class="btn btn-outline-success" type="submit" value="qu">Search Name</button>
</form>
{% for city in city_list %}
<li>
{{city.name}}   {{city.city_no}}
</li>
{% endfor %}
{% endblock %}
and in views.py
query = self.request.POST.get("q")

django search returns a blank page

I have designed my search box in my django app but the search only returns the extended html page, not the search results.
#View
class SearchListProject(ListView):
paginate_by = 4
template_name = 'website/search_project.html'
def get_queryset(self):
search_project = self.request.GET.get('q')
return Project.objects.filter(description__icontains=search_project)
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['search_project'] = self.request.GET.get('q')
return context
#url
path('search_project/', SearchListProject.as_view(), name='search_project'),
path('search_project/page/<int:page>', SearchListProject.as_view(), name='search_project')
#html
{% extends 'website/project_list.html' %}
<h3 class="alert alert-primary text-center">Search: {{ search_project }}</h3>
{% block previous_page_url %}
{% url 'website:search_project' page_obj.previous_page_number %}?q={{ search_project }}
{% endblock %}
{% block next_page_url %}
{% url 'website:search_project' page_obj.next_page_number%}?q={{ search_project }}
{% endblock %}
#my form
<form action="{% url 'website:search_project' %}">
<input type="text" name="q">
<button type="submit"><i class="icofont-search"></i></button>
</form>

No Post matches the given query

I am using Django version 2.
I am working on a blog web app using PostgreSQL database.
I am trying to add a search feature to the web app but when I open the url (http://localhost:8000/search/) to make a search, I get the error below.
Page not found (404)
Request Method: GET
Request URL: http://localhost:8000/search/
Raised by: blog.views.post_detail
No Post matches the given query.
here is the blog/urls.py
from django.contrib.postgres.search import SearchVector
from .forms import CommentForm, SearchForm
from .models import Post, Comment
from django.shortcuts import render, get_object_or_404
from django.urls import path
from . import views
urlpatterns = [
path('', views.PostListView.as_view(), name='home'),
path('<slug:post>/', views.post_detail, name='post_detail'),
path('<int:post_id>/share', views.post_share, name='share'),
path('search/', views.post_search, name='post_search'),
]
here is the views.py
def post_detail(request, post):
post = get_object_or_404(Post, slug=post)
comments = post.comments.filter(active=True)
new_comment = None
if request.method == 'POST':
comment_form = CommentForm(data=request.POST)
if comment_form.is_valid():
new_comment = comment_form.save(commit=False)
new_comment.post = post
new_comment.save()
else:
comment_form = CommentForm()
return render(request, 'detail.html', {'post': post,
'comments': comments, 'new_comment':
new_comment,'comment_form': comment_form})
def post_search(request):
form = SearchForm()
query = None
results = []
if 'query' in request.GET:
form = SearchForm(request.GET)
if form.is_valid():
query = form.cleaned_data['query']
results = Post.objects.annotate(
search=SearchVector('title','body'),
).filter(search=query)
return render(request, 'search.html',
{'form':form,'query':query,'results':results})
Here are the templates files.
For search.html -(page to make query)
{% extends 'base.html' %}
{% block title %}Search{% endblock title %}
{% block page_title %}Search Posts{% endblock page_title %}
{% block content %}
{% if query %}
<h1>Posts containing "{{ query }}"</h1>
<h3>
{% with results.count as total_results %}
Found {{ total_results }} result{{ total_results|pluralize }}
{% endwith %}
</h3>
{% for post in results %}
<h4>{{ post.title }}</h4>
{{ post.body|truncatewords:5 }}
{% empty %}
<p>There is no results for your query.</p>
{% endfor %}
<p>Search again</p>
{% else %}
<h1>Search for posts</h1>
<form action="." method="GET">
{{ form.as_p }}
<input type="submit" value="Search">
</form>
{% endif %}
{% endblock content %}
For the html for post_detail
{% extends 'base.html' %}
{% load blog_tags %}
{% load crispy_forms_tags %}
{% load profanity %}
{% block title %}{{post.title}}{% endblock title %}
{% block navlink %}
<nav>
<ul>
<li class="current">Home</li>
<li>About</li>
<li >Services</li>
</ul>
</nav>
{% endblock navlink %}
{% block page_title %}{{post.title}}{% endblock page_title %}
{% block content %}
{{post.body|markdown}}
<p>Share this post via email</p>
{% with comments.count as total_comments %}
<h2>{{ total_comments }} comment{{ total_comments|pluralize }} </h2>
{% endwith %}
<div class="container">
{% for comment in comments %}
<div class="comment">
<p>Comment {{ forloop.counter }} by <em>{{ comment.name }}</em> - {{comment.created}} </p>
{{ comment.body|censor|linebreaks }}
</div>
{% empty %}
<p>There are no comments yet.</p>
{% endfor %}
{% if new_comment %}
<h2>Your comment has been added</h2>
{% else %}
<h2>Add a new comment</h2>
<form method="post">{% csrf_token %}
{{comment_form|crispy}}
<input class="button_1" type="submit" value="Add comment">
</form>
{% endif %}
</div>
{% endblock content %}
This is probably for one of the strange reason search is here actually matches with slug:post. One of easiest solution for your problem is to re-order urls and make sure /search place before. Like following
urlpatterns = [
path('', views.PostListView.as_view(), name='home'),
path('search/', views.post_search, name='post_search'),
path('<slug:post>/', views.post_detail, name='post_detail'),
path('<int:post_id>/share', views.post_share, name='share')
]
My suggestion for further developement whenever its need to add slug in url we need to make sure there is some prefix before it.

Why is my Update URL link kicking me to the CreateNew html view

so this is a tag on from my previous stackoverflow post:
Django updateView saving another instance instead of updating
and i think i've narrowed it down. Whats happening is that when i click on the link to update my view, it sends me to the "create new" page. my problem is that I cant figure out why its doing that.
Any and all help is appreciated.
here is the code:
question_form.html
{% extends "base.html" %}
{% load bootstrap3 %}
{% block content %}
<h4>Create New Question</h4>
<form method="POST" action="{% url 'questions:create' %}" id="questionForm">
{% csrf_token %}
{% bootstrap_form form %}
<input type="submit" value="Post" class="btn btn-primary btn-large">
</form>
{% endblock %}
question_update.html
{% extends "base.html" %}
{% load bootstrap3 %}
{% block content %}
<h4>Update Question</h4>
<form method="POST" action="{% url 'questions:update' pk=question.pk %}" id="questionForm">
{% csrf_token %}
{% bootstrap_form form %}
<input type="submit" value="Update" class="btn btn-primary btn-large">
</form>
{% endblock %}
question_detail.html
{% block content %}
this is the question detail view
<h3>{{ question.question_html|safe }}</h3>
<h3>{{ question.answer_html|safe }}</h3>
Update Question
{% endblock %}
urls.py
url(r'new/$', views.CreateQuestion.as_view(), name='create'),
url(r'questionupdate/(?P<pk>\d+)/$', views.QuestionUpdate.as_view(), name='update'),
url(r'questiondetail/(?P<pk>\d+)/$', views.QuestionDetail.as_view(), name='single'),
views.py
class CreateQuestion(generic.CreateView):
model = models.Question
form = QuestionForm
fields = ('question', 'answer')
success_url = reverse_lazy('questions:all')
def form_valid(self, form):
self.object = form.save(commit=False)
self.object.user = self.request.user
self.object.save()
return super().form_valid(form)
class QuestionDetail(generic.DetailView):
model = models.Question
class QuestionUpdate(generic.UpdateView):
model = models.Question
form_class = QuestionForm
context_object_name = 'question'
From your urls.py the name of update view is only update. You can try only update tag in html file Like
{% extends "base.html" %}
{% load bootstrap3 %}
{% block content %}
<h4>Update Question</h4>
<form method="POST" action="{% url 'update' pk=question.pk %}" id="questionForm">
{% csrf_token %}
{% bootstrap_form form %}
<input type="submit" value="Update" class="btn btn-primary btn-large">
</form>
{% endblock %}
I've figured it out. it turns out I was missing the template name part under my Create and update views which directs them to their own html templates:
class CreateQuestion(generic.CreateView):
model = models.Question
form_class = QuestionForm
fields = ('question', 'answer')
template_name = "questions/question_form_create.html"
success_url = reverse_lazy('questions:all')
class QuestionUpdate(generic.UpdateView):
model = models.Question
form_class = QuestionForm
template_name = "questions/question_form_update.html"