Как бороться с превышением в 64 байта API в callback_data (PyTelegramBotAPI)

Пишу бота для отслеживания посылок. Когда юзер отправляет трекномер ему возвращается 3 переменные(Индекс, Статус, Трекномер), появляется кнопка отследить посылку и мне надо передать эти 3 переменные в call.data, но тут появляется проблема, существует ограничение в 64 байта для call.data, я просто не могу передать так много переменных, а мне очень нужно их передать, что можно придумать? Пытался преобразовать все переменные в 1 кортеж, дабы сократить размер, но не прокатило.

Ошибка: A request to the Telegram API was unsuccessful. Error code: 400. Description: Bad Request: BUTTON_DATA_INVALID

#main
track = message.text 
bot.send_message(message.chat.id,f'{st,ind}',reply_markup=trackme(ind,st,track))

#keyboard
def trackme(ind,st,track):
  data = (ind,st,track)
  print(data.__sizeof__())
  trackme = types.InlineKeyboardMarkup()
  button = types.InlineKeyboardButton(text="Отслеживать посылку", callback_data=f"trackme-{data}")
  trackme.row(button)
  return trackme

Как можно в def trackme() передать все 3 переменные по нажатию кнопки "Отслеживать посылку"


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

Автор решения: gil9red

Когда юзер отправляет трекномер ему возвращается 3 переменные(Индекс, Статус, Трекномер), появляется кнопка отследить посылку и мне надо передать эти 3 переменные в call.data, но тут появляется проблема, существует ограничение в 64 байта для call.data

Если для идентификации нужно несколько полей, что не влезают в ограничение, то нужно еще поле для привязки.

Я бы хранил эти данные в базе данных. И привязывал их к одним данным: id или guid

Например, завел бы таблицу Track с полями:

  • id INTEGER PRIMARY KEY
  • index TEXT
  • status TEXT
  • number TEXT
  • Уникальный индекс для полей index + number. Поле status, наверняка, меняется, поэтому его не включаем.

Тогда, имея index и number можно проверить есть ли посылка в базе. И по id, который можно в callback-data положить, можно получить информацию по посылке


Для peewee та таблица могла бы выглядеть так:

import time

# pip install peewee
from peewee import Model, TextField
from playhouse.sqliteq import SqliteQueueDatabase


DB_FILE_NAME = 'db.sqlite'


# This working with multithreading
# SOURCE: http://docs.peewee-orm.com/en/latest/peewee/playhouse.html#sqliteq
db = SqliteQueueDatabase(
    DB_FILE_NAME,
    pragmas={
        'foreign_keys': 1,
        'journal_mode': 'wal',    # WAL-mode
        'cache_size': -1024 * 64  # 64MB page-cache
    },
    use_gevent=False,     # Use the standard library "threading" module.
    autostart=True,
    queue_max_size=64,    # Max. # of pending writes that can accumulate.
    results_timeout=5.0,  # Max. time to wait for query to be executed.
)


class BaseModel(Model):
    class Meta:
        database = db


class Track(BaseModel):
    index = TextField()
    status = TextField()
    number = TextField()

    class Meta:
        indexes = (
            (('index', 'number'), True),
        )


db.connect()
db.create_tables([Track])

# Задержка в 50мс, чтобы дать время на запуск SqliteQueueDatabase и создание таблиц
# Т.к. в SqliteQueueDatabase запросы на чтение выполняются сразу, а на запись попадают в очередь
time.sleep(0.050)


index = '1111'
number = '2222'
status = 'Ready'

track = Track.get_or_none(index=index, number=number)
print(track)
# None

track = Track.create(index=index, number=number, status=status)
print(track)
# 1

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

→ Ссылка