How to by default not show list of items? - django

There is a page where the list of elements is displayed. Also on this page there is a search by value. When I enter a value, the page only displays elements with that value.
I need to make the page show nothing but the search by default. And only after the query, the page shows the elements with the entered value. How to do it?
home.html
<div class="headtext">
<form method="GET" action="{% url 'search' %}">
<input type="search" type="text" name="q" prequired placeholder="Put appnumber">
<button type="submit">Find</button>
</form>
</div>
<div>
{% for application in object_list %}
<div>
<p>Application: {{ application.appnumber }}, status: {{ application.status }}</p>
</div>
{% endfor %}
</div>
urls.py
from django.urls import path
from .views import HomeView, Search
urlpatterns = [
path('', HomeView.as_view(), name="home"),
path('search/', Search.as_view(), name="search"),
views.py
class HomeView(ListView):
model = Application
template_name = 'home.html'
class Search(ListView):
template_name = 'home.html'
def get_queryset(self):
return Application.objects.filter(appnumber__icontains=self.request.GET.get("q"))
def get_context_data(self, *args, **kwargs):
context = super().get_context_data(*args, **kwargs)
context["q"] = self.request.GET.get("q")
return context

Simply check the existence of the object_list context variable:
<div class="headtext">
<form method="GET" action="{% url 'search' %}">
<input type="search" type="text" name="q" prequired placeholder="Put appnumber">
<button type="submit">Find</button>
</form>
</div>
{% if object_list %}
<div>
{% for application in object_list %}
<div>
<p>Application: {{ application.appnumber }}, status: {{ application.status }}</p>
</div>
{% endfor %}
</div>
{% endif %}
Edit: I hadn't noticed that HomeView is also a subclass of ListView. Change it to:
class HomeView(TemplateView):
template_name = 'home.html'

You can have an method that will take 'q' from request and return it or None.
Then your get_queryset can use this parameter to return object list you need.
Something like this should work
class Search(ListView):
template_name = 'home.html'
def get_q(self):
q = self.request.GET.get('q', None)
return q
def get_queryset(self):
q = self.get_q()
if not q:
return []
return Application.objects.filter(appnumber__icontains=q)

Related

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>

Reverse for 'update_order' with arguments '('',)' not found. 1 pattern(s) tried: ['update_order\\/(?P<pk>[^/]+)\\/$']

I guess there is some error in updateorder function, but I cannot find it. When I am clicking on the update button in dashboard.html it gives an error saying that
Reverse for 'update_order' with arguments '('',)' not found. 1 pattern(s) tried: ['update_order\/(?P[^/]+)\/$']
views.py
from django.shortcuts import render, redirect
from django.http import HttpResponse
from accounts.models import *
from accounts.forms import OrderForm
# Create your views here.
def home(request):
customers = Customer.objects.all()
orders = Order.objects.all()
total_customers = customers.count()
total_orders = orders.count()
pending = orders.filter(status='Pending').count()
delivered = orders.filter(status='Delivered').count()
context = {'customers':customers, 'orders':orders, 'pending':pending, 'delivered':delivered, 'total_customers':total_customers,
'total_orders':total_orders}
return render(request, 'accounts/dashboard.html', context)
def products(request):
products = Product.objects.all()
return render(request, 'accounts/products.html', {'products':products})
def customer(request, pk):
customers = Customer.objects.get(id=pk)
orders = Order.objects.all()
orders_counts = orders.count()
context = {'customers':customers, 'orders':orders, 'orders_counts':orders_counts}
return render(request, 'accounts/customer.html', context)
def createorder(request):
form = OrderForm
if request.method=='POST':
form = OrderForm(request.POST)
if form.is_valid():
form.save()
return redirect('/')
context = {'form':form}
return render(request, 'accounts/order_form.html', context)
def updateorder(request, pk):
orders = Order.objects.get(id = pk)
form = OrderForm(instance = orders)
context = {'form':form}
return render(request, 'accounts/order_form.html', context)
> Blockquote
urls.py
from django.urls import path
from . import views
urlpatterns = [
path('', views.home, name = 'home'),
path('products/', views.products, name = 'products'),
path('customer/<str:pk>/', views.customer, name = 'customer'),
path('create_order/', views.createorder, name = 'create_order'),
path('update_order/<str:pk>/', views.updateorder, name = 'update_order')
]
dashboard.html
{% extends 'accounts/main.html' %}
{% block content %}
{% include 'accounts/status.html' %}
<br>
<div class="row">
<div class="col-md-5">
<h5>CUSTOMERS:</h5>
<hr>
<div class="card card-body">
<a class="btn btn-primary btn-sm btn-block" href="">CREATE CUSTOMERS</a>
<table class = "table table-sm">
<tr>
<th>Customers</th>
<th>Phone</th>
</tr>
{% for i in customers %}
<tr>
<!-- <td>View</td> -->
<td>{{i.name}}</td>
<td>{{i.phone}}</td>
<td><a class="btn btn-info" href="{% url 'customer' i.id %}">View</a></td>
</tr>
{% endfor %}
</table>
</div>
</div>
<div class="col-md-7">
<h5>LAST 5 ORDERS</h5>
<hr>
<div class="card card-body">
<a class="btn btn-primary btn-sm btn-block" href="{% url 'create_order' %}">CREATE ORDERS</a>
<table class = "table table-sm">
<tr>
<th>Product</th>
<th>Date Ordered</th>
<th>Status</th>
<th>Update</th>
<th>Remove</th>
</tr>
{% for i in orders %}
<tr>
<td>{{i.product}}</td>
<td>{{i.date_created}}</td>
<td>{{i.status}}</td>
<td><a class="btn btn-info" href="{% url 'update_order' Order.id %}">Update</a></td>
<td><a class="btn btn-danger" href="">Delete</a></td>
</tr>
{% endfor %}
</table>
</div>
</div>
</div>
{% endblock %}
forms.py
from django.forms import ModelForm
from accounts.models import Order
class OrderForm(ModelForm):
class Meta:
model = Order
fields = '__all__'
order_forms.html
{% extends 'accounts/main.html' %}
{% load static %}
{% block content %}
<form method="post">
{% csrf_token %}
{{form}}
<input type="submit" name="Submit">
</form>
{% endblock %}
{% for i in orders %}
...
{% url 'update_order' Order.id %}
it's i, not Order, so change to
{% url 'update_order' i.id %}
For django-1.x, you can not use such path(..)s, and in that case you need to write a regular expression, like:
url(r'^complete/(?P<todo_id>[0-9]+)$', views.completeTodo, name='complete'),
If you are using django-2.x, you probably want to use path(..), like you have.
I believe it may be to do with how you've set up your regex. What data type is the Order object from your models, I am assuming they're string since that's the type you have defined in your urls. If they're then do as you've done , else if its string then do what's below
For urls, instead of this:
url('update_order/<todo_id>', , views.updateorder, name = 'update_order'),
try this:
url(r'^update_order/(?P<todo_id>\d+)$', , views.updateorder, name = 'update_order'),
Or incase you want to use [path]
path('update_order/<int:todo_id>', views.updateorder, name = 'update_order'),

Django 2.1.2 - AttributeError: 'UserProfile' object has no attribute 'object'

I am having problems with a class named SearchView(ListView) which I am using to display a search query. This class "SearchView" is being inherited from a UserProfile View, so that users can use the search bar in the profile view to search any post. When I try to load the route /users/// it raise the Following error: 'UserProfile' object has no attribute 'object. I guess it is because I am overriding the get_context_data() method.
This is the code of the SearchView class:
class SearchView(ListView):
model = Post
def get_context_data(self, *args, **kwargs):
context = super().get_context_data(**kwargs)
try:
context['list_result'] = self.result
except:
messages.error(self.request, 'test')
finally:
return context
def get(self, request, *args, **kwargs):
if request.GET.get('search'):
search_query = request.GET.get('search', None)
self.result = Post.objects.filter(title__icontains=search_query).order_by()
if not self.result:
messages.error(request, f'No results found for {search_query}')
return super().get(request, *args, **kwargs)
This is the code of the UserProfile View:
#method_decorator(login_required, name='dispatch')
class UserProfile(SearchView, DetailView):
model = User
context_object_name = 'user_object'
def get_context_data(self, **kwargs):
data = super().get_context_data(**kwargs)
try:
relevant_post = Post.objects.filter(author_id=self.kwargs.get('pk')).order_by('-rating')[0]
data['relevant_post'] = relevant_post
except IndexError:
pass
finally:
return data
This is the search template:
{% extends 'blog/base.html' %}
{% load static %}
{% block content %}
<form class="align-middle w-50" type="GET" style="margin: 0">
<span class="fa fa-search form-control-feedback"></span>
<input type="text" class="form-control" name="search"
placeholder="Search ..">
</form>
{% if list_result %}
<h2>Results: </h2>
{% for result in list_result %}
<div class="container">
<article class="media content-section">
<div class="media-body">
<div class="article-metadata">
<img class="rounded-circle article-img" src="{{ result.author.profile.image.url }} "/>
<a class="mr-2" href="{% url 'profile' result.author.id result.author.username %}">{{ result.author }}</a>
<small class="text-muted">{{ result.post_date|date:"N d, o" }} . </small>
<div class="float-right mt-1">
<img src="{% static 'blog/rating_icon.svg' %}" alt="Ratings">
<div></div>
<medium class="ml-2">{{ result.rating }}</medium>
</div>
<h2><a class="article-title" href="{% url 'post-detail' result.id result.title %}">{{ result.title }}</a></h2>
<a href="{% url 'post-detail' result.id result.title%}">
Click here for more details.
</a>
</div>
</div>
</article>
</div>
{%endfor%}
{%endif%}
{%endblock%}
Thank you in advance.
try adding self.object = self.get_object() to get_context_data. Because a DetailView needs an object attribute

how to handle same form on different pages (DRY)

I have a template called base.html. it contains a fixed search form at top of it. all of my other templates inherit from base.html. I want to my form works on every pages (right now I have 10 different pages).
One silly solution is to handle form for every single view, but it is opposite of DRY.
So how can I handle my form one time for all of views ?
NOTE: base.html is just a template and is not used directly by a view.
You need to create a separate app for 'search' and need to create views and templates accordingly.
I have an app called 'Products' in my Django project and it has the model called 'Product' and I use search to search from that model.
search/views.py:
from django.shortcuts import render
from django.views.generic import ListView
from products.models import Product
class SearchProductView(ListView):
template_name = "search/view.html"
def get_context_data(self, *args, **kwargs):
context = super(SearchProductView, self).get_context_data(*args, **kwargs)
query = self.request.GET.get('q')
context['query'] = query
# SearchQuery.objects.create(query=query)
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)
return Product.objects.featured()
'''
__icontains = field contains this
__iexact = fields is exactly this
'''
search/templates/view.html (to render the search results):
{% extends "base.html" %}
{% block content %}
<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-6 mx-auto py-5'>
{% include 'search/snippets/search-form.html' %}
</div>
<div class='col-12'>
<hr>
</div>
{% endif %}
</div>
<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><div class='row'><div class='col-12'><hr/></div>
{% elif forloop.counter|divisibleby:2 %}
</div> </div><div class='row'><div class='col-12'><hr/></div>
{% else %}
</div>
{% endif %}
{% endfor %}
</div>
{% endblock %}
search/templates/snippets/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="text" 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>
and, finally, urls.py for search app:
from django.conf.urls import url
from .views import (
SearchProductView
)
urlpatterns = [
url(r'^$', SearchProductView.as_view(), name='query'),
]
and include this in your main urls.py:
url(r'^search/', include("search.urls", namespace='search')),
I hope this helps.
Good luck!

haystack on existing template

How to implement working SearchView in existing views.py?
I already have CBV, and added in urls.py as /moderate and want to apply search form in it. but always got "Results No results found."
This is my /moderate page with 3 forms, using SearchView and piece of code from tutorial in template.
And this from /search page, with urls(r'^search/$', include('haystack.urls'))
urls.py
urlpatterns= [
url(r'^search/', include('haystack.urls')),
url(r'^moderate/', Moderate.as_view(), name='moderate'),
]
views.py
class Moderate(SearchView):
#method_decorator(staff_member_required)
def dispatch(self, *args, **kwargs):
return super(Moderate, self).dispatch(*args, **kwargs)
#model = Ad
template_name = 'adapp/ad_moderate.html'
#template_name = 'search/search.html'
paginator_class = DiggPaginator
paginate_by = 10
ad_type = None
ad_sub_type = None
def get_queryset(self):
qs = super(Moderate, self).get_queryset().filter(ad_type__isnull=False,
ad_sub_type__isnull=False)
return qs
def get_context_data(self, **kwargs):
context = super(Moderate, self).get_context_data(**kwargs)
context['filter'] = ModerateFilter(self.request.GET)
return context
# define method to recieve fields from form, and change data accordings
def post(self, request, *args, **kwargs):
selected = request.POST['selected']
record = Ad.objects.get(pk=int(selected))
form = ModerateForm(request.POST, instance=record)
if form.is_valid():
form.save(commit=True)
return HttpResponseRedirect('')
template/ad_moderate.html
{% extends 'base.html' %}
{% load i18n url_tags %}
{% block content %}
<div id="casing">
<div id="content">
{# filter form, to show only models with moderated=True #}
<form action="" method="get">
{{ filter.form.as_p }}
<input type="submit">
</form>
<h2>Search</h2>
{# search form right from tutorial #}
<form method="get" action="">
<table>
{{ form.as_table }}
<tr>
<td> </td>
<td>
<input type="submit" value="Search">
</td>
</tr>
</table>
{% if query %}
<h3>Results</h3>
{% for result in page.object_list %}
<p>
{{ result.object.title }}
</p>
{% empty %}
<p>No results found.</p>
{% endfor %}
{% else %}
{# Show some example queries to run, maybe query syntax, something else? #}
{% endif %}
</form>
{% for object in filter %}
{# a lot of template tags and third form to change value of model #}
<form action="" method="POST">
{% csrf_token %}
<input type="radio" name="moderated" value="True">Accept
<br>
<input type="radio" name="moderated" value="False">Decline
<input type="hidden" value="{{ object.id }}"
name="selected">
<input class="btn" type="submit" value="moderate">
</form>
search_indexes.py
from .models import Ad
class AdIndex(indexes.SearchIndex, indexes.Indexable):
text = indexes.CharField(document=True, use_template=True)
def get_model(self):
# my model, with one search should be
return Ad
templates/search/indexes/app/ad_text.txt
{{ object.title }}
{{ object.short_desc }}
{{ object.description }}
{{ object.experience }}
{{ object.skills }}
{{ object.name }}
{{ object.city }}
get_context_data():
context['search'] = SearchForm(self.request.GET).search()
Would solve a problem.
That means, I should create form and send return from .save() method, rather that django-like form instance.