Fixed search and implemented an asset search api

Added asset picker for parent attribute

Co-authored-by: Panagiotis Petridis <lPanagiotisPetridisl@gmail.com>
This commit is contained in:
Matthew Smith
2019-10-05 20:17:26 +01:00
parent 1d253aa452
commit e3cbcbd151
7 changed files with 109 additions and 81 deletions

View File

@@ -20,6 +20,7 @@
{% else %} {% else %}
<form method="post" id="asset_update_form" action="{% url 'asset_create'%}"> <form method="post" id="asset_update_form" action="{% url 'asset_create'%}">
{% endif %} {% endif %}
{% include 'form_errors.html' %}
<div class="row" style="padding-bottom: 1em"> <div class="row" style="padding-bottom: 1em">
<div class="col-sm-12"> <div class="col-sm-12">
<div class="pull-right"> <div class="pull-right">
@@ -142,35 +143,8 @@
Collection Details Collection Details
</div> </div>
<div class="panel-body"> <div class="panel-body">
<div class="form-group"> {% include 'partials/asset_picker.html' %}
<label for="parent_id">Parent</label> </div
<input type="hidden" name="{{ form.parent.html_name }}" id="hidden_parent_id" value="{{ object.parent.id }}">
<div class="input-group">
<input type="text" id="parent_id" value="{{ object.parent|default:'' }}" disabled="" class="form-control">
<span class="input-group-btn">
<button type="button" class="btn btn-default" onclick="clearParent()">Clear</button>
</span>
</div>
</div>
<div class="form-group">
<label for="parent_search">Search for asset</label>
<div class="input-group">
<input type="text" id="parent_search" class="form-control">
<span class="input-group-btn">
<button type="button" class="btn btn-default" onclick="formAssetSearch()">
<i class="glyphicon glyphicon-search"></i> Search
</button>
</span>
</div>
</div>
<div class="col s2">
<br>
</div>
<div class="col s12" id="formAssetSearchResult">
<!--Placeholder for search results-->
</div>
</div>
</div> </div>
</div> </div>
<div class="row"> <div class="row">

View File

@@ -11,20 +11,20 @@
<form id="asset-search-form"> <form id="asset-search-form">
{% csrf_token %} {% csrf_token %}
<div class="input-group"> <div class="input-group">
<input type="query" name="query" placeholder="Search by Asset ID/Description" class="form-control" value="{{searchName}}"> <input type="query" name="query" placeholder="Search by Asset ID/Description" class="form-control" value="{{search_name}}">
<label for="asset_id" class="sr-only">Asset ID/Description:</label> <label for="asset_id" class="sr-only">Asset ID/Description:</label>
<span class="input-group-btn"><button type="submit" class="btn btn-default">Search</button></span> <span class="input-group-btn"><button type="submit" class="btn btn-default">Search</button></span>
</div> </div>
</form>
<form class="form-inline" id="asset-filter-form">
{% csrf_token %}
<div class="form-group"> <div class="form-group">
<label for="cat">Category:</label> <label for="cat">Category:</label>
<select name="cat" class="form-control"> <select name="cat" class="form-control">
<option>None</option> <option value="">None</option>
{% for name in categories %} {% for name in categories %}
{% if name == category_select %}
<option selected>
{% else %}
<option> <option>
{% endif %}
{{ name }} {{ name }}
</option> </option>
{% endfor %} {% endfor %}
@@ -33,15 +33,19 @@
<div class="form-group"> <div class="form-group">
<label for="status">Status:</label> <label for="status">Status:</label>
<select name="status" class="form-control"> <select name="status" class="form-control">
<option>None</option> <option value="">None</option>
{% for name in statuses %} {% for name in statuses %}
{% if name == status_select %}
<option selected>
{% else %}
<option> <option>
{% endif %}
{{ name }} {{ name }}
</option> </option>
{% endfor %} {% endfor %}
</select> </select>
</div> </div>
<!---TODO: Auto filter whenever an option is selected, instead of using a button ---> <!---TODO: Auto filter whenever an option is selected, instead of using a button -->
<button type="submit" class="btn btn-default">Filter</button> <button type="submit" class="btn btn-default">Filter</button>
</form> </form>

View File

@@ -24,6 +24,7 @@
{% else %} {% else %}
<form method="post" id="asset_update_form" action="{% url 'asset_update' pk=object.pk%}"> <form method="post" id="asset_update_form" action="{% url 'asset_update' pk=object.pk%}">
{% endif %} {% endif %}
{% include 'form_errors.html' %}
<div class="row" style="padding-bottom: 1em"> <div class="row" style="padding-bottom: 1em">
<div class="col-sm-12"> <div class="col-sm-12">
<div class="pull-right"> <div class="pull-right">
@@ -190,35 +191,8 @@
</div> </div>
<div class="panel-body"> <div class="panel-body">
{% if edit or duplicate %} {% if edit or duplicate %}
<div class="form-group"> {% include 'partials/asset_picker.html' %}
<label for="parent_id">Parent</label> {% else%}
<input type="hidden" name="{{ form.parent.html_name }}" id="hidden_parent_id"
value="{{ object.parent.id }}">
<div class="input-group">
<input type="text" id="parent_id" value="{{ object.parent|default:'' }}"
disabled="" class="form-control">
<span class="input-group-btn"><button type="button" class="btn btn-default" onclick="clearParent()">Clear
</button></span>
</div>
</div>
<div class="form-group">
<label for="parent_search">Search for asset</label>
<div class="input-group">
<input type="text" id="parent_search" class="form-control">
<span class="input-group-btn"><button type="button" class="btn btn-default" onclick="formAssetSearch()">
<i class="glyphicon glyphicon-search"></i> Search
</button></span>
</div>
</div>
<div class="col s2">
<br>
</div>
<div class="col s12" id="formAssetSearchResult">
<!--Placeholder for search results-->
</div>
{% else %}
<dl> <dl>
<dt>Parent</dt> <dt>Parent</dt>
<dd> <dd>

View File

@@ -1,7 +1,6 @@
{% for item in object_list %} {% for item in object_list %}
{# <li><a href="{% url 'asset_detail' item.pk %}">{{ item.asset_id }} - {{ item.description }}</a></li>#} {# <li><a href="{% url 'asset_detail' item.pk %}">{{ item.asset_id }} - {{ item.description }}</a></li>#}
<!---TODO: When the ability to filter the list is added, remove the colours from the filter - specifically, stop greying out sold/binned stuff if it is being searched for---> <!---TODO: When the ability to filter the list is added, remove the colours from the filter - specifically, stop greying out sold/binned stuff if it is being searched for--> <tr class="
<tr class="
{% if item.status.name == 'Broken' %} {% if item.status.name == 'Broken' %}
danger danger
{% elif item.status.name == 'Lost'%} {% elif item.status.name == 'Lost'%}

View File

@@ -0,0 +1,63 @@
<select name="parent" id="parent_id" class="selectpicker">
{% if object.parent%}
<option value="{{object.parent.pk}}" selected>{{object.parent.description}}</option>
{% endif %}
</select>
{% load static %}
{% block css %}
<link rel="stylesheet" href="{% static "css/bootstrap-select.min.css" %}"/>
<link rel="stylesheet" href="{% static "css/ajax-bootstrap-select.css" %}"/>
{% endblock %}
{% block preload_js %}
<script src="{% static "js/bootstrap-select.js" %}"></script>
<script src="{% static "js/ajax-bootstrap-select.js" %}"></script>
{% endblock %}
{% block js %}
<script>
$('#parent_id')
.selectpicker({
liveSearch: true
})
.ajaxSelectPicker({
ajax: {
url: '{% url 'asset_search_json'%}',
type: "get",
data: function () {
var params = {
{% verbatim %}query: '{{{q}}}'{% endverbatim %}
};
return params;
}
},
locale: {
emptyTitle: 'Search for item...'
},
preprocessData: function(data){
var assets = [];
if(data.length){
var len = data.length;
for(var i = 0; i < len; i++){
var curr = data[i];
assets.push(
{
'value': curr.id,
'text': curr.label,
'disabled': false
}
);
}
assets.push(
{
'value': null,
'text': "No parent"
});
}
return assets;
},
preserveSelected: false
});
</script>
{% endblock js %}

View File

@@ -15,6 +15,8 @@ urlpatterns = [
path('asset/<int:pk>/duplicate/', views.AssetDuplicate.as_view(), name='asset_duplicate'), path('asset/<int:pk>/duplicate/', views.AssetDuplicate.as_view(), name='asset_duplicate'),
path('asset/delete/', views.asset_delete, name='ajax_asset_delete'), path('asset/delete/', views.asset_delete, name='ajax_asset_delete'),
path('asset/search/', views.AssetSearch.as_view(), name='asset_search_json'),
path('supplier/list', views.SupplierList.as_view(), name='supplier_list'), path('supplier/list', views.SupplierList.as_view(), name='supplier_list'),
path('supplier/<int:pk>', views.SupplierDetail.as_view(), name='supplier_detail'), path('supplier/<int:pk>', views.SupplierDetail.as_view(), name='supplier_detail'),
path('supplier/create', views.SupplierCreate.as_view(), name='supplier_create'), path('supplier/create', views.SupplierCreate.as_view(), name='supplier_create'),

View File

@@ -1,7 +1,7 @@
from django.shortcuts import render, get_object_or_404 from django.shortcuts import render, get_object_or_404
from django.contrib.auth.decorators import login_required from django.contrib.auth.decorators import login_required
from django.contrib.auth.mixins import LoginRequiredMixin from django.contrib.auth.mixins import LoginRequiredMixin
from django.http import HttpResponse, QueryDict from django.http import HttpResponse, QueryDict, JsonResponse
from django.core import serializers from django.core import serializers
from django.views import generic from django.views import generic
from django.contrib.auth import views as auth_views from django.contrib.auth import views as auth_views
@@ -22,27 +22,39 @@ class AssetList(LoginRequiredMixin, generic.ListView):
def get_queryset(self): def get_queryset(self):
#TODO Feedback to user when search fails #TODO Feedback to user when search fails
query = self.request.GET.get('query', "") query = self.request.GET.get('query', "")
queryset = self.model.objects.all()
if len(query) >= 3: if len(query) >= 3:
return self.model.objects.filter(Q(asset_id__exact=query) | Q(description__icontains=query)) queryset = self.model.objects.filter(Q(asset_id__exact=query) | Q(description__icontains=query))
elif query != "":
return self.model.objects.filter(Q(asset_id__exact=query)) cat = self.request.GET.get('cat', "")
else: status = self.request.GET.get('status', "")
cat = self.request.GET.get('cat', "") if cat != "":
status = self.request.GET.get('status', "") queryset = queryset.filter(category__name__exact=cat)
if cat != "None": elif status != "":
return self.model.objects.filter(category__name__exact=cat) queryset = queryset.filter(status__name__exact=status)
elif status != "None":
return self.model.objects.filter(status__name__exact=status) return queryset
else:
return self.model.objects.all()
def get_context_data(self, **kwargs): def get_context_data(self, **kwargs):
context = super(AssetList, self).get_context_data(**kwargs) context = super(AssetList, self).get_context_data(**kwargs)
context["search_name"] = self.request.GET.get('query', "") context["search_name"] = self.request.GET.get('query', "")
context["categories"] = models.AssetCategory.objects.all() context["categories"] = models.AssetCategory.objects.all()
context["category_select"] = self.request.GET.get('cat', "")
context["statuses"] = models.AssetStatus.objects.all() context["statuses"] = models.AssetStatus.objects.all()
context["status_select"] = self.request.GET.get('stats', "")
return context; return context;
class AssetSearch(AssetList):
def render_to_response(self, context, **response_kwargs):
result = []
for asset in context["object_list"]:
result.append({"id":asset.pk, "label":(asset.asset_id + " | " + asset.description)})
return JsonResponse(result, safe=False)
class AssetDetail(LoginRequiredMixin, generic.DetailView): class AssetDetail(LoginRequiredMixin, generic.DetailView):
model = models.Asset model = models.Asset
template_name = 'asset_update.html' template_name = 'asset_update.html'