Как создать алгоритм матчинга анкет, немного похожий на Леонардо Дай Винчик и Tinder

Пишу бота для Telegram на Python (библиотека aiogram с asyncio), функционал которого чем-то схож с Леонардо Дай Винчик или Tinder. Пользователь начинает поиск и ему поочередно выдаются анкеты из БД. Он может либо "лайкнуть" анкету, либо "дизлайкнуть". Соответственно, когда симпатия взаимна, обоим пользователям отправляется контакт для связи (и так далее).

Модели в БД выглядят следующим образом:

Модель пользователя:

class User(BaseModel):
    id = PrimaryKeyField()  # Постоянный Telegram ID
    mention = CharField(unique=True, null=True)  # Упоминание пользователя в виде @diplomente :)
    phone = CharField(null=True)  # TG - Contact

    name = CharField(null=False)  # По-умолчанию предлагается имя Telegram профиля, но пользователя может сменить
    age = IntegerField()  # Возраст в цифрах
    city = CharField(default="Душанбе")
    photo = IntegerField()  # ID фотографии профиля. Значение только храниться в БД.

    gender = CharField(max_length=1)  # M - Male, F - Female
    search_gender = CharField(max_length=1)  # M - Male, F - Male, B - Both
    description = CharField()  # Описание профиля, информация о себе и цели поиска

Модель симпатий:

class Mutuality(BaseModel):
    first = ForeignKeyField(User)
    second = ForeignKeyField(User)
    status = BooleanField(default=0)  # 0 - дизлайк, 1 - симпатия
    # Когда отправляется симпатия, создается запись в БД, где first - тот, кто отправил симпатию, second - тот, кому она
    # направлена.

Теперь столкнулся со сложностями при реализации:

  1. Как реализовать алгоритм поиска следующей анкеты?
  2. Как избежать дубликатов (повторные отображения анкет, к примеру, ранее друг друга "дизлайкнувших" или друг друга "лайкнувших" и так далее)?

И какие у вас будут советы и рекомендации? Спасибо!


Ответы (2 шт):

Автор решения: Чёрный плащ

Создайте список, где находится информация по существующим активным анкетам, например это будет список кортежей. После этого создайте Хендлер next_user, при помощи машины состояний конечного автомата присвойте ему состояние актив, когда пользователь просматривает другие анкеты. Функция будет обрабатывать входящее сообщение в виде сердечка или дислайка, брать рандомный элемент из нашего списка анкет, отображать данную анкету и удалять ее из нашего списка.

Список определите, как глобальную переменную, однако исключите возможность возникновения асинхронности, путём инициализации списка внутри вашей функции-обработчика.

Вот и весь алгоритм. Ничего сложного.

→ Ссылка
Автор решения: Alibek Avila

Чтобы избежать дубликатов как предложение - создать еще одну таблицу с историей действий (когда один другого лайкнул/дизлайкнул/ответил взаимностью)

Далее при выводе потенциально интересной анкеты пользователю можно выводить все, за исключением тех, что уже есть в таблице с действиями.

P.s. дабы избежать переполнения этой таблицы можно периодически очищать действия более ~недельной давности

→ Ссылка