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 для выполнения всех ваших поисков.

Вернуться на верх