Django links, url parameters overwriting - django

I've got django template with table/list with sorting action:
Name
and later I've got paging:
first
What I want to achieve is a link:
http://localhost:8000/list/?page=3&order_by=name
but, while - clicking a link, I can get either page or order_by.
How to solve it the 'django way'? (for 2 and more parameters).
More details -
def list_view(request):
items_list = model.objects.all()
# Filter
request_filter = request.GET.get('filter',"")
if request_filter:
items_list = items_list.filter(model__icontains=request_filter)
# Paging
paginator = Paginator(list, 2) # Show 2 items per page.
page_number = request.GET.get('page',1)
page_obj = paginator.get_page(page_number)
items_list = paginator.page(page_number)
return render(request,'list.html', {'list' : items_list, 'filter':request_filter, 'page_obj': page_obj})
and template: (related parts)
<form action="" method="GET">
<input type="text" name="filter" value={{filter}} >
<button class="btn btn-sm btn-outline-success" type="submit">Filtruj</button>
</form>
<table class="table">
<thead>
<tr>
<th>Name</th>
etc </table>
<div class="pagination">
<span class="step-links">
{% if page_obj.has_previous %}
« first
previous
{% endif %}

Related

How to hide entire row if one or two fields are empty Django

How can I hide an entire row if one or more specific fields are empty? For example, I have a django query set up so that I can get a total profit from items in the inventory manager. The way that I have that written is like:
html
{% extends 'portal/base.html' %}
{% block title %}Inventory{% endblock %}
{% block content %}
<br>
<div class="row">
<div class="col">
<form class="d-flex" role="search" action="/search" method="get">
<input class="form-control me-2" type="text" name="q" placeholder="Search" aria-label="Search">
<button class="btn btn-outline-success">Search</button>
</form>
</div>
<div class="col">
<a class="btn btn-primary me-md-2" href="/newitem" type="button">Input New Purchase</a>
</div>
</div>
</div>
<table class="table table-striped">
<thead>
<tr>
<th>Breakdown</th>
<th>Product ID</th>
<th>Product</th>
<th>Total Profit</th>
</tr>
</thead>
{% for inventory in inventory %}
<tr>
<td><a class='btn btn-success btn-sm' href=''>View Breakdown</a>
<td>{{inventory.id}}</td>
<td>{{inventory.product}}</td>
<td>{{ inventory.Calculate_profit }}</td>
</tr>
{% endfor %}
</table>
{% endblock %}
views.py
#login_required(login_url="/login")
def profitsperitem(request):
inventory = Inventory.objects.all().order_by('id')
return render(request, 'portal/profitsperitem.html', {"inventory": inventory})
models.py
#property
def Calculate_profit(self):
soldfor = Inventory.objects.filter(soldprice=self.soldprice).aggregate(Sum('soldprice'))['soldprice__sum'] or 0.00
paidfor = Inventory.objects.filter(paid=self.paid).aggregate(Sum('paid'))['paid__sum'] or 0.00
shipfor = Inventory.objects.filter(shipcost=self.shipcost).aggregate(Sum('shipcost'))['shipcost__sum'] or 0.00
totalprofit = soldfor - paidfor - shipfor
return totalprofit
As long as the model fields soldprice , paid , and shipcost are all filled out on every row in the database, I can get the results no problem. I get an error if soldprice or shipcost are null or none, so when there is nothing added to database. If one row does not have soldprice or shipcost set, none of the results can be viewed as this error pops up: "TypeError at /profitsperitem
unsupported operand type(s) for -: 'float' and 'decimal.Decimal'"
My question is how can I hide the entire row if either or both soldprice and/or shipcost are empty?
Tho filter all rows with any of the two fields beeing null/None use a query like this
from django.db.models import Q
#login_required(login_url="/login")
def profitsperitem(request):
inventory = Inventory.objects.filter(
Q(soldprice__isnull = False) | Q(shipcost__isnull = False)
).order_by('id')
return render(request, 'portal/profitsperitem.html', {"inventory": inventory})
I was able to update the view like this
#login_required(login_url="/login")
def profitsperitem(request):
inventory = Inventory.objects.filter(soldprice__isnull = False, shipcost__isnull = False).order_by('id')
return render(request, 'portal/profitsperitem.html', {"inventory": inventory})
{% for inventory in inventory %}
{% if inventory.Calculate_profit %}
<tr>
<td><a class='btn btn-success btn-sm' href=''>View Breakdown</a>
<td>{{inventory.id}}</td>
<td>{{inventory.product}}</td>
<td>{{ inventory.Calculate_profit }}</td>
</tr>
{% endif %}
{% endfor %}
you can print row only if you have calculate price.
if(soldfor is not None and paidfor is not None and shipfor is not None )
totalprofit = soldfor - paidfor - shipfor
else totalprofit =None
Also You can check if Calculate profit has some value

All my rows are still visible eventhough i am filtering

THis my first time using the django filter and i am trying to filter my all my records are still show even do my url says it is filtering the my records- any help will be appreciated
This my filter File
class Clientsearch(django_filters.FilterSet):
class Meta:
model = client
fields ='__all__'
exclude = ['Companyemail','Telephone','address','Postcode','RegNom','UTRno','PAYE','VAT','pensionusername','pensionpassword','companyfilling','authenticationcode','gatewayonlineuserid','gatewayonlinepassword',
'finacialdate',
'confirmationdate',
'agreedfees','updated_at','created_at','datejoined']
This my view.py
def manage_client(request):
clients=client.objects.all()
myFilter = Clientsearch(request.GET,queryset = clients)
context = {'myFilter':myFilter,'clients':clients}
clients = myFilter.qs
return render(request,"admintemplate/manage_client_template.html",context)
This the Html Code for my Table - All the rows are still show but i can see in the url it is filtering
<br>
<div class="row">
<div class="col">
<div class="card card-body">
<form method ="get">
{{myFilter.form}}
<button class="btn btn-primary" type ="submit">Search</button>
</form>
</div>
</div>
</div>
<br>
<div class="row">
<div class="col-md">
<div class="card card-body">
<table class="table table-sm">
<tr>
<th>ID</th>
<th>Company Name</th>
<th>Company Email</th>
<th>Sector</th>
<th>Employee Assigned</th>
<th>Edit</th>
<th>Delete</th>
</tr>
{% for client in clients %}
<tr>
<td>{{client.id}}</td>
<td>{{client.Companyname}}</td>
<td>{{client.Companyemail}}</td>
<td>{{client.sector}}</td>
<td>{{client.username}}</td>
<td>Edit</td>
<td>delete</td>
{% endfor %}
</table>
</div>
</div>
</div>
You are using the queryset you passed clients = client.objects.all(), use the filters queryset which you can access using myFilter.qs, i.e in your template the loop will be:
{% for client in myFilter.qs %}
You need to assign clients = myFilter.qs before you create your context. Doing so after you create the context doesn't change the value that you originally passed to the context (a client.objects.all() queryset)
def manage_client(request):
clients = client.objects.all()
myFilter = Clientsearch(request.GET,queryset = clients)
clients = myFilter.qs # These lines
context = {'myFilter': myFilter, 'clients': clients} # These lines
return render(request, "admintemplate/manage_client_template.html", context)

Search Bar in Django

EDIT: I managed to include a Search bar using 'DjangoFilter'
I would like to add a search bar to my template in Django
I would like to include a search box in above a list of articles so users can search through the data.
When I enter something in the bar nothing happens though...
here below my code
Thanks for the help in advance
In HTML page
<form class="form-inline my-2 my-lg-0">
<input class="form-control mr-sm-2" type="search" placeholder="Search" aria-label="Search" name="search" >
<button class="btn btn-outline-success my-2 my-sm-0" type="submit">Search</button>
</form>
In views.py
def article_overview(request):
search_term = ''
if 'search' in request.GET:
search_term = request.GET['search']
articles = Article.objects.all().filter(feeder__icontains=search_term)
articles = Article.objects.all()
return render(request, 'overviews/overview.html', {'articles' : articles, 'search_term': search_term })
in overview.html(simplified):
{% for article in articles %}
<a> {{article.feeder}} </a>
{% endfor %}
In views.py,
class SearchView(ListView):
model = Article
template_name = 'search.html'
context_object_name = 'all_search_results'
def get_queryset(self):
result = super(SearchView, self).get_queryset()
query = self.request.GET.get('search')
if query:
postresult = Article.objects.filter(title__contains=query)
result = postresult
else:
result = None
return result
In your template to search query,
<form class="add_your_class" method="GET" action="" >
<input class="add_your_class" type="search" name="search">
<button class="add_your_class" type="submit"> Search </button>
</form>
In templates you can add it as to show results
{% for result in all_search_results %}
{{ .....add according to your model }}
{% empty %}
add something to show no results
{% endfor %}
My example worked in my case:
base template:
form class="form-inline my-2 my-lg-0" method="GET" action="{% url 'ecomm:search' %}" >
<input class="form-control mr-sm-2" type="search" name="search">
<button class="btn btn btn-outline-info my-2 my-sm-0" type="submit"> Search </button>
</form>
search template:
{% extends "ecomm/base.html" %}
{% block content %}
{% for product in all_search_results %}
<h3>{{product.title}}</h3>
<p>{{product.description}}</p>
<img src="{{ product.picture.url }}">
{% empty %}
<h2>No results found</h2>
{% endfor %}
{% endblock %}
the view:
class SearchView(ListView):
model = Products
template_name = 'ecomm/search.html'
context_object_name = 'all_search_results'
def get_queryset(self):
result = super(SearchView, self).get_queryset()
query = self.request.GET.get('search')
if query:
postresult = Products.objects.filter(title__contains=query)
result = postresult
else:
result = None
return result
the url:
path('results/', ecomm_views.SearchView.as_view(), name='search'),
Another simple solution is to use DataTables which inlcude a search bar by default. Put your fields in each row and search it out that way.
<table id="articles" class="display" style="width:100%">
<thead>
<tr>
<th>Feeder</th>
</tr>
</thead>
<tbody>
{% for article in articles %}
<tr>
<td>{{article.feeder}</td>
</tr>
{% endfor %}
</tbody>
</table>
<script>
$(document).ready(function () {
$('#articles').DataTable();
});
</script>
Assuming that you have your articles saved in your database, what you can do is have a datalist for your input, use AJAX to prepopulate the datalist with the articles from your database so that you have some sort of an autocomplete dropdown/search box.
There's an excellent tutorial from Teamtreehouse.com for this implementation. Here's the link.
You are assigning article variable in two places, therefore you're overwriting the first one. Rename article variable inside if statement and pass that to template
if 'search' in request.GET:
search_term = request.GET['search']
search_result = Article.objects.all().filter(feeder__icontains=search_term)
articles = Article.objects.all()
return render(request, 'overviews/overview.html', {'articles' : articles, 'search_result': search_result })

Django display search results

I'm currently working on a blog app in Django. As all Blog apps I need a search form. Therefore I have write a small view and context processor (to make the search form available globally) that queries search results:
view.py:
class BlogSearchListView(ListView):
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
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>
settings.py:
TEMPLATE_CONTEXT_PROCESSORS = (
'django.core.context_processors.auth',
'django.core.context_processors.debug',
'django.core.context_processors.i18n',
'quickblog.quickblog.context_processors.categorysearch_form',
)
context_processors.py
from .forms import PostForm
def categorysearch_form(request):
form = PostForm()
return {'categorysearch_form': form}
post_list.html:
{% extends 'quickblog/base.html' %}
{% block content %}
{% for post in posts %}
<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 %}
<div>
<span>
{% if posts.has_previous %}
« First <a> |</a>
Previous
{% endif %}
{% if posts.has_next %}
<span> Page {{ posts.number }} of {{ posts.paginator.num_pages }}.</span>
Next<a> |</a>
Last »
{% endif %}
</span>
</div>
{% endblock %}
The rest of the project can be checked here: https://github.com/rsmvdl/quickblog
I now want to render the results the same way as they get display in my post_list.html view with one detail more: I want that the word the user searched for gets highlighted in the search results, so that the user is able to get the context of the content ASAP ;) . I hope to get any creative ideas. Thanks.
You can create a custom template filter to add an HTML tag around the searched-for word in your post title or content. This will not be an exact solution but you should be able to adapt it:
#register.filter
#stringfilter
def highlight_search_term(text, search_term):
if search_term in text:
text.replace(search_term, '<span class="highlight">' + search_term + '</span>')
return mark_safe(text)
You can then apply this filter to your post title or content in your template with {{ post.title|highlight_search_term:search_term }}.
You will need to also pass search_term to your template context so that the filter can know what to highlight. Be careful with mark_safe() if you are applying this to user-submitted content!
You can create a context processor and pass request.GET.get('q') as context.
context_processors.py
def search(request):
search_keyword = request.GET.get('q')
context = {'search_keyword': search_keyword}
return context
And in your template access it as {{ search_keyword }}
search_results.html
<h3>Showing results for: {{ search_keyword }}</h3>

django: update database upon onsubmit dropdown

I am trying to create a ticketing system. What I want to do is when I change the Status dropdown list it should update the status of the ticket in the database. Also, I would like to update and view in the same page. Any insights if that would be possible?
forms.py
class ViewForm(forms.Form):
statuses = [
('In Progress', 'In Progress'),
('On Hold', 'On Hold'),
('Done', 'Done'),
('ForQA', 'ForQA'),
('QAPassed', 'QAPassed'),
('QARevs', 'QARevs'),
]
status = forms.ChoiceField(label='Status', required=True, choices=statuses, widget=forms.Select(attrs={'onchange': 'actionform.submit();'}))
views.py
def view_sheet(request, project_id):
project = Project.objects.get(pk=project_id)
tickets = Ticket.objects.filter(project=project_id)
form = ViewForm()
context = {
'project': project,
'tickets': tickets,
'form': form,
}
return render(request, 'project/sheet/view.html', context)
view.html
<div class="tracker-sheet">
<div class="project-name">
<h1>{{project.name}}</h1>
</div>
<div class="actions">
<a href="{% url 'add_ticket' project.id %}">
<button type="submit">New Ticket</button>
</a>
</div >
<div class="tracker-table">
<table>
<tr>
<th>Total Worked</th>
<th>Status</th>
<th>Status Date</th>
<th>Received</th>
<th>Due Date</th>
<th>Agent</th>
<th>Sub Type</th>
<th>CID</th>
<th>Link</th>
<th>Task Description</th>
<th>Server</th>
<th>Qty</th>
<th>Info</th>
</tr>
{% for ticket in tickets %}
<tr>
<td><span class="table-constant"></span></td>
{% for field in form %}
<td>{{field}}</td> <!-- Status dropdown list -->
{% endfor %}
<td><span class="table-constant">{{ticket.status_date}}</span></td>
</form>
<td><span class="table-constant">{{ticket.received}}</span></td>
<td><span class="table-constant">{{ticket.due_date}}</span></td>
<td><span class="table-constant"></span></td>
<td><span class="table-constant">{{ticket.sub_type}}</span></td>
<td><span class="table-vary"></span></td>
<td><span class="table-constant">{{ticket.link}}</span></td>
<td><input type="submit" value="{{ticket.task_description}}"</td>
<td><span class="table-constant"></span></td>
<td><span class="table-constant">{{ticket.qty}}</span></td>
<td></td>
</tr>
{% endfor %}
</table>
</div>
Something like this should do it:
views.py
def update_status(request, ticket_id):
ticket = get_object_or_404(Ticket, pk=ticket_id)
status = request.GET.get(status)
if status:
ticket.status = status
ticket.save()
else:
raise Http404
return HttpResponse({'ticket_id': ticket.id, 'status': ticket.status, content_type='application/json')
And in the template (or remote js file):
<script>
$(document).ready(function(){
$(".statuses").change(function(){
$.ajax({url: "update_status/" + $(this).data("ticket_id) + "/?status=" $(this).val(), success: function(result){
console.log(result);
}});
});
});
</script>
urls.py:
....
url(r'^update_status/(?P<ticket_id>[\d]+)$', update_status),
....
NOTE: You'l need a different ticket id for each of these trs, so I'd add a data-ticket_id = {{ ticket.id }} to each select. That means your {{ field }} is going to have to get more declarative.
Something like:
<select id="status_{{ticket.id}}" class="statuses" data-ticket_id="{{ ticket.id }}" />
{% for k, v in statuses %}
<option value="{{ k }}">{{ v }}</option>
{% endfor %}
What you are asking is totally possible.
The idea:
One way would be to use a javascript function call to update this field (AJAX GET or POST). This script will request a URL managed by the same view, or a new one.
The view would then process the request, return some data for you to parse and optionally confirm that the change what successful, or display an error.
In practice:
You can use for example a jQuery Post, with the URL parameter the one to your view_sheet (or like I said, a new view just for this purpose).
In your view you could play with request.is_ajax(), a test on the request that will be true when it comes from your jQuery post.
What I want to do is when I change the Status dropdown list it should
update the status of the ticket in the database
Instead of this :
status = forms.ChoiceField(label='Status', required=True, choices=statuses, widget=forms.Select(attrs={'onchange': 'actionform.submit();'}))
Try this :
status = forms.ChoiceField(label='Status', required=True, choices=statuses, widget=forms.Select(attrs={'onChange':'this.form.submit()'}))