fogersp
@fogersp

Django (и DRF): как искать не по полю в таблице, а по его измененному значению?

Я использую Django + Django Rest Framework для построения простого API.
Мне нужно найти через GET запрос телефон, например 12345678901. Все бы ничего, но в таблице номера могут быть как в таком же формате, так и в формате 1-234-567-89-01, или несколько номеров через запятую. Так вот, убрать дефисы и разделить по запятой это конечно не проблема, а вот как искать в итоге через __contains или __exact не по старому значению поля, а по новому - обработанному?

Вот мои начинания:

views.py
class UserPropertiesViewSet(viewsets.ModelViewSet):
    queryset = UserProperties.objects.all()
    serializer_class = serializers.UserPropertiesSerializer

    def get_queryset(self):
        queryset = self.queryset
        phone = self.request.query_params.get('phone')
        if phone:
            users = queryset.filter(
            Q(phone__contains=phone)
            | Q(user__phone__contains=phone)
        )
            return users
        else:
            return queryset


serializers.py
class UserPropertiesSerializer(serializers.ModelSerializer):
    ...
    allphones = serializers.SerializerMethodField(read_only=True)
    class Meta:
        model = models.UserProperties
        fields = ['.... ', 'allphones']

    def get_allphones(self, obj):
        # возвращаю список из всех номеров которые есть у пользователя (из двух таблиц: user_properties + из таблицы user)
        user = models.User.objects.filter(id__exact=obj.user_id).values_list('phone', flat=True)
        result = [obj.phone,]
        if user[0]:
            for phone in user[0].split(','):
                result.append(''.join(filter(lambda x: x.isdigit(), phone)))
        return set(result)


В итоге я могу искать по обеим таблицам, да, но только в том формате, в котором хранятся там значения. А хранятся они в разном формате и поменять в самой базе я их не могу.

allphones - это я создал виртуальное поле SerializerMethodField чтобы собрать в нем список из всех номеров, да и еще очищенных от всяких лишних символов. Но, как и ожидалось - по нему искать нельзя, allphones__contains=phone я имею ввиду. Выдает ошибку что нет такого поля, и это действительно так. А я думал что все просто будет - создам отформатированный список и буду по нему фильтровать с помощью DRF. В итоге, вывести значения полей я могу как угодно, или создать свое поле и использовать to_representation() с to_internal_value(), но это просто вывод нужного формата. И по нему я не могу искать, или не правильно все делаю

В общем, помогите. Как бы вы делали в данной ситуации? Что я упустил и куда копать
  • Вопрос задан
  • 278 просмотров
Решения вопроса 1
tumbler
@tumbler
бекенд-разработчик на python
  1. Делаете отдельное поле normalized_phone, в которое пишите "нормализованное" по вашим правилам значение
  2. При поиске по тем же правилам "нормализуете" пользовательский ввод и ищете по полю normalized_phone.

Ответ написан
Пригласить эксперта
Ответы на вопрос 1
fogersp
@fogersp Автор вопроса
Частичное решение по совету Сергей Тихонов :
users = queryset.annotate(phone_norm=Replace('user__phone', Value('-'), Value(''))).filter(
                Q(phone_norm__icontains=phone)
            | Q(phone__icontains=phone)
            )
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы