Add member search api route
This commit is contained in:
parent
fddaf083b4
commit
402ec28ff5
|
@ -12,7 +12,9 @@ class Member(models.Model):
|
||||||
|
|
||||||
set_details = models.BooleanField(default=False)
|
set_details = models.BooleanField(default=False)
|
||||||
preferred_name = models.CharField(max_length=32, blank=True)
|
preferred_name = models.CharField(max_length=32, blank=True)
|
||||||
|
status = models.CharField(max_length=32, blank=True)
|
||||||
phone = models.CharField(max_length=32, blank=True)
|
phone = models.CharField(max_length=32, blank=True)
|
||||||
|
expire_date = models.DateField(default=date.today, blank=True, null=True)
|
||||||
current_start_date = models.DateField(default=date.today, blank=True, null=True)
|
current_start_date = models.DateField(default=date.today, blank=True, null=True)
|
||||||
application_date = models.DateField(default=date.today, blank=True, null=True)
|
application_date = models.DateField(default=date.today, blank=True, null=True)
|
||||||
vetted_date = models.DateField(blank=True, null=True)
|
vetted_date = models.DateField(blank=True, null=True)
|
||||||
|
|
|
@ -22,12 +22,20 @@ class UserSerializer(serializers.ModelSerializer):
|
||||||
depth = 1
|
depth = 1
|
||||||
|
|
||||||
|
|
||||||
|
# member viewing member list or other member
|
||||||
|
class OtherMemberSerializer(serializers.ModelSerializer):
|
||||||
|
class Meta:
|
||||||
|
model = models.Member
|
||||||
|
fields = ['preferred_name', 'last_name', 'status', 'current_start_date']
|
||||||
|
|
||||||
|
# member viewing himself
|
||||||
class MemberSerializer(serializers.ModelSerializer):
|
class MemberSerializer(serializers.ModelSerializer):
|
||||||
class Meta:
|
class Meta:
|
||||||
model = models.Member
|
model = models.Member
|
||||||
fields = '__all__'
|
fields = '__all__'
|
||||||
read_only_fields = ['user', 'application_date', 'current_start_date', 'vetted_date', 'monthly_fees', 'old_member_id']
|
read_only_fields = ['user', 'application_date', 'current_start_date', 'vetted_date', 'monthly_fees', 'old_member_id']
|
||||||
|
|
||||||
|
# adming viewing member
|
||||||
class AdminMemberSerializer(serializers.ModelSerializer):
|
class AdminMemberSerializer(serializers.ModelSerializer):
|
||||||
class Meta:
|
class Meta:
|
||||||
model = models.Member
|
model = models.Member
|
||||||
|
|
|
@ -3,6 +3,8 @@ from django.db.models import Max
|
||||||
from rest_framework import viewsets, views, permissions
|
from rest_framework import viewsets, views, permissions
|
||||||
from rest_framework.response import Response
|
from rest_framework.response import Response
|
||||||
from rest_auth.registration.views import RegisterView
|
from rest_auth.registration.views import RegisterView
|
||||||
|
from fuzzywuzzy import fuzz, process
|
||||||
|
from collections import OrderedDict
|
||||||
|
|
||||||
from . import models, serializers
|
from . import models, serializers
|
||||||
|
|
||||||
|
@ -16,6 +18,53 @@ class UserViewSet(viewsets.ModelViewSet):
|
||||||
serializer_class = serializers.UserSerializer
|
serializer_class = serializers.UserSerializer
|
||||||
|
|
||||||
|
|
||||||
|
search_strings = {}
|
||||||
|
def gen_search_strings():
|
||||||
|
for m in models.Member.objects.all():
|
||||||
|
string = '{} {} {} {}'.format(
|
||||||
|
m.preferred_name,
|
||||||
|
m.last_name,
|
||||||
|
m.first_name,
|
||||||
|
m.last_name,
|
||||||
|
).lower()
|
||||||
|
search_strings[string] = m.id
|
||||||
|
gen_search_strings()
|
||||||
|
|
||||||
|
class SearchViewSet(viewsets.ReadOnlyModelViewSet):
|
||||||
|
permission_classes = [AllowMetadata | permissions.IsAuthenticated]
|
||||||
|
serializer_class = serializers.OtherMemberSerializer
|
||||||
|
|
||||||
|
def get_queryset(self):
|
||||||
|
NUM_SEARCH_RESULTS = 10
|
||||||
|
|
||||||
|
queryset = models.Member.objects.all()
|
||||||
|
params = self.request.query_params
|
||||||
|
|
||||||
|
if 'q' in params and len(params['q']) >= 3:
|
||||||
|
search = params['q'].lower()
|
||||||
|
choices = search_strings.keys()
|
||||||
|
|
||||||
|
# get exact starts with matches
|
||||||
|
results = [x for x in choices if x.startswith(search)]
|
||||||
|
# then get exact substring matches
|
||||||
|
results += [x for x in choices if search in x]
|
||||||
|
# then get fuzzy matches
|
||||||
|
fuzzy_results = process.extract(search, choices, limit=NUM_SEARCH_RESULTS, scorer=fuzz.token_set_ratio)
|
||||||
|
results += [x[0] for x in fuzzy_results]
|
||||||
|
|
||||||
|
# remove dupes
|
||||||
|
results = list(OrderedDict.fromkeys(results))
|
||||||
|
|
||||||
|
result_ids = [search_strings[x] for x in results]
|
||||||
|
result_objects = [queryset.get(id=x) for x in result_ids]
|
||||||
|
|
||||||
|
queryset = result_objects
|
||||||
|
else:
|
||||||
|
queryset = queryset.order_by('-vetted_date')
|
||||||
|
|
||||||
|
return queryset[:NUM_SEARCH_RESULTS]
|
||||||
|
|
||||||
|
|
||||||
class MemberViewSet(viewsets.ModelViewSet):
|
class MemberViewSet(viewsets.ModelViewSet):
|
||||||
permission_classes = [AllowMetadata | permissions.IsAuthenticated]
|
permission_classes = [AllowMetadata | permissions.IsAuthenticated]
|
||||||
http_method_names = ['options', 'head', 'get', 'put', 'patch']
|
http_method_names = ['options', 'head', 'get', 'put', 'patch']
|
||||||
|
|
|
@ -10,6 +10,7 @@ router.register(r'users', views.UserViewSet)
|
||||||
router.register(r'members', views.MemberViewSet, basename='member')
|
router.register(r'members', views.MemberViewSet, basename='member')
|
||||||
router.register(r'courses', views.CourseViewSet, basename='course')
|
router.register(r'courses', views.CourseViewSet, basename='course')
|
||||||
router.register(r'sessions', views.SessionViewSet, basename='session')
|
router.register(r'sessions', views.SessionViewSet, basename='session')
|
||||||
|
router.register(r'search', views.SearchViewSet, basename='search')
|
||||||
#router.register(r'me', views.FullMemberView, basename='fullmember')
|
#router.register(r'me', views.FullMemberView, basename='fullmember')
|
||||||
#router.register(r'registration', views.RegistrationViewSet, basename='register')
|
#router.register(r'registration', views.RegistrationViewSet, basename='register')
|
||||||
|
|
||||||
|
|
|
@ -6,8 +6,12 @@ from apiserver.api import models, old_models
|
||||||
|
|
||||||
MEMBER_FIELDS = [
|
MEMBER_FIELDS = [
|
||||||
'id',
|
'id',
|
||||||
|
'first_name',
|
||||||
|
'last_name',
|
||||||
'preferred_name',
|
'preferred_name',
|
||||||
|
'status',
|
||||||
'phone',
|
'phone',
|
||||||
|
'expire_date',
|
||||||
'current_start_date',
|
'current_start_date',
|
||||||
'application_date',
|
'application_date',
|
||||||
'vetted_date',
|
'vetted_date',
|
||||||
|
|
|
@ -1,11 +1,23 @@
|
||||||
argon2-cffi==19.2.0
|
argon2-cffi==19.2.0
|
||||||
asgiref==3.2.3
|
asgiref==3.2.3
|
||||||
|
certifi==2019.11.28
|
||||||
cffi==1.13.2
|
cffi==1.13.2
|
||||||
|
chardet==3.0.4
|
||||||
|
defusedxml==0.6.0
|
||||||
Django==3.0.2
|
Django==3.0.2
|
||||||
|
django-allauth==0.41.0
|
||||||
django-rest-auth==0.9.5
|
django-rest-auth==0.9.5
|
||||||
djangorestframework==3.11.0
|
djangorestframework==3.11.0
|
||||||
|
fuzzywuzzy==0.17.0
|
||||||
|
idna==2.8
|
||||||
|
oauthlib==3.1.0
|
||||||
pkg-resources==0.0.0
|
pkg-resources==0.0.0
|
||||||
pycparser==2.19
|
pycparser==2.19
|
||||||
|
python-Levenshtein==0.12.0
|
||||||
|
python3-openid==3.1.0
|
||||||
pytz==2019.3
|
pytz==2019.3
|
||||||
|
requests==2.22.0
|
||||||
|
requests-oauthlib==1.3.0
|
||||||
six==1.13.0
|
six==1.13.0
|
||||||
sqlparse==0.3.0
|
sqlparse==0.3.0
|
||||||
|
urllib3==1.25.7
|
||||||
|
|
Loading…
Reference in New Issue
Block a user