2014-11-10 3 views
0

Я реализую функцию поиска для имен пользователей. Некоторые имена имеют акцентированные символы, но я хочу, чтобы их можно было искать с ближайшим приближением ascii. Например: Vû Trån будет доступен для поиска с Vu Tran.Не удалось использовать ilike-метод SQLAlchemy с атрибутом getter

Я нашел библиотеку Python под названием unidecode для обработки этого преобразования. Он работает как ожидалось и берет мою строку unicode Vû Trån и возвращает Vu Tran. Отлично.

Проблема возникает, когда я начинаю запрашивать мою базу данных - я использую SQLAlchemy и Postgres.

Вот мой Python запрос:

Person.query.filter(Person.ascii_name.ilike("%{q}%".format(q=query))).limit(25).all() 

ascii_name является геттером для моего колонка имени, реализованный в такой

class Person(Base, PersonUtil): 

    """ 
     My abbreviated Person class 
    """  

    __tablename__ = 'person' 

    id = Column(BigInteger, ForeignKey('user.id'), primary_key=True) 
    first_name = Column(Unicode, nullable=False) 
    last_name = Column(Unicode, nullable=False) 

    name = column_property(first_name + " " + last_name) 
    ascii_name = synonym('name', descriptor=property(fget=PersonUtil._get_ascii_name)) 

class PersonUtil(object): 
    def _get_ascii_name(self): 
     return unidecode(unicode(self.name)) 

Моей целью этого кодом является то, что, так как я храню версию Юникода имя и фамилия в моей базе данных, мне нужно иметь способ позвонить unidecode(unicode(name)), когда я получаю имя человека. Следовательно, я использую descriptor=property(fget=...), так что всякий раз, когда я вызываю Person.ascii_name, я извлекаю атрибут «unidecoded» name. Таким образом, я могу просто написать Person.ascii_name.ilike("%{my_query}%")... и сопоставить ближайший ascii_name с поисковым запросом, который также является просто символом ascii.

Это не работает. Метод ilike с ascii_name работает, когда у меня нет преобразованных символов в запросе. Например, запрос ilike будет работать для имени «Bob Smith», но он не будет работать для «Bøb Smíth». Он терпит неудачу, когда он сталкивается с первым преобразованным персонажем, который в случае с «Bøb Smíth» является буквой «ø».

Я не уверен, почему это происходит. Получатель ascii_name возвращает ожидаемую строку «Bob Smith» или «Vu Tran», но в сочетании с методом ilike он не работает.

  1. Почему это происходит? Я не смог найти ничего об этом.
  2. Как я могу исправить мой существующий код, чтобы сделать эту работу, или есть лучший способ сделать это, что будет работать? Я бы предпочел не менять схему БД.

спасибо.

+0

В PostgreSQL есть нечто подобное: http://stackoverflow.com/questions/11005036/does-postgresql-support-accent-insensitive-collations – pozs

ответ

0

Что вы хотите сделать просто не будет работать, потому что ilike работает только с реальными столбцами в базе данных. column_property и synonym являются просто синтаксическими сахарами, предоставляемыми sqlalchemy, чтобы облегчить легкий доступ к переднему концу. Если вы хотите использовать бэкэнд для запроса с помощью LIKE так, как вы предполагали, вам нужны фактические значения. Я боюсь, что вам нужно создать/сохранить полное имя ascii в базе данных, что означает, что вам нужно изменить свою схему, чтобы включить ascii_name в качестве реального столбца, и убедитесь, что они вставлены. Чтобы убедиться в этом, вы должны сбросить данные в таблице и посмотреть, могут ли ваши запросы, созданные вручную.

+0

Спасибо за ваш ответ. Изменение схемы db не имеет большого значения, но было бы неплохо иметь возможность делать это без изменения схемы.Кажется, нет другого варианта. – JohnZ

Смежные вопросы