misc: implement customized date search for birthdate attribute (#44656)

This commit is contained in:
Benjamin Dauvergne 2020-06-30 21:03:18 +02:00
parent a67989da21
commit e090ad25a7
3 changed files with 46 additions and 1 deletions

View File

@ -25,10 +25,11 @@ from itertools import chain
from django import forms
from django.core.exceptions import ValidationError
from django.core.validators import RegexValidator
from django.utils import six
from django.utils import six, formats
from django.utils.translation import ugettext_lazy as _, pgettext_lazy
from django.utils import html
from django.core.files.storage import default_storage
from django.db.models import query
from django.utils.functional import keep_lazy
@ -207,6 +208,18 @@ def profile_attributes_ng_serialize(ctx, value):
return None
def date_free_text_search(term):
for date_format in formats.get_format('DATE_INPUT_FORMATS'):
try:
date = datetime.datetime.strptime(term, date_format).date()
break
except (ValueError, TypeError):
pass
else:
return None
return query.Q(attribute_values__content__exact=date.isoformat())
DEFAULT_ALLOW_BLANK = True
DEFAULT_MAX_LENGTH = 256
@ -251,6 +264,7 @@ DEFAULT_ATTRIBUTE_KINDS = [
'serialize': lambda x: x and x.isoformat(),
'deserialize': lambda x: x and datetime.datetime.strptime(x, '%Y-%m-%d').date(),
'rest_framework_field_class': BirthdateRestField,
'free_text_search': date_free_text_search,
},
{
'label': _('french postcode'),

View File

@ -37,6 +37,23 @@ class UserQuerySet(models.QuerySet):
searchable_attributes = Attribute.objects.filter(searchable=True)
queries = []
for term in terms:
q = None
specific_queries = []
for a in searchable_attributes:
kind = a.get_kind()
free_text_search_function = kind.get('free_text_search')
if free_text_search_function:
q = free_text_search_function(term)
if q is not None:
specific_queries.append(q & models.query.Q(attribute_values__attribute=a))
# if the term is recognized by some specific attribute type, like a
# date, does not use the later generic matcher
if specific_queries:
queries.append(six.moves.reduce(models.query.Q.__or__, specific_queries))
continue
q = (
models.query.Q(username__icontains=term)
| models.query.Q(first_name__icontains=term)

View File

@ -1703,3 +1703,17 @@ def test_filter_users_by_last_modification(app, admin, simple_user, freezer):
assert len(resp.json['results']) == 2
resp = app.get('/api/users/', params={'modified__lt': '2019-10-27T02:58:07'})
assert len(resp.json['results']) == 0
def test_free_text_search(app, admin, settings):
settings.LANGUAGE_CODE = 'fr' # use fr date format
app.authorization = ('Basic', (admin.username, admin.username))
Attribute.objects.create(kind='birthdate', name='birthdate', label='birthdate', required=False, searchable=True)
user = User.objects.create()
user.attributes.birthdate = datetime.date(1982, 2, 10)
resp = app.get('/api/users/?q=10/02/1982')
assert len(resp.json['results']) == 1
assert resp.json['results'][0]['id'] == user.id