Как правильно заменить местозаполнители в запросе?

Логика скрипта состоит в том, чтобы в метод передавался запрос (query) и неограниченный кортеж values.

После, метод перебирает кортеж values (сохраняет в переменную), находит все индексы символа ? и вставляет значения кортежа values в список под индексом символа '?'.

Вот код, но он заменяет лишь почему-то на последнее значение:

def test(query, *values):
        print(f"Query: {query}\nValues: {values}")
        query_list = list(query)
        indexes = {}

        for count, value in enumerate(query_list):
            if value == '?':
                print(f"\n[*] Знак '?' найден в списке под индексом {count}")  
                for i in range(len(values)):
                    print(f"Index of value: [{i}], Index of symbol: {count}")
                    indexes[count] = values[i]

        for key, value in indexes.items():
            query_list[key] = value

        query = "".join(query_list)

        print(f"Result: {query}\nDict: {indexes}")

Вывод:

Query: SELECT * FROM `?` WHERE `password` = ? AND `login` = ?
Values: ('users', 'qwerty', 'Alex2007')

[*] Знак '?' найден в списке под индексом 15
Index of value: [0], Index of symbol: 15
Index of value: [1], Index of symbol: 15
Index of value: [2], Index of symbol: 15

[*] Знак '?' найден в списке под индексом 37
Index of value: [0], Index of symbol: 37
Index of value: [1], Index of symbol: 37
Index of value: [2], Index of symbol: 37

[*] Знак '?' найден в списке под индексом 53
Index of value: [0], Index of symbol: 53
Index of value: [1], Index of symbol: 53
Index of value: [2], Index of symbol: 53
Result: SELECT * FROM `Alex2007` WHERE `password` = Alex2007 AND `login` = Alex2007
Dict: {15: 'Alex2007', 37: 'Alex2007', 53: 'Alex2007'}

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

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

попробуйте изменить код так:

values = iter(values)
for count, value in enumerate(query_list):
   if value == '?':
        print(f"\n[*] Знак '?' найден в списке под индексом {count}")  
        v = next(values)
        print(f"Value: [{v}], Index of symbol: {count}")
        indexes[count] = v
→ Ссылка
Автор решения: MaxU

У вас неправильный и опасный подход. Таким образом вы открываетесь для SQL Injections.

Правильным подходом здесь будет использование связываемых переменных (синонимы: prepared statement, bind variables). Связать можно только литералы, но не наименования таблиц или столбцов. Поэтому вашу задачу придется разделить на две части - динамическое формирование запроса с подставлением названий таблиц / столбцов и на безопасное связывание переменных:

qry_template = """SELECT * FROM {} WHERE password = ? AND login = ?"""

пользоваться этим нужно так:

cursor.execute(qry_template.format(table_name), values) # здесь значения переменных `password` и `login` автоматически свяжутся со значениями из списка или кортежа `values` 
for row in cursor.fetchall():
    ...

можно также использовать f-string, но интерполяция переменной будет происходить в момент создания / объявления переменной qry:

table_name = "my_table_name"
qry = f"""SELECT * FROM {table_name} WHERE password = ? AND login = ?"""
....
cursor.execute(qry, values)
→ Ссылка