From 1b8ca34ddb405b1ea87a07f26327c3d1c5eef12c Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Sat, 11 May 2019 10:36:24 +1000 Subject: [PATCH] Added fuzzy search function for matching against part names --- InvenTree/part/models.py | 41 ++++++++++++++++++++++++++++++++++++++-- 1 file changed, 39 insertions(+), 2 deletions(-) diff --git a/InvenTree/part/models.py b/InvenTree/part/models.py index 0318c11f57..46734f9e15 100644 --- a/InvenTree/part/models.py +++ b/InvenTree/part/models.py @@ -24,6 +24,8 @@ from django.contrib.auth.models import User from django.db.models.signals import pre_delete from django.dispatch import receiver +from fuzzywuzzy import fuzz + from InvenTree import helpers from InvenTree import validators from InvenTree.models import InvenTreeTree @@ -88,8 +90,6 @@ def before_delete_part_category(sender, instance, using, **kwargs): child.save() -# Function to automatically rename a part image on upload -# Format: part_pk. def rename_part_image(instance, filename): """ Function for renaming a part image file @@ -116,6 +116,43 @@ def rename_part_image(instance, filename): return os.path.join(base, fn) +def match_part_names(match, include_description=False, threshold=65, reverse=True): + """ Return a list of parts whose name matches the search term using fuzzy search. + + Args: + match: Term to match against + include_description: Also search the part description (default = False) + threshold: Match percentage that must be exceeded (default = 65) + reverse: Ordering for search results (default = True - highest match is first) + + Returns: + A sorted dict where each element contains the following key:value pairs: + - 'part' : The matched part + - 'ratio' : The matched ratio + """ + + parts = Part.objects.all() + + matches = [] + + for part in parts: + compare = part.name + if include_description: + compare += part.description + + ratio = fuzz.partial_ratio(match, compare) + + if ratio >= threshold: + matches.append({ + 'part': part, + 'ratio': ratio + }) + + matches = sorted(matches, key=lambda item: item['ratio'], reverse=reverse) + + return matches + + class Part(models.Model): """ The Part object represents an abstract part, the 'concept' of an actual entity.