mirror of
https://github.com/inventree/InvenTree
synced 2024-08-30 18:33:04 +00:00
Update PartCreate form
- Display list of close matches - Invalidate form (for now)
This commit is contained in:
parent
4e4ee2742b
commit
d9c0d2f5e3
@ -116,14 +116,14 @@ def rename_part_image(instance, filename):
|
|||||||
return os.path.join(base, fn)
|
return os.path.join(base, fn)
|
||||||
|
|
||||||
|
|
||||||
def match_part_names(match, include_description=False, threshold=65, reverse=True):
|
def match_part_names(match, threshold=80, reverse=True, compare_length=False):
|
||||||
""" Return a list of parts whose name matches the search term using fuzzy search.
|
""" Return a list of parts whose name matches the search term using fuzzy search.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
match: Term to match against
|
match: Term to match against
|
||||||
include_description: Also search the part description (default = False)
|
|
||||||
threshold: Match percentage that must be exceeded (default = 65)
|
threshold: Match percentage that must be exceeded (default = 65)
|
||||||
reverse: Ordering for search results (default = True - highest match is first)
|
reverse: Ordering for search results (default = True - highest match is first)
|
||||||
|
compare_length: Include string length checks
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
A sorted dict where each element contains the following key:value pairs:
|
A sorted dict where each element contains the following key:value pairs:
|
||||||
@ -131,16 +131,29 @@ def match_part_names(match, include_description=False, threshold=65, reverse=Tru
|
|||||||
- 'ratio' : The matched ratio
|
- 'ratio' : The matched ratio
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
match = str(match).strip().lower()
|
||||||
|
|
||||||
|
if len(match) == 0:
|
||||||
|
return []
|
||||||
|
|
||||||
parts = Part.objects.all()
|
parts = Part.objects.all()
|
||||||
|
|
||||||
matches = []
|
matches = []
|
||||||
|
|
||||||
for part in parts:
|
for part in parts:
|
||||||
compare = part.name
|
compare = str(part.name).strip().lower()
|
||||||
if include_description:
|
|
||||||
compare += part.description
|
|
||||||
|
|
||||||
ratio = fuzz.partial_ratio(match, compare)
|
if len(compare) == 0:
|
||||||
|
continue
|
||||||
|
|
||||||
|
ratio = fuzz.partial_ratio(compare, match)
|
||||||
|
|
||||||
|
if compare_length:
|
||||||
|
# Also employ primitive length comparison
|
||||||
|
l_min = min(len(match), len(compare))
|
||||||
|
l_max = max(len(match), len(compare))
|
||||||
|
|
||||||
|
ratio *= (l_min / l_max)
|
||||||
|
|
||||||
if ratio >= threshold:
|
if ratio >= threshold:
|
||||||
matches.append({
|
matches.append({
|
||||||
|
18
InvenTree/part/templates/part/create_part.html
Normal file
18
InvenTree/part/templates/part/create_part.html
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
{% extends "modal_form.html" %}
|
||||||
|
|
||||||
|
{% block pre_form_content %}
|
||||||
|
|
||||||
|
{{ block.super }}
|
||||||
|
|
||||||
|
{% if matches %}
|
||||||
|
<b>Matching Parts</b>
|
||||||
|
<ul class='list-group'>
|
||||||
|
{% for match in matches %}
|
||||||
|
<li class='list-group-item list-group-item-condensed'>
|
||||||
|
{{ match.part.name }} - <i>{{ match.part.description }}</i> ({{ match.ratio }}%)
|
||||||
|
</li>
|
||||||
|
{% endfor %}
|
||||||
|
</ul>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% endblock %}
|
@ -16,6 +16,7 @@ from company.models import Company
|
|||||||
from .models import PartCategory, Part, PartAttachment
|
from .models import PartCategory, Part, PartAttachment
|
||||||
from .models import BomItem
|
from .models import BomItem
|
||||||
from .models import SupplierPart
|
from .models import SupplierPart
|
||||||
|
from .models import match_part_names
|
||||||
|
|
||||||
from . import forms as part_forms
|
from . import forms as part_forms
|
||||||
|
|
||||||
@ -135,7 +136,7 @@ class PartCreate(AjaxCreateView):
|
|||||||
form_class = part_forms.EditPartForm
|
form_class = part_forms.EditPartForm
|
||||||
|
|
||||||
ajax_form_title = 'Create new part'
|
ajax_form_title = 'Create new part'
|
||||||
ajax_template_name = 'modal_form.html'
|
ajax_template_name = 'part/create_part.html'
|
||||||
|
|
||||||
def get_data(self):
|
def get_data(self):
|
||||||
return {
|
return {
|
||||||
@ -174,6 +175,28 @@ class PartCreate(AjaxCreateView):
|
|||||||
|
|
||||||
return form
|
return form
|
||||||
|
|
||||||
|
def post(self, request, *args, **kwargs):
|
||||||
|
|
||||||
|
form = self.get_form()
|
||||||
|
|
||||||
|
name = request.POST.get('name', None)
|
||||||
|
|
||||||
|
context = {}
|
||||||
|
|
||||||
|
if name:
|
||||||
|
matches = match_part_names(name)
|
||||||
|
|
||||||
|
if len(matches) > 0:
|
||||||
|
context['matches'] = matches
|
||||||
|
|
||||||
|
form.non_field_errors = 'Check matches'
|
||||||
|
|
||||||
|
data = {
|
||||||
|
'form_valid': False
|
||||||
|
}
|
||||||
|
|
||||||
|
return self.renderJsonResponse(request, form, data, context=context)
|
||||||
|
|
||||||
def get_initial(self):
|
def get_initial(self):
|
||||||
""" Get initial data for the new Part object:
|
""" Get initial data for the new Part object:
|
||||||
|
|
||||||
|
@ -27,6 +27,10 @@
|
|||||||
padding: 6px 12px;
|
padding: 6px 12px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.list-group-item-condensed {
|
||||||
|
padding: 5px 10px;
|
||||||
|
}
|
||||||
|
|
||||||
/* Force select2 elements in modal forms to be full width */
|
/* Force select2 elements in modal forms to be full width */
|
||||||
.select-full-width {
|
.select-full-width {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
Loading…
Reference in New Issue
Block a user