Get Django search query right - django

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'),

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'),
]

Django - How to load paginated Page (next page) into my Template?

I have a model named "Person" (List of names).
6 Persons named "Anne". My Pagination is 2 per Page.
When i start a search query on my page for "Anne". I get the Response of "6 Results", it shows me the first two Results and it displays "Page 1 of 3. Next. So far everything fine. but when i press "next" the Browser only updates to
..../post_searchtwo/?page=2 but the next two Results will not show up.
(Using Django version 2.2.2 with PostgreSQL 11)
thanks in advance.
views.py
def post_searchtwo(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 = Person.objects.annotate(
search=SearchVector('city', 'last_name', 'first_name')
).filter(search=query)
paginator = Paginator(results, 2) # --- Show 2 items per page
page = request.GET.get('page')
try:
post_list = paginator.page(page)
except PageNotAnInteger:
post_list = paginator.page(1)
except EmptyPage:
post_list = paginator.page(paginator.num_pages)
context = {
'form': form,
'query': query,
'page': page,
'post_list': post_list,
'results': results
}
return render(request,'search/post_searchtwo.html', context)
my template / post_searchtwo.htnl
{% extends 'base.html' %}
{% load static %}
{% block custom_css %}
<link rel="stylesheet" type="text/css" href="{% static 'css/home_styles.css' %}">
{% endblock %}
{% block content %}
<form action="." method="get">
{{ form.as_p }}
<input type="submit" value="Search">
</form>
{% if query %}
<h3>Posts containing "{{ query }}"</h3>
<h3>
{% with results.count as total_results %}
Found {{ total_results }} result{{ total_results|pluralize }}
{% endwith %}
</h3>
{% for post in post_list %}
<h4>
{{ post.first_name }} {{ post.last_name }}
</h4>
{% empty %}
<p>Theren are no results for your query.</p>
{% endfor %}
<div class="col-6 offset-md-3">
{% include "pagination.html" with page=post_list %}
</div>
{% endif %}
{% endblock %}
.../pagination.htnl
<div class="pagination">
<span class="step-links">
{% if page.has_previous %}
Previous
{% endif %}
<span class="current">
Page {{ page.number }} of {{ page.paginator.num_pages }}.
</span>
{% if page.has_next %}
Next
{% endif %}
</span>
</div>
Update: Thanks to #Daniel Roseman
as Daniel pointed out (down below) here the changes.
.../pagination.htnl
<div class="pagination">
<span class="step-links">
{% if page.has_previous %}
Previous
{% endif %}
<span class="current">
Page {{ page.number }} of {{ page.paginator.num_pages }}.
</span>
{% if page.has_next %}
Next
{% endif %}
</span>
</div>

How to store form data in form pagination using session?

I'm working on a quiz. The quiz has multiple questions - forms. Since there may be many questions, I've created a pagination for these forms. Everything seems to work correctly but only the data from forms on last page are sent to server.
How to hold the data from previous pages so I can send all forms then to server?
I'm considering using session but can't figure out how to make it work. As you can see, all questions are in one form with method post. But pagination are GET methods.
def take_quiz(request,id):
if request.method == 'POST':
quiz = get_object_or_404(models.LanguageQuiz, pk=id)
sitting = get_object_or_404(models.Sitting, quiz=quiz, user=request.user)
for k,v in request.POST.iteritems():
if 'choice-for' in k:
q = Question.objects.get(pk=k.split('-')[-1])
choice = Choice.objects.get(pk=v)
sitting_question = get_object_or_404(SittingQuestion,sitting=sitting,question=q)
sitting_question.answer = choice
sitting_question.save()
correct_answers = len([x for x in sitting.sitting_questions.all() if x.answer.correct])
result = float(correct_answers)/sitting.sitting_questions.all().count() * 100
return render(request,'quiz/result.html',context={'result':result,
'level':level,
'quiz':quiz})
if request.method == 'GET':
with transaction.atomic():
quiz = get_object_or_404(models.LanguageQuiz, pk=id)
if models.Sitting.objects.filter(quiz=quiz, user=request.user).exists():
sitting = get_object_or_404(models.Sitting, quiz=quiz, user=request.user)
check_expired_sitting(sitting)
sitting.delete()
sitting = models.Sitting.objects.create(quiz=quiz, user=request.user)
sitting.load_questions()
questions = [x.question for x in sitting.sitting_questions.all()]
paginator = Paginator(questions,2)
page_num = request.GET.get('page',1)
page = paginator.page(page_num)
context = {'page':page,
'quiz':quiz}
return render(request,'quiz/quiz.html',context=context)
TEMPLATE
{% extends 'base.html' %}
{% block content %}
<h1>{{ quiz.name }}</h1>
<br><br><br>
<form action="" method="post">{% csrf_token %}
{% for question in page.object_list %}
<div class="question">
<h3>{{ question.text }}</h3>
<div class="choices">
{% for choice in question.get_choices_list %}
<input type="radio" name="choice-for-question-{{ question.id }}"
id="choice-{{ question.id }}-{{ forloop.counter }}" value="{{ choice.id }}"/>
<label for="choice-{{ question.id }}-{{ forloop.counter }}">{{ choice.text }}</label><br/>
{% endfor %}
</div>
</div>
{% endfor %}
{% if not page.has_next %}
<button class='accordion' type="submit">Submit Quiz</button>
{% endif %}
</form>
<div class="pagination">
<span class="step-links">
{% if page.has_previous %}
previous
{% endif %}
<span class="current">
Page {{ page.number }} of {{ page.paginator.num_pages }}.
</span>
{% if page.has_next %}
next
{% endif %}
</span>
</div>
{% endblock %}

How can I use django-userena login and logout forms in every page with djangocms?

I have a site running with djangocms and I need the login and logout capabilities of django-userena, it's easy for me to use this because every user will have a profile page too. The design for the menu in every page states that a simple login form has to be in the top right corner of the menu. I have already done that, but I need the django-userena login to work with it. How can I do it?
I have tried to add the form in my base.html. Also tried with a middleware.py like this
class LoginFormMiddleware(object):
def process_request(self, request):
from userena.forms import AuthenticationForm
if request.method == 'POST' and request.POST.has_key('base-account') and request.POST['base-account'] == 'Login':
form = AuthenticationForm(data=request.POST, prefix="login")
if form.is_valid():
from django.contrib.auth import login
login(request, form.get_user())
request.method = 'GET'
else:
form = AuthenticationForm(request, prefix="login")
request.login_form = form
class LogoutFormMiddleware(object):
def process_request(self, request):
if request.method == 'POST' and request.POST.has_key('base-account') and request.POST['base-account'] == 'Logout':
from userena.views import signout
signout(request)
request.method = 'GET'
base.html
<form class="navbar-form navbar-right login-strip" action="" method="post">
{% csrf_token %}
<p id="login">
{{ request.login_form.non_field_errors }}
{% for field in request.login_form %}
{{ field.errors }}
{{ field.label_tag}}: {{ field }}
{% endfor %}
<input type="submit" name="base-account" value="Login" />
</p>
</form>
{% else %}
<form class="navbar-form navbar-right login-strip" action="" method="post">
{% csrf_token %}
<p id="logout">Logged in as <b>{{ request.user.username }}</b>.
<input type="submit" name="base-account" value="Logout" />
</p>
</form>
{% endif %}
This gives me this error
'WSGIRequest' object has no attribute 'get'
I have tried a lot of thighs in this.
Now I'm not using any side django-authetication I just put some code in my menu.html this way I can login and log out as need.
My problem was the normal account has no way to logout.
My work around is that:
menu.html
{% load i18n menu_tags cache %}
{% for child in children %}
<li class="{% if child.ancestor %}ancestor{% endif %}
{% if child.selected %} active{% endif %}
{% if child.children %} dropdown{% endif %}">
{% if child.children %}
<a class="dropdown-toggle" data-toggle="dropdown" href="#">
{{ child.get_menu_title }} <span class="caret"></span>
</a>
<ul class="dropdown-menu">
{% show_menu from_level to_level extra_inactive extra_active template "" "" child %}
</ul>
{% else %}
<span>{{ child.get_menu_title }}</span>
{% endif %}
</li>
{% if class and forloop.last and not forloop.parentloop %}{% endif %}
{% endfor %}
<li class="User" style="position: absolute; right: 0;">
<a >
{% if user.is_authenticated %}
<form method="post" action= "accounts/logout/?next={{ request.path }}">
{% csrf_token %}
<button type="submit" class="cms-btn cms-btn-action"><span class="glyphicon glyphicon-user"></span> {{ request.user.username }}</button>
</form>
{% else %}
<form action="{% url 'pages-root' %}{% if request.path != logout_url %}?next={{ request.path }}&{{ cms_edit_on }}&cms-toolbar-login=1{% endif %}"
class="cms-toolbar-item cms-form-login" method="post">
{% csrf_token %}
<label{% if request.toolbar.login_form.username.errors or request.toolbar.login_form.non_field_errors or cms_toolbar_login_error %} class="cms-error"{% endif %}>
<span>{% trans request.toolbar.login_form.username.label %}</span>
{{ request.toolbar.login_form.username }}
</label>
<label{% if request.toolbar.login_form.password.errors or request.toolbar.login_form.non_field_errors or cms_toolbar_login_error %} class="cms-error"{% endif %}>
<span>{% trans request.toolbar.login_form.password.label %}</span>
{{ request.toolbar.login_form.password }}
</label>
<label>
<input class="cms-btn cms-btn-action" type="submit" value="{% trans 'Login' %}">
</label>
</form>
{% endif %}
</a>
</li>
urls.py added this:
url(r'^accounts/', include('django.contrib.auth.urls')),
I end up with this code, more mobile friend.
<li class="User" style="position: absolute; right: 0;">
<a >
{% if user.is_authenticated %}
<form method="post" action= "accounts/logout/?next={{ request.path }}">
{% csrf_token %}
<p id="logout"><span class="glyphicon glyphicon-user"></span> <b>{{ request.user.username }}</b>
<button type="submit" class="cms-btn cms-btn-action"><span class="glyphicon glyphicon-off"></span> {% trans "Logout" %}</button>
</form>
{% else %}
<form method="post" action="{{request.path}}?edit">
{% csrf_token %}
<button type="submit" class="btn btn-default"><span class="glyphicon glyphicon-user"></span> {% trans "Login" %}</button>
</form>
{% endif %}
</a>
</li>

Django comments pagination isnt working

there is a trouble I'm new to django and there is an issue I can't understand,
there is a view:
def article(request, article_id = 1, comments_page_number = 1):
all_comments = Comments.objects.filter(comments_article_id = article_id)
paginator = Paginator(all_comments, 2)
comment_form = CommentForm
args = {}
args.update(csrf(request))
args['article'] = Article.objects.get(id = article_id)
args['comments'] = paginator.page(comments_page_number)
args['form'] = comment_form
args['username'] = auth.get_user(request).username
return render_to_response('article.html', args)
there is a template article.html
{% extends 'main.html' %}
{% block article %}
<h4>{{article.article_date}}</h4>
<h2>{{article.article_title}}</h2>
<p> {{article.article_body}}</p>
<hr>
<div class="large-offset-1 large-8 columns">
<p>Комментарии: </p>
{% for comment in comments %}
<p>{{comment.comments_text}}</p>
<hr>
{% endfor %}
{% if username %}
<form action="/articles/addcomment/{{article.id}}/" method="POST" >
{% csrf_token %}
{{form }}
<input type="submit" class="button" value="Add comment">
</form>
{% endif %}
</div>
<div class="row">
<div class="large-3 large-offset-5 columns">
<ul class="pagination">
{% if comments.has_previous %}
<li class="arrow">«</li>
{% else %}
<li class="arrow unavailable">«</li>
{% endif %}
{% for page in comments.paginator.page_range %}
{% if page == comments.number %}
<li class="current">{{ page }}</li>
{% else %}
<li>{{ page }}</li>
{% endif %}
{% endfor %}
{% if comments.has_next %}
<li class="arrow">»</li>
{% else %}
<li class="arrow unavailable">»</li>
{% endif %}
</ul>
</div>
</div>
{% endblock %}
this is my article/urls.py
urlpatterns = patterns('',
url(r'^articles/get/(?P<article_id>\d+)/$','article.views.article'),
url(r'^articles/get/(?P<article_id>\d+)/comments/(\d+)/$', 'article.views.article'),
)
after that on my article page appeared an pages pagination, but when I'm clicking on the second page, for example, it it is just changing my url, but new comments are not appearing, just old ones.
What should I do to do this right? Thank you very much!
Your variable name comments_page_number uses always the default value. Name your second parameter in the url route to match this variable name.
you need :
url(r'^articles/get/(?P<article_id>\d+)/comments/(?P<comments_page_number>\d+)/$', 'article.views.this_article'),