Django: Фильтр по столбцу модели с помощью Regex
У меня есть номера телефонов, хранящиеся в базе данных как (921) 414-1313, и я хочу запустить поиск по этому полю, но я не хочу заставлять их включать (, ' ', ) или -.
Я использую Postgres и сначала пытался работать с SearchVector, но столкнулся с той же проблемой (так что пока я делаю это старым способом).
У меня есть определение модели, которое возвращает "неформатированное" число 9214141313, но я не могу понять, как сделать запрос к моему пользовательскому определению внутри модели?
В конечном итоге, я хочу, чтобы клиент мог ввести 921414 и получить ответ на соответствующую запись.
GitHub: https://github.com/varlenthegray/wcadmin/blob/dev/main/views.py#L25
Модель:
class JobSite(models.Model):
customer = models.ForeignKey(Customer, on_delete=models.CASCADE)
quickbooks_id = models.IntegerField(editable=False, null=True, blank=True)
name = models.CharField(max_length=200, null=True, blank=True)
first_name = models.CharField(max_length=200, null=True, blank=True)
last_name = models.CharField(max_length=200, null=True, blank=True)
print_on_check_name = models.CharField(max_length=200, null=True, blank=True)
address = models.CharField(max_length=200, null=True, blank=True)
address_2 = models.CharField(max_length=200, null=True, blank=True)
city = models.CharField(max_length=100, null=True, blank=True)
state = models.CharField(max_length=50, null=True, blank=True)
zip = models.CharField(max_length=20, null=True, blank=True)
phone_number = models.CharField(max_length=30, null=True, blank=True)
email = models.CharField(max_length=400, null=True, blank=True)
service_interval = models.IntegerField(default=12)
next_service_date = models.DateField(null=True, blank=True)
primary_technician = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE, blank=True, null=True)
active = models.BooleanField(default=True)
access_code = models.CharField(max_length=10, null=True, blank=True)
bill_parent = models.BooleanField(default=False)
requires_supporting_technician = models.BooleanField(default=False)
service_scheduled = models.BooleanField(default=False)
disable_service = models.BooleanField(default=False)
qb_created_on = models.DateTimeField(null=True, blank=True)
def __str__(self):
return f'{self.name}'
def phone_digits_only(self):
return re.sub("[^0-9]", "", self.phone_number)
@property
def is_past_due(self):
ignore_after = timezone.localdate() - relativedelta(years=5)
# noinspection StrFormat
if self.next_service_date:
if ignore_after >= self.next_service_date:
return False
else:
return timezone.localdate() > self.next_service_date
else:
return False
@property
def is_due_soon(self):
ignore_after = timezone.localdate() - relativedelta(years=3)
if self.next_service_date and self.next_service_date >= ignore_after:
three_months_future = timezone.localdate() + relativedelta(months=2)
return three_months_future > self.next_service_date
else:
return False
Views.py
def search_system(request, search_term=False):
if search_term:
job_sites = JobSite.objects.filter(
Q(first_name__icontains=search_term) |
Q(last_name__icontains=search_term) |
Q(quickbooks_id__icontains=search_term) |
Q(email__icontains=search_term) |
Q(phone_number_digits=search_term)
)
else:
job_sites = JobSite.objects.all().prefetch_related('customer')
data = []
for job in job_sites:
if job.first_name and job.last_name:
name = job.first_name + ' ' + job.last_name
elif job.customer.company:
name = job.customer.company
else:
name = job.customer.first_name + ' ' + job.customer.last_name
this_job = {'value': name}
data.append(this_job)
return JsonResponse(data, safe=False)
Лучшим решением IMHO является использование библиотеки phonenumbers, которая очень чистая и хорошо поддерживается.
Затем сделайте пользовательское поле "phone_cleaned
", в которое добавьте сигналы "create" и "update" для этой модели, и обновите phone_cleaned
соответственно (используя библиотеку для очистки номера телефона). И используйте это phone_cleaned
для выполнения всех ваших поисков.