Конфликты хэндлеров в aiogram

Помоги разобраться с кодом пожалуйста. У меня возникает конфликт хэндлеров, а именно они вызваются в боте в неподходящее время, например при заполнении анкеты выполняются хэндлеры по порядку до функции form_city. За этой функцией должна следовать функция def form_sex но начинает выполняться функция view_profiles_by_gender из файла view_prifile.py. GPT говорит возможно, у вас где-то не сброшено состояние машины состояний (FSMContext), и обработчики начинают вызываться в неправильный момент. Но я так и не разобрался. Я использую aiogram 3.4.1

import asyncio
from aiogram import Bot, Dispatcher

import handlers
from dayvinchick.data.database import DataBase
from config_reader import config


async def main() -> None:
    bot = Bot(config.bot_token.get_secret_value())
    dp = Dispatcher()
    db_users = DataBase("users_base.db", "users")
    db_likes = DataBase("users_base.db", "likes")

    await db_users.create_table()
    await db_likes.create_table()

    dp.include_routers(
        handlers.start.router,
        handlers.view_profile.router,
        handlers.questionare.router,
        handlers.create_profile.router
    )

    await bot.delete_webhook(drop_pending_updates=True)
    await dp.start_polling(bot, db=db_users)


if __name__ == "__main__":
    asyncio.run(main())

файл questionare.py

import aiohttp
import re

from aiogram import Router, F
from aiogram.types import Message
from aiogram.fsm.context import FSMContext

from dayvinchick.keyboards.builders import form_btn
from dayvinchick.data.database import DataBase

from dayvinchick.utils.states import Form
from dayvinchick.utils.city import check_city
from dayvinchick.keyboards.reply import main

router = Router()

db = DataBase("users_base.db", "users")  # Создание экземпляра класса DataBase


@router.message(F.text == "заполнить анкету")
async def my_form(message: Message, state: FSMContext):
    #user_id = message.from_user.id
    user_name = message.from_user.username
    user_data = await db.get_user_data(user_name)

    if user_data:
        await message.answer("Такой пользователь уже существует!")
        return
    await state.set_state(Form.name)
    await message.answer(
        "Отлично, введи своё имя",
        reply_markup=form_btn([message.from_user.first_name])
    )


@router.message(Form.name)
async def form_name(message: Message, state: FSMContext):
    name = message.text.strip()

    # Проверяем, что имя состоит только из букв русского или латинского алфавита
    if re.match("^[a-zA-Zа-яА-Я]+$", name):
        await state.update_data(name=name)
        await state.set_state(Form.age)
        await message.answer("Теперь укажи свой возраст")
    else:
        await message.answer("Некорректный ввод! Имя должно содержать только буквы русского или латинского алфавита.")


@router.message(Form.age)
async def form_age(message: Message, state: FSMContext):
    age_str = message.text.strip()
    if age_str.isdigit():
        age = int(age_str)
        if 16 <= age <= 80:
            await state.update_data(age=age)
            await state.set_state(Form.city)
            await message.answer("Теперь укажи свой город")
        else:
            await message.answer("Возраст должен быть от 16 до 80 лет. Попробуй ещё раз!")
    else:
        await message.answer("Попробуй ещё раз! Возраст должен быть целым числом.")


@router.message(Form.city)
async def form_city(message: Message, state: FSMContext):
    city_name = message.text.strip()
    if await check_city(city_name):
        await state.update_data(city=city_name)
        await state.set_state(Form.sex)
        await message.answer(
            "Теперь давай определимся с полом",
            reply_markup=form_btn(["Парень", "Девушка"])
        )
    else:
        await message.answer("Указанный город не найден. Попробуйте ещё раз!")
        return


@router.message(Form.sex, F.text.casefold().in_(["парень", "девушка"]))
async def form_sex(message: Message, state: FSMContext):
    await state.update_data(sex=message.text)
    await state.set_state(Form.look_for)
    await message.answer(
        "Кого ты предпочитаешь искать?",
        reply_markup=form_btn(["Парни", "Девушки", "Мне все равно"])
    )


@router.message(Form.sex)
async def incorrect_form_sex(message: Message, state: FSMContext):
    await message.answer("Выбери один вариант!")


@router.message(
    Form.look_for,
    F.text.casefold().in_(["девушки", "парни", "мне все равно"])
)
async def form_look_for(message: Message, state: FSMContext):
    await state.update_data(look_for=message.text)
    await state.set_state(Form.about)
    await message.answer("Теперь расскажи о себе")


@router.message(Form.look_for)
async def incorrect_form_look_for(message: Message, state: FSMContext):
    await message.answer("Выбери один вариант!")


@router.message(Form.about)
async def form_about(message: Message, state: FSMContext):
    if len(message.text) < 5:
        await message.answer("Введи что-нибудь поинтересней")
    else:
        await state.update_data(about=message.text)
        await state.set_state(Form.photo)
        await message.answer("Теперь отправь свое фото")


@router.message(Form.photo, F.photo)
async def form_photo(message: Message, state: FSMContext, db: DataBase):
    photo_file_id = message.photo[-1].file_id
    file_info = await message.bot.get_file(photo_file_id)
    photo_url = f"https://api.telegram.org/file/bot{message.bot.token}/{file_info.file_path}"

    async with aiohttp.ClientSession() as session:
        async with session.get(photo_url) as resp:
            photo_data = await resp.read()

    data = await state.get_data()
    #user_id = message.from_user.id
    username = message.from_user.username

    await state.clear()

    frm_text = []
    [frm_text.append(value) for _, value in data.items()]
    await db.insert(username, frm_text, photo_data, photo_file_id)
    #await db.insert(user_id, frm_text, photo_data)

    await message.answer_photo(photo_file_id, "\n".join(map(str, frm_text)))
    await message.answer("Выберите действие:", reply_markup=main)


@router.message(Form.photo, ~F.photo)
async def incorrect_form_photo(message: Message, state: FSMContext):
    await message.answer("Отправь фото!")

файл view_profile.py

from aiogram import types
from aiogram import Router, F
from aiogram.fsm.context import FSMContext

from typing import Generator
from aiogram.fsm.state import State

from dayvinchick.utils.states import Form
from dayvinchick.data.database import DataBase
from dayvinchick.keyboards.inline import inline_kb
from dayvinchick.keyboards.reply import main, stat_menu, gender_menu, age_menu

from aiogram import Bot


from dayvinchick.config_reader import config

import logging

# Настройка логгера
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)


router = Router()
bot = Bot(config.bot_token.get_secret_value())

db = DataBase("users_base.db", "users")  # Создание экземпляра класса
db2 = DataBase("users_base.db", "likes")


#@router.message(F.text == "просмотр анкет")
#async def view_profiles(message: types.Message, state: FSMContext):
#    profiles = await db.get_all_profiles()  # Получаем все анкеты из базы данных
#    if not profiles:
#        await message.answer("В базе данных нет ни одной анкеты.")
#        return

    # Создаем генератор, который будет возвращать по одной анкете
#    profilegenerator = (profile for profile in profiles)

    # Получаем первую анкету
#    profile = next(profilegenerator, None)

    # Если анкета есть, то отправляем ее пользователю
#    if profile:
#        await send_profile(message, profile, profilegenerator, state)  # Добавляем state в качестве аргумента
#    else:
#        await message.answer("В базе данных нет ни одной анкеты.")


@router.message(F.text == "просмотр анкет")
async def view_profiles(message: types.Message, state: FSMContext):
    await message.answer("Выберите пол:", reply_markup=gender_menu)


@router.message(F.text == "Парень")
async def view_profiles_by_gender(message: types.Message, state: FSMContext):
    gender = message.text
    print(gender)
    profiles = await db.get_profiles_by_gender(gender)  # Замените эту строку вашим запросом к базе данных
    print(profiles)
    if not profiles:
        await message.answer(f"В базе данных нет анкет с полом '{gender}'.")
        return

    profilegenerator = (profile for profile in profiles)
    profile = next(profilegenerator, None)

    if profile:
        await send_profile(message, profile, profilegenerator, state)
    else:
        await message.answer(f"В базе данных нет анкет с полом '{gender}'.")


@router.message(F.text == "Девушка")
async def view_profiles_by_gender(message: types.Message, state: FSMContext):
    gender = message.text
    print(gender)
    profiles = await db.get_profiles_by_gender(gender)  # Замените эту строку вашим запросом к базе данных
    print(profiles)
    if not profiles:
        await message.answer(f"В базе данных нет анкет с полом '{gender}'.")
        return

    profilegenerator = (profile for profile in profiles)
    profile = next(profilegenerator, None)

    if profile:
        await send_profile(message, profile, profilegenerator, state)
    else:
        await message.answer(f"В базе данных нет анкет с полом '{gender}'.")


@router.message(State(Form.name))
async def send_profile(message: types.Message, profile: tuple, profilegenerator: Generator, state: FSMContext):
    # Формируем текст анкеты
    profilemessage = f"Имя: {profile[2]}\n" \
                      f"Возраст: {profile[3]}\n" \
                      f"Город: {profile[4]}\n" \
                      f"Пол: {profile[5]}\n" \
                      f"О себе: {profile[7]}\n"

    # Отправляем текст анкеты
    await message.answer(profilemessage, reply_markup=inline_kb)

    # Отправляем фото
    await message.answer_photo(profile[9])  # profile[9] содержит photofileid из базы данных

    # Сохраняем текущую анкету и генератор в состояние
    await state.update_data(profile=profile, profilegenerator=profilegenerator)


# Добавляем обработчик для кнопки "Статистика"
@router.message(F.text == "статистика")
async def show_stat_menu(message: types.Message):
    await message.answer("Выберите вид статистики:", reply_markup=stat_menu)


@router.message(F.text == "полученные лайки")
async def view_likes_stat(message: types.Message):
    user_name = message.from_user.username
    if user_name:
        user_data = await db.get_user_data(user_name)
        if user_data:
            await message.answer(f"Количество полученных лайков: {user_data['likes']}")
        else:
            await message.answer("Ошибка: Ваша анкета не найдена.")
    else:
        await message.answer("Ошибка: Не удалось получить информацию о вашем пользователе.")


@router.message(F.text == "отправленные лайки")
async def sent_likes_stat(message: types.Message, db: DataBase):
    sender_username = message.from_user.username
    if sender_username:
        likes = await db.get_sent_likes(sender_username)
        if likes:
            response = "Отправленные лайки:\n"
            for like in likes:
                receiver_username = like[0]
                receiver_user_name = like[1]
                response += f"- [{receiver_user_name}](t.me/{receiver_username})\n"
            await message.answer(response)
        else:
            await message.answer("У вас пока нет отправленных лайков.")
    else:
        await message.answer("Ошибка: Не удалось получить информацию о вашем пользователе.")


@router.message(F.text == "назад")
async def back_to_main_menu(message: types.Message):
    await message.answer("Выберите действие:", reply_markup=main)  # Отправляем главное меню


@router.callback_query(F.data == "write_message")
async def write_message_callback(query: types.CallbackQuery, state: FSMContext, db: DataBase):
    await query.answer()  # Ответим на запрос, чтобы Telegram не считал его просроченным

    data = await state.get_data()
    profile = data.get("profile")

    if profile:
        user_name = profile[1]  # ID автора анкеты
        author_data = await db.get_author_by_name(user_name)  # Получаем данные об авторе анкеты
        if author_data:
            # Формируем URI для открытия чата с пользователем
            username = author_data['user_name']
            chat_uri = f"https://t.me/{username}"
            await query.message.answer(f"Откройте чат с автором анкеты по ссылке: {chat_uri}")
        else:
            await query.message.answer("Информация об авторе анкеты не найдена.")
    else:
        await query.message.answer("Информация об анкете не найдена.")


@router.callback_query(F.data == "like")
async def likecallback(query: types.CallbackQuery, state: FSMContext, db: DataBase):
    await query.answer()  # Ответим на запрос, чтобы Telegram не считал его просроченным
    # Получаем текущую анкету и генератор из состояния
    data = await state.get_data()
    profile = data.get("profile")
    profilegenerator = data.get("profilegenerator")
    # Увеличиваем количество лайков в базе данных для текущего профиля
    await db.increment_likes(profile[1])  # Предположим, что profile[1] содержит идентификатор пользователя
    # Добавляем запись о лайке в базу данных
    sender_username = query.from_user.username  # Используем имя пользователя, который поставил лайк
    receiver_username = profile[1]
    await db.insert_like(sender_username, receiver_username)
    # Отправляем сообщение пользователю, что он поставил лайк
    await query.message.answer(f"Вы поставили лайк {profile[2]}.")
    # Получаем следующую анкету из генератора
    profile = next(profilegenerator, None)
    # Если анкета есть, то отправляем ее пользователю
    if profile:
        await send_profile(query.message, profile, profilegenerator, state)
    else:
        await query.message.answer("Вы просмотрели все анкеты в базе данных.")


@router.callback_query(F.data == "dislike")
async def dislikecallback(query: types.CallbackQuery, state: FSMContext):
    await query.answer()  # Ответим на запрос, чтобы Telegram не считал его просроченным
    # Получаем текущую анкету и генератор из состояния
    data = await state.get_data()
    profile = data.get("profile")
    profilegenerator = data.get("profilegenerator")
    # Отправляем сообщение пользователю, что он поставил дизлайк
    await query.message.answer(f"Вы поставили дизлайк {profile[2]}.")
    # Получаем следующую анкету из генератора
    profile = next(profilegenerator, None)
    # Если анкета есть, то отправляем ее пользователю
    if profile:
        await send_profile(query.message, profile, profilegenerator, state)
    else:
        await query.message.answer("Вы просмотрели все анкеты в базе данных.")


@router.callback_query(F.data == "main_menu")
async def main_menu_callback(query: types.CallbackQuery):
    await query.answer()  # Ответим на запрос, чтобы Telegram не считал его просроченным
    await query.message.answer("Выберите действие:", reply_markup=main)  # Отправляем главное меню
    await query.message.delete_reply_markup()  # Скрываем inline клавиатуру

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